From 19792b639077a2d23c5cc782b2172ed88d65b3f9 Mon Sep 17 00:00:00 2001 From: sunbreak Date: Wed, 24 May 2023 16:32:38 -0300 Subject: [PATCH 01/74] Initial commit --- LICENSE | 661 ++++++++++++++++++++++++++++++++++ script/AllocatorVault.s.sol | 13 + src/AllocatorVault.sol | 192 ++++++++++ src/test/AllocatorVault.t.sol | 13 + 4 files changed, 879 insertions(+) create mode 100644 LICENSE create mode 100644 script/AllocatorVault.s.sol create mode 100644 src/AllocatorVault.sol create mode 100644 src/test/AllocatorVault.t.sol diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..0ad25db4 --- /dev/null +++ b/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/script/AllocatorVault.s.sol b/script/AllocatorVault.s.sol new file mode 100644 index 00000000..4f5e8655 --- /dev/null +++ b/script/AllocatorVault.s.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.8.16; + +import "forge-std/Script.sol"; + +contract AllocatorVaultScript is Script { + function setUp() public {} + + function run() public { + vm.broadcast(); + } +} diff --git a/src/AllocatorVault.sol b/src/AllocatorVault.sol new file mode 100644 index 00000000..8d1cbb6b --- /dev/null +++ b/src/AllocatorVault.sol @@ -0,0 +1,192 @@ +// SPDX-FileCopyrightText: © 2020 Lev Livnev +// SPDX-FileCopyrightText: © 2021 Dai Foundation +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +pragma solidity ^0.8.16; + +interface VatLike { + function live() external view returns (uint256); + function frob(bytes32, address, address, address, int256, int256) external; + function hope(address) external; +} + +interface JugLike { + function drip(bytes32) external returns (uint256); +} + +interface TokenLike { + function totalSupply() external view returns (uint256); + function approve(address, uint256) external; + function transfer(address, uint256) external; +} + +interface GemJoinLike { + function gem() external view returns (TokenLike); + function ilk() external view returns (bytes32); + function vat() external view returns (address); + function join(address, uint256) external; +} + +interface NstJoinLike { + function nst() external view returns (TokenLike); + function vat() external view returns (address); + function exit(address, uint256) external; + function join(address, uint256) external; +} + +contract AllocatorVault { + + // --- storage variables --- + + mapping(address => uint256) public wards; + mapping(address => uint256) public can; + JugLike public jug; + + // --- constants --- + + uint256 constant RAY = 10 ** 27; + + // --- immutables --- + + VatLike immutable public vat; + bytes32 immutable public ilk; + GemJoinLike immutable public gemJoin; + NstJoinLike immutable public nstJoin; + TokenLike immutable public nst; + + // --- events --- + + event Rely(address indexed usr); + event Deny(address indexed usr); + event Hope(address indexed usr); + event Nope(address indexed usr); + event File(bytes32 indexed what, address data); + event Draw(address indexed funnel, address indexed to, uint256 wad); + event Take(address indexed funnel, address indexed to, uint256 wad); + event Wipe(address indexed funnel, uint256 wad); + + // --- modifiers --- + + modifier auth() { + require(wards[msg.sender] == 1, "AllocatorVault/not-authorized"); + _; + } + + modifier funnel { + require(can[msg.sender] == 1, "AllocatorVault/only-funnel"); + _; + } + + // --- constructor --- + + constructor(address vat_, address gemJoin_, address nstJoin_) { + vat = VatLike(vat_); + + gemJoin = GemJoinLike(gemJoin_); + nstJoin = NstJoinLike(nstJoin_); + + require(vat_ == gemJoin.vat() && vat_ == nstJoin.vat(), "AllocatorVault/vat-not-match"); + + ilk = GemJoinLike(gemJoin_).ilk(); + nst = NstJoinLike(nstJoin_).nst(); + + VatLike(vat_).hope(nstJoin_); + nst.approve(nstJoin_, type(uint256).max); + + wards[msg.sender] = 1; + emit Rely(msg.sender); + } + + // --- math --- + + function _divup(uint256 x, uint256 y) internal pure returns (uint256 z) { + unchecked { + z = x != 0 ? ((x - 1) / y) + 1 : 0; + } + } + + // --- administration --- + + function init() external auth { + TokenLike gem = gemJoin.gem(); + uint256 supply = gem.totalSupply(); + require(supply <= uint256(type(int256).max), "AllocatorVault/overflow"); + + gem.approve(address(gemJoin), supply); + gemJoin.join(address(this), supply); + vat.frob(ilk, address(this), address(this), address(0), int256(supply), 0); + } + + function rely(address usr) external auth { + wards[usr] = 1; + emit Rely(usr); + } + + function deny(address usr) external auth { + wards[usr] = 0; + emit Deny(usr); + } + + function hope(address usr) external auth { + require(vat.live() == 1, "AllocatorVault/no-hope-during-shutdown"); + can[usr] = 1; + emit Hope(usr); + } + + function nope(address usr) external auth { + require(vat.live() == 1, "AllocatorVault/no-nope-during-shutdown"); + can[usr] = 0; + emit Nope(usr); + } + + function file(bytes32 what, address data) external auth { + if (what == "jug") { + jug = JugLike(data); + } else revert("AllocatorVault/unrecognised-param"); + emit File(what, data); + } + + // --- funnels execution --- + + function draw(address to, uint256 wad) public funnel { + uint256 rate = jug.drip(ilk); + uint256 dart = _divup(wad * RAY, rate); + require(dart <= uint256(type(int256).max), "AllocatorVault/overflow"); + vat.frob(ilk, address(this), address(0), address(this), 0, int256(dart)); + nstJoin.exit(to, wad); + emit Draw(msg.sender, to, wad); + } + + function draw(uint256 wad) external { + draw(address(this), wad); + } + + function take(address to, uint256 wad) external funnel { + nst.transfer(to, wad); + emit Take(msg.sender, to, wad); + } + + function wipe(uint256 wad) external funnel { + nstJoin.join(address(this), wad); + uint256 rate = jug.drip(ilk); + uint256 dart = wad * RAY / rate; + require(dart <= uint256(type(int256).max), "AllocatorVault/overflow"); + vat.frob(ilk, address(this), address(this), address(this), 0, -int256(dart)); + emit Wipe(msg.sender, wad); + } + + // TODO: evaluate if quit function is necessary and how it should be +} diff --git a/src/test/AllocatorVault.t.sol b/src/test/AllocatorVault.t.sol new file mode 100644 index 00000000..042829cd --- /dev/null +++ b/src/test/AllocatorVault.t.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.8.16; + +import "forge-std/Test.sol"; +import "../AllocatorVault.sol"; + +contract AllocatorVaultTest is Test { + AllocatorVault public vault; + + function setUp() public { + } +} From 07375c0c07d52d6af9c7ac238fae476be299add0 Mon Sep 17 00:00:00 2001 From: sunbreak Date: Fri, 26 May 2023 17:26:03 -0300 Subject: [PATCH 02/74] Use wards for everything --- src/AllocatorVault.sol | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/src/AllocatorVault.sol b/src/AllocatorVault.sol index 8d1cbb6b..4c056924 100644 --- a/src/AllocatorVault.sol +++ b/src/AllocatorVault.sol @@ -52,7 +52,6 @@ contract AllocatorVault { // --- storage variables --- mapping(address => uint256) public wards; - mapping(address => uint256) public can; JugLike public jug; // --- constants --- @@ -71,8 +70,6 @@ contract AllocatorVault { event Rely(address indexed usr); event Deny(address indexed usr); - event Hope(address indexed usr); - event Nope(address indexed usr); event File(bytes32 indexed what, address data); event Draw(address indexed funnel, address indexed to, uint256 wad); event Take(address indexed funnel, address indexed to, uint256 wad); @@ -85,11 +82,6 @@ contract AllocatorVault { _; } - modifier funnel { - require(can[msg.sender] == 1, "AllocatorVault/only-funnel"); - _; - } - // --- constructor --- constructor(address vat_, address gemJoin_, address nstJoin_) { @@ -140,18 +132,6 @@ contract AllocatorVault { emit Deny(usr); } - function hope(address usr) external auth { - require(vat.live() == 1, "AllocatorVault/no-hope-during-shutdown"); - can[usr] = 1; - emit Hope(usr); - } - - function nope(address usr) external auth { - require(vat.live() == 1, "AllocatorVault/no-nope-during-shutdown"); - can[usr] = 0; - emit Nope(usr); - } - function file(bytes32 what, address data) external auth { if (what == "jug") { jug = JugLike(data); @@ -161,7 +141,7 @@ contract AllocatorVault { // --- funnels execution --- - function draw(address to, uint256 wad) public funnel { + function draw(address to, uint256 wad) public auth { uint256 rate = jug.drip(ilk); uint256 dart = _divup(wad * RAY, rate); require(dart <= uint256(type(int256).max), "AllocatorVault/overflow"); @@ -174,12 +154,12 @@ contract AllocatorVault { draw(address(this), wad); } - function take(address to, uint256 wad) external funnel { + function take(address to, uint256 wad) external auth { nst.transfer(to, wad); emit Take(msg.sender, to, wad); } - function wipe(uint256 wad) external funnel { + function wipe(uint256 wad) external auth { nstJoin.join(address(this), wad); uint256 rate = jug.drip(ilk); uint256 dart = wad * RAY / rate; From 936dae6b9502709612362aa8009505d1c84a6687 Mon Sep 17 00:00:00 2001 From: sunbreak Date: Mon, 29 May 2023 16:17:55 -0300 Subject: [PATCH 03/74] Renaming: AllocatorVault => AllocatorBuffer --- ...{AllocatorVault.s.sol => AllocatorBuffer.s.sol} | 2 +- src/{AllocatorVault.sol => AllocatorBuffer.sol} | 14 +++++++------- ...{AllocatorVault.t.sol => AllocatorBuffer.t.sol} | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) rename script/{AllocatorVault.s.sol => AllocatorBuffer.s.sol} (82%) rename src/{AllocatorVault.sol => AllocatorBuffer.sol} (91%) rename src/test/{AllocatorVault.t.sol => AllocatorBuffer.t.sol} (57%) diff --git a/script/AllocatorVault.s.sol b/script/AllocatorBuffer.s.sol similarity index 82% rename from script/AllocatorVault.s.sol rename to script/AllocatorBuffer.s.sol index 4f5e8655..01d01f5d 100644 --- a/script/AllocatorVault.s.sol +++ b/script/AllocatorBuffer.s.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.16; import "forge-std/Script.sol"; -contract AllocatorVaultScript is Script { +contract AllocatorBufferScript is Script { function setUp() public {} function run() public { diff --git a/src/AllocatorVault.sol b/src/AllocatorBuffer.sol similarity index 91% rename from src/AllocatorVault.sol rename to src/AllocatorBuffer.sol index 4c056924..d4d938d1 100644 --- a/src/AllocatorVault.sol +++ b/src/AllocatorBuffer.sol @@ -47,7 +47,7 @@ interface NstJoinLike { function join(address, uint256) external; } -contract AllocatorVault { +contract AllocatorBuffer { // --- storage variables --- @@ -78,7 +78,7 @@ contract AllocatorVault { // --- modifiers --- modifier auth() { - require(wards[msg.sender] == 1, "AllocatorVault/not-authorized"); + require(wards[msg.sender] == 1, "AllocatorBuffer/not-authorized"); _; } @@ -90,7 +90,7 @@ contract AllocatorVault { gemJoin = GemJoinLike(gemJoin_); nstJoin = NstJoinLike(nstJoin_); - require(vat_ == gemJoin.vat() && vat_ == nstJoin.vat(), "AllocatorVault/vat-not-match"); + require(vat_ == gemJoin.vat() && vat_ == nstJoin.vat(), "AllocatorBuffer/vat-not-match"); ilk = GemJoinLike(gemJoin_).ilk(); nst = NstJoinLike(nstJoin_).nst(); @@ -115,7 +115,7 @@ contract AllocatorVault { function init() external auth { TokenLike gem = gemJoin.gem(); uint256 supply = gem.totalSupply(); - require(supply <= uint256(type(int256).max), "AllocatorVault/overflow"); + require(supply <= uint256(type(int256).max), "AllocatorBuffer/overflow"); gem.approve(address(gemJoin), supply); gemJoin.join(address(this), supply); @@ -135,7 +135,7 @@ contract AllocatorVault { function file(bytes32 what, address data) external auth { if (what == "jug") { jug = JugLike(data); - } else revert("AllocatorVault/unrecognised-param"); + } else revert("AllocatorBuffer/unrecognised-param"); emit File(what, data); } @@ -144,7 +144,7 @@ contract AllocatorVault { function draw(address to, uint256 wad) public auth { uint256 rate = jug.drip(ilk); uint256 dart = _divup(wad * RAY, rate); - require(dart <= uint256(type(int256).max), "AllocatorVault/overflow"); + require(dart <= uint256(type(int256).max), "AllocatorBuffer/overflow"); vat.frob(ilk, address(this), address(0), address(this), 0, int256(dart)); nstJoin.exit(to, wad); emit Draw(msg.sender, to, wad); @@ -163,7 +163,7 @@ contract AllocatorVault { nstJoin.join(address(this), wad); uint256 rate = jug.drip(ilk); uint256 dart = wad * RAY / rate; - require(dart <= uint256(type(int256).max), "AllocatorVault/overflow"); + require(dart <= uint256(type(int256).max), "AllocatorBuffer/overflow"); vat.frob(ilk, address(this), address(this), address(this), 0, -int256(dart)); emit Wipe(msg.sender, wad); } diff --git a/src/test/AllocatorVault.t.sol b/src/test/AllocatorBuffer.t.sol similarity index 57% rename from src/test/AllocatorVault.t.sol rename to src/test/AllocatorBuffer.t.sol index 042829cd..3563c4bc 100644 --- a/src/test/AllocatorVault.t.sol +++ b/src/test/AllocatorBuffer.t.sol @@ -3,10 +3,10 @@ pragma solidity ^0.8.16; import "forge-std/Test.sol"; -import "../AllocatorVault.sol"; +import "../AllocatorBuffer.sol"; -contract AllocatorVaultTest is Test { - AllocatorVault public vault; +contract AllocatorBufferTest is Test { + AllocatorBuffer public buffer; function setUp() public { } From 0e4c56720fe11aae5757c75857e029e5b9f4e858 Mon Sep 17 00:00:00 2001 From: sunbreak Date: Mon, 29 May 2023 17:16:02 -0300 Subject: [PATCH 04/74] forge install: dss-test --- .gitmodules | 3 +++ lib/dss-test | 1 + 2 files changed, 4 insertions(+) create mode 160000 lib/dss-test diff --git a/.gitmodules b/.gitmodules index 888d42dc..98ffb6a8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "lib/forge-std"] path = lib/forge-std url = https://github.com/foundry-rs/forge-std +[submodule "lib/dss-test"] + path = lib/dss-test + url = https://github.com/makerdao/dss-test diff --git a/lib/dss-test b/lib/dss-test new file mode 160000 index 00000000..9d755781 --- /dev/null +++ b/lib/dss-test @@ -0,0 +1 @@ +Subproject commit 9d7557817af849273ec1d952cc953b212f19025f From 6656947e25ab0f49e122a0fd853cc9ebcbfd979b Mon Sep 17 00:00:00 2001 From: sunbreak Date: Mon, 29 May 2023 17:20:03 -0300 Subject: [PATCH 05/74] forge remove: forge-std --- .gitmodules | 3 --- lib/forge-std | 1 - 2 files changed, 4 deletions(-) delete mode 160000 lib/forge-std diff --git a/.gitmodules b/.gitmodules index 98ffb6a8..a2df3f1f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "lib/forge-std"] - path = lib/forge-std - url = https://github.com/foundry-rs/forge-std [submodule "lib/dss-test"] path = lib/dss-test url = https://github.com/makerdao/dss-test diff --git a/lib/forge-std b/lib/forge-std deleted file mode 160000 index 73d44ec7..00000000 --- a/lib/forge-std +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 73d44ec7d124e3831bc5f832267889ffb6f9bc3f From 9378bbfdfb314d4fa45fa2b6e3d1659dd502a63b Mon Sep 17 00:00:00 2001 From: sunbreak Date: Mon, 29 May 2023 17:39:29 -0300 Subject: [PATCH 06/74] Fix file error message --- src/AllocatorBuffer.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AllocatorBuffer.sol b/src/AllocatorBuffer.sol index d4d938d1..9fb92130 100644 --- a/src/AllocatorBuffer.sol +++ b/src/AllocatorBuffer.sol @@ -135,7 +135,7 @@ contract AllocatorBuffer { function file(bytes32 what, address data) external auth { if (what == "jug") { jug = JugLike(data); - } else revert("AllocatorBuffer/unrecognised-param"); + } else revert("AllocatorBuffer/file-unrecognized-param"); emit File(what, data); } From f5dae4dbba7d217abfd254e70c45881fce55db26 Mon Sep 17 00:00:00 2001 From: sunbreak Date: Mon, 29 May 2023 23:26:21 -0300 Subject: [PATCH 07/74] Add unit tests for AllocatorBuffer --- src/test/AllocatorBuffer.t.sol | 296 ++++++++++++++++++++++++++++++++- 1 file changed, 294 insertions(+), 2 deletions(-) diff --git a/src/test/AllocatorBuffer.t.sol b/src/test/AllocatorBuffer.t.sol index 3563c4bc..e3508810 100644 --- a/src/test/AllocatorBuffer.t.sol +++ b/src/test/AllocatorBuffer.t.sol @@ -2,12 +2,304 @@ pragma solidity ^0.8.16; -import "forge-std/Test.sol"; +import "dss-test/DssTest.sol"; import "../AllocatorBuffer.sol"; -contract AllocatorBufferTest is Test { +contract VatMock { + uint256 public rate = 10**27; + + struct Urn { + uint256 ink; + uint256 art; + } + + mapping (bytes32 => mapping (address => Urn )) public urns; + mapping (bytes32 => mapping (address => uint)) public gem; + mapping (address => uint256) public dai; + + function hope(address) external {} + + event log(string, uint256); + event log(string, int256); + + function frob(bytes32 i, address u, address v, address w, int256 dink, int256 dart) external { + Urn memory urn = urns[i][u]; + + urn.ink = dink >= 0 ? urn.ink + uint256(dink) : urn.ink - uint256(-dink); + urn.art = dart >= 0 ? urn.art + uint256(dart) : urn.art - uint256(-dart); + + gem[i][v] = dink >= 0 ? gem[i][v] - uint256(dink) : gem[i][v] + uint256(-dink); + int256 dtab = int256(rate) * dart; + dai[w] = dtab >= 0 ? dai[w] + uint256(dtab) : dai[w] - uint256(-dtab); + + urns[i][u] = urn; + } + + function move(address src, address dst, uint256 rad) external { + dai[src] = dai[src] - rad; + dai[dst] = dai[dst] + rad; + } + + function slip(bytes32 ilk, address usr, int256 wad) external { + gem[ilk][usr] = wad >= 0 ? gem[ilk][usr] + uint256(wad) : gem[ilk][usr] - uint256(-wad); + } + + function fold(uint256 rate_) external { + rate = rate + rate_; + } +} + +contract JugMock { + VatMock vat; + + uint256 duty = 1001 * 10**27 / 1000; + uint256 rho = block.timestamp; + + constructor(VatMock vat_) { + vat = vat_; + } + + function drip(bytes32) external returns (uint256 rate) { + uint256 add = (duty - 10**27) * (block.timestamp - rho); + rate = vat.rate() + add; + vat.fold(add); + rho = block.timestamp; + } +} + +contract GemMock { + mapping (address => uint256) public balanceOf; + mapping (address => mapping (address => uint256)) public allowance; + + uint256 public totalSupply; + + constructor(uint256 initialSupply) { + mint(msg.sender, initialSupply); + } + + function approve(address spender, uint256 value) external returns (bool) { + allowance[msg.sender][spender] = value; + return true; + } + + function transfer(address to, uint256 value) external returns (bool) { + uint256 balance = balanceOf[msg.sender]; + require(balance >= value, "Gem/insufficient-balance"); + + unchecked { + balanceOf[msg.sender] = balance - value; + balanceOf[to] += value; + } + return true; + } + + function transferFrom(address from, address to, uint256 value) external returns (bool) { + uint256 balance = balanceOf[from]; + require(balance >= value, "Gem/insufficient-balance"); + + if (from != msg.sender) { + uint256 allowed = allowance[from][msg.sender]; + if (allowed != type(uint256).max) { + require(allowed >= value, "Gem/insufficient-allowance"); + + unchecked { + allowance[from][msg.sender] = allowed - value; + } + } + } + + unchecked { + balanceOf[from] = balance - value; + balanceOf[to] += value; + } + return true; + } + + function mint(address to, uint256 value) public { + unchecked { + balanceOf[to] = balanceOf[to] + value; + } + totalSupply = totalSupply + value; + } + + function burn(address from, uint256 value) external { + uint256 balance = balanceOf[from]; + require(balance >= value, "Gem/insufficient-balance"); + + if (from != msg.sender) { + uint256 allowed = allowance[from][msg.sender]; + if (allowed != type(uint256).max) { + require(allowed >= value, "Gem/insufficient-allowance"); + + unchecked { + allowance[from][msg.sender] = allowed - value; + } + } + } + + unchecked { + balanceOf[from] = balance - value; + totalSupply = totalSupply - value; + } + } +} + +contract GemJoinMock { + VatMock public vat; + bytes32 public ilk; + GemMock public gem; + + constructor(VatMock vat_, bytes32 ilk_, GemMock gem_) { + vat = vat_; + ilk = ilk_; + gem = gem_; + } + + function join(address usr, uint256 wad) external { + vat.slip(ilk, usr, int256(wad)); + gem.transferFrom(msg.sender, address(this), wad); + } +} + +contract NstJoinMock { + VatMock public vat; + GemMock public nst; + + constructor(VatMock vat_, GemMock nst_) { + vat = vat_; + nst = nst_; + } + + function join(address usr, uint256 wad) external { + vat.move(address(this), usr, wad * 10**27); + nst.burn(msg.sender, wad); + } + + function exit(address usr, uint256 wad) external { + vat.move(msg.sender, address(this), wad * 10**27); + nst.mint(usr, wad); + } +} + +contract AllocatorBufferTest is DssTest { + using stdStorage for StdStorage; + + VatMock public vat; + JugMock public jug; + GemMock public gem; + GemJoinMock public gemJoin; + GemMock public nst; + NstJoinMock public nstJoin; AllocatorBuffer public buffer; + bytes32 public ilk; + + function _divup(uint256 x, uint256 y) internal pure returns (uint256 z) { + unchecked { + z = x != 0 ? ((x - 1) / y) + 1 : 0; + } + } function setUp() public { + ilk = "TEST-ILK"; + vat = new VatMock(); + jug = new JugMock(vat); + gem = new GemMock(100 * 10**18); + gemJoin = new GemJoinMock(vat, ilk, gem); + nst = new GemMock(0); + nstJoin = new NstJoinMock(vat, nst); + buffer = new AllocatorBuffer(address(vat), address(gemJoin), address(nstJoin)); + gem.transfer(address(buffer), 100 * 10**18); + + // Add some existing DAI assigned to nstJoin to avoid a particular error + stdstore.target(address(vat)).sig("dai(address)").with_key(address(nstJoin)).depth(0).checked_write(100_000 * 10**45); + } + + function testAuth() public { + checkAuth(address(buffer), "AllocatorBuffer"); + } + + function testModifiers() public { + bytes4[] memory authedMethods = new bytes4[](5); + authedMethods[0] = buffer.init.selector; + authedMethods[1] = bytes4(keccak256("draw(address,uint256)")); + authedMethods[2] = bytes4(keccak256("draw(uint256)")); + authedMethods[3] = buffer.take.selector; + authedMethods[4] = buffer.wipe.selector; + + vm.startPrank(address(0xBEEF)); + checkModifier(address(buffer), "AllocatorBuffer/not-authorized", authedMethods); + vm.stopPrank(); + } + + function testFile() public { + checkFileAddress(address(buffer), "AllocatorBuffer", ["jug"]); + } + + function testInit() public { + assertEq(gem.balanceOf(address(buffer)), gem.totalSupply()); + assertEq(gem.balanceOf(address(gemJoin)), 0); + (uint256 ink, ) = vat.urns(ilk, address(buffer)); + assertEq(ink, 0); + buffer.init(); + assertEq(gem.balanceOf(address(buffer)), 0); + assertEq(gem.balanceOf(address(gemJoin)), gem.totalSupply()); + (ink, ) = vat.urns(ilk, address(buffer)); + assertEq(ink, gem.totalSupply()); + } + + function testInitNotTotalSupply() public { + deal(address(gem), address(buffer), gem.balanceOf(address(buffer)) - 1); + vm.expectRevert("Gem/insufficient-balance"); + buffer.init(); + } + + uint256 div = 1001; // Hack to solve a compiling issue + + function testDrawWipe() public { + buffer.init(); + buffer.file("jug", address(jug)); + (, uint256 art) = vat.urns(ilk, address(buffer)); + assertEq(art, 0); + buffer.draw(50 * 10**18); + (, art) = vat.urns(ilk, address(buffer)); + assertEq(art, 50 * 10**18); + assertEq(vat.rate(), 10**27); + assertEq(nst.balanceOf(address(buffer)), 50 * 10**18); + vm.warp(block.timestamp + 1); + buffer.draw(50 * 10**18); + (, art) = vat.urns(ilk, address(buffer)); + uint256 expectedArt = 50 * 10**18 + _divup(50 * 10**18 * 1000, div); + assertEq(art, expectedArt); + assertEq(vat.rate(), 1001 * 10**27 / 1000); + assertEq(nst.balanceOf(address(buffer)), 100 * 10**18); + assertGt(art * vat.rate(), 100.05 * 10**45); + assertLt(art * vat.rate(), 100.06 * 10**45); + vm.expectRevert("Gem/insufficient-balance"); + buffer.wipe(100.06 ether); + deal(address(nst), address(buffer), 100.06 * 10**18, true); + assertEq(nst.balanceOf(address(buffer)), 100.06 * 10**18); + vm.expectRevert(); + buffer.wipe(100.06 ether); // It will try to wipe more art than existing, then reverts + buffer.wipe(100.05 ether); + assertEq(nst.balanceOf(address(buffer)), 0.01 * 10**18); + (, art) = vat.urns(ilk, address(buffer)); + assertEq(art, 1); // Dust which is impossible to wipe + } + + function testDrawOtherAddress() public { + buffer.init(); + buffer.file("jug", address(jug)); + buffer.draw(address(0xBEEF), 50 * 10**18); + assertEq(nst.balanceOf(address(0xBEEF)), 50 * 10**18); + } + + function testDrawAndTake() public { + buffer.init(); + buffer.file("jug", address(jug)); + buffer.draw(50 * 10**18); + assertEq(nst.balanceOf(address(buffer)), 50 * 10**18); + buffer.take(address(0xBEEF), 20 * 10**18); + assertEq(nst.balanceOf(address(buffer)), 30 * 10**18); + assertEq(nst.balanceOf(address(0xBEEF)), 20 * 10**18); } } From 576d48ba67605379309425254d6129224e22377b Mon Sep 17 00:00:00 2001 From: sunbreak Date: Wed, 31 May 2023 11:07:01 -0300 Subject: [PATCH 08/74] Add AllocatorOracle and change supply to 1M --- src/AllocatorBuffer.sol | 5 +-- src/AllocatorOracle.sol | 42 +++++++++++++++++++++++++ src/test/AllocatorBuffer.t.sol | 4 +-- src/test/AllocatorOracle.t.sol | 57 ++++++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 src/AllocatorOracle.sol create mode 100644 src/test/AllocatorOracle.t.sol diff --git a/src/AllocatorBuffer.sol b/src/AllocatorBuffer.sol index 9fb92130..4e45f0f3 100644 --- a/src/AllocatorBuffer.sol +++ b/src/AllocatorBuffer.sol @@ -56,7 +56,8 @@ contract AllocatorBuffer { // --- constants --- - uint256 constant RAY = 10 ** 27; + uint256 constant WAD = 10**18; + uint256 constant RAY = 10**27; // --- immutables --- @@ -115,7 +116,7 @@ contract AllocatorBuffer { function init() external auth { TokenLike gem = gemJoin.gem(); uint256 supply = gem.totalSupply(); - require(supply <= uint256(type(int256).max), "AllocatorBuffer/overflow"); + require(supply == 10**6 * WAD, "AllocatorBuffer/supply-not-one-million-wad"); gem.approve(address(gemJoin), supply); gemJoin.join(address(this), supply); diff --git a/src/AllocatorOracle.sol b/src/AllocatorOracle.sol new file mode 100644 index 00000000..2a9b6628 --- /dev/null +++ b/src/AllocatorOracle.sol @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: © 2020 Lev Livnev +// SPDX-FileCopyrightText: © 2021 Dai Foundation +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +pragma solidity ^0.8.16; + +contract AllocatorOracle { + // 1M price together with 1M supply, allows up to 1T DAI minting + // and it is a good balance for collateral redemption in Global Shutdown + uint256 internal constant PRICE = 10**6 * 10**18; // 1M in WAD + + /** + @notice Return value and status of the oracle + @return val PRICE constant + @return ok always true + */ + function peek() public pure returns (bytes32 val, bool ok) { + val = bytes32(PRICE); + ok = true; + } + + /** + @notice Return value + @return val PRICE constant + */ + function read() external pure returns (bytes32 val) { + val = bytes32(PRICE); + } +} diff --git a/src/test/AllocatorBuffer.t.sol b/src/test/AllocatorBuffer.t.sol index e3508810..0c3ac604 100644 --- a/src/test/AllocatorBuffer.t.sol +++ b/src/test/AllocatorBuffer.t.sol @@ -203,12 +203,12 @@ contract AllocatorBufferTest is DssTest { ilk = "TEST-ILK"; vat = new VatMock(); jug = new JugMock(vat); - gem = new GemMock(100 * 10**18); + gem = new GemMock(1_000_000 * 10**18); gemJoin = new GemJoinMock(vat, ilk, gem); nst = new GemMock(0); nstJoin = new NstJoinMock(vat, nst); buffer = new AllocatorBuffer(address(vat), address(gemJoin), address(nstJoin)); - gem.transfer(address(buffer), 100 * 10**18); + gem.transfer(address(buffer), 1_000_000 * 10**18); // Add some existing DAI assigned to nstJoin to avoid a particular error stdstore.target(address(vat)).sig("dai(address)").with_key(address(nstJoin)).depth(0).checked_write(100_000 * 10**45); diff --git a/src/test/AllocatorOracle.t.sol b/src/test/AllocatorOracle.t.sol new file mode 100644 index 00000000..a779b3b2 --- /dev/null +++ b/src/test/AllocatorOracle.t.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.8.16; + +import "dss-test/DssTest.sol"; +import "../AllocatorOracle.sol"; + +contract AllocatorOracleTest is DssTest { + AllocatorOracle public oracle; + + function setUp() public { + oracle = new AllocatorOracle(); + } + + function testOracle() public { + (bytes32 val, bool ok) = oracle.peek(); + assertEq(val, bytes32(uint256(10**6 * 10**18))); + assertTrue(ok); + assertEq(oracle.read(), bytes32(uint256(10**6 * 10**18))); + } + + function testPricing() public { + uint256 par = 1 * 10**27; + uint256 price = uint256(oracle.read()); // 1 * 10**6 * 10**18; + uint256 colSupply = 1 * 10**6 * 10**18; + uint256 colDebt = 1 * 10**6 * 10**45; // Imagine a scenario where the ilk only has 1M debt + uint256 totDebt = 50 * 10**9 * 10**45; // Imagine a scenario where the tot Supply of DAI is 50B + + console.log("cage(ilk):"); + console.log(""); + uint256 tag = par * 10**18 / price; + console.log("tag[ilk] =", tag); + console.log(""); + console.log("skim(ilk, buffer):"); + console.log(""); + uint256 owe = (colDebt / 10**27) * tag / 10**27; + console.log("owe =", owe); + uint256 wad = owe <= colSupply ? owe : colSupply; + console.log("wad =", wad); + uint256 gap = owe - wad; + console.log("gap[ilk] =", gap); + console.log(""); + console.log("flow(ilk):"); + console.log(""); + wad = (colDebt / 10**27) * tag / 10**27; + console.log("wad =", wad); + uint256 fix = (wad - gap) * 10**27 / (totDebt / 10**27); + console.log("fix[ilk] =", fix); + console.log(""); + console.log("cash(ilk,...):"); + console.log(""); + console.log("1 = wad * fix / 10^27 => wad = 10^27 / fix"); + uint256 amtDaiNeeded = 10**27 / fix; + console.log("Amount of wei DAI needed to get 1 wei of gem =", amtDaiNeeded); + assertEq(amtDaiNeeded, 0.00000005 * 10**18); + } +} From d78847be99c3da549e8448e4c403750a49f0259a Mon Sep 17 00:00:00 2001 From: sunbreak Date: Fri, 2 Jun 2023 09:53:35 -0300 Subject: [PATCH 09/74] Fix copyright Oracle --- src/AllocatorOracle.sol | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/AllocatorOracle.sol b/src/AllocatorOracle.sol index 2a9b6628..eedaf892 100644 --- a/src/AllocatorOracle.sol +++ b/src/AllocatorOracle.sol @@ -1,5 +1,4 @@ -// SPDX-FileCopyrightText: © 2020 Lev Livnev -// SPDX-FileCopyrightText: © 2021 Dai Foundation +// SPDX-FileCopyrightText: © 2023 Dai Foundation // SPDX-License-Identifier: AGPL-3.0-or-later // // This program is free software: you can redistribute it and/or modify From 2446bae9433f1fea323a0375c956e33cd4a9f6f5 Mon Sep 17 00:00:00 2001 From: sunbreak Date: Tue, 6 Jun 2023 18:44:58 -0300 Subject: [PATCH 10/74] Add README --- README | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 README diff --git a/README b/README new file mode 100644 index 00000000..7175dafb --- /dev/null +++ b/README @@ -0,0 +1,2 @@ +Part of this code was inspired by https://github.com/makerdao/rwa-toolkit/blob/master/src/urns/RwaUrn.sol mainly authored by livnev. +Since it should belong to the MakerDAO community the Copyright from our additions has been transferred to Dai Foundation. From 25a46ffd6f1aa93a60560d746a57432707392095 Mon Sep 17 00:00:00 2001 From: sunbreak Date: Wed, 7 Jun 2023 12:25:18 -0300 Subject: [PATCH 11/74] Add getters --- src/AllocatorBuffer.sol | 21 +++++++++++++++++++++ src/test/AllocatorBuffer.t.sol | 13 ++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/AllocatorBuffer.sol b/src/AllocatorBuffer.sol index 4e45f0f3..9a134ed6 100644 --- a/src/AllocatorBuffer.sol +++ b/src/AllocatorBuffer.sol @@ -18,7 +18,9 @@ pragma solidity ^0.8.16; interface VatLike { + function ilks(bytes32) external view returns (uint256, uint256, uint256, uint256, uint256); function live() external view returns (uint256); + function urns(bytes32, address) external view returns (uint256, uint256); function frob(bytes32, address, address, address, int256, int256) external; function hope(address) external; } @@ -111,6 +113,25 @@ contract AllocatorBuffer { } } + // --- getters --- + + function debt() external view returns (uint256) { + (, uint256 art) = vat.urns(ilk, address(this)); + (, uint rate,,,) = vat.ilks(ilk); + return _divup(art * rate, RAY); + } + + function line() external view returns (uint256) { + (,,, uint256 line_,) = vat.ilks(ilk); + return line_ / RAY; + } + + function slot() external view returns (uint256) { + (, uint256 art) = vat.urns(ilk, address(this)); + (, uint rate,,uint256 line_,) = vat.ilks(ilk); + return (line_ - art * rate) / RAY; + } + // --- administration --- function init() external auth { diff --git a/src/test/AllocatorBuffer.t.sol b/src/test/AllocatorBuffer.t.sol index 0c3ac604..7e8052cf 100644 --- a/src/test/AllocatorBuffer.t.sol +++ b/src/test/AllocatorBuffer.t.sol @@ -7,6 +7,7 @@ import "../AllocatorBuffer.sol"; contract VatMock { uint256 public rate = 10**27; + uint256 public line = 20_000_000 * 10**45; struct Urn { uint256 ink; @@ -17,10 +18,11 @@ contract VatMock { mapping (bytes32 => mapping (address => uint)) public gem; mapping (address => uint256) public dai; - function hope(address) external {} + function ilks(bytes32) external view returns (uint256, uint256, uint256, uint256, uint256) { + return (0, rate, 0, line, 0); + } - event log(string, uint256); - event log(string, int256); + function hope(address) external {} function frob(bytes32 i, address u, address v, address w, int256 dink, int256 dart) external { Urn memory urn = urns[i][u]; @@ -258,12 +260,15 @@ contract AllocatorBufferTest is DssTest { function testDrawWipe() public { buffer.init(); buffer.file("jug", address(jug)); + assertEq(buffer.line(), 20_000_000 * 10**18); (, uint256 art) = vat.urns(ilk, address(buffer)); assertEq(art, 0); buffer.draw(50 * 10**18); (, art) = vat.urns(ilk, address(buffer)); assertEq(art, 50 * 10**18); assertEq(vat.rate(), 10**27); + assertEq(buffer.debt(), 50 * 10**18); + assertEq(buffer.slot(), (20_000_000 - 50) * 10**18); assertEq(nst.balanceOf(address(buffer)), 50 * 10**18); vm.warp(block.timestamp + 1); buffer.draw(50 * 10**18); @@ -271,6 +276,8 @@ contract AllocatorBufferTest is DssTest { uint256 expectedArt = 50 * 10**18 + _divup(50 * 10**18 * 1000, div); assertEq(art, expectedArt); assertEq(vat.rate(), 1001 * 10**27 / 1000); + assertEq(buffer.debt(), _divup(expectedArt * 1001, 1000)); + assertEq(buffer.slot(), 20_000_000 * 10**18 - _divup(expectedArt * 1001, 1000)); assertEq(nst.balanceOf(address(buffer)), 100 * 10**18); assertGt(art * vat.rate(), 100.05 * 10**45); assertLt(art * vat.rate(), 100.06 * 10**45); From 685204dc192b779a86c0f54137092c15f0b3c149 Mon Sep 17 00:00:00 2001 From: sunbreak Date: Wed, 7 Jun 2023 12:58:58 -0300 Subject: [PATCH 12/74] Fix slot + minors --- src/AllocatorBuffer.sol | 7 ++++--- src/test/AllocatorBuffer.t.sol | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/AllocatorBuffer.sol b/src/AllocatorBuffer.sol index 9a134ed6..99c409cf 100644 --- a/src/AllocatorBuffer.sol +++ b/src/AllocatorBuffer.sol @@ -117,7 +117,7 @@ contract AllocatorBuffer { function debt() external view returns (uint256) { (, uint256 art) = vat.urns(ilk, address(this)); - (, uint rate,,,) = vat.ilks(ilk); + (, uint256 rate,,,) = vat.ilks(ilk); return _divup(art * rate, RAY); } @@ -128,8 +128,9 @@ contract AllocatorBuffer { function slot() external view returns (uint256) { (, uint256 art) = vat.urns(ilk, address(this)); - (, uint rate,,uint256 line_,) = vat.ilks(ilk); - return (line_ - art * rate) / RAY; + (, uint256 rate,, uint256 line_,) = vat.ilks(ilk); + uint256 debt_ = art * rate; + return line_ > debt_ ? (line_ - debt_) / RAY : 0; } // --- administration --- diff --git a/src/test/AllocatorBuffer.t.sol b/src/test/AllocatorBuffer.t.sol index 7e8052cf..50a41ce3 100644 --- a/src/test/AllocatorBuffer.t.sol +++ b/src/test/AllocatorBuffer.t.sol @@ -268,7 +268,7 @@ contract AllocatorBufferTest is DssTest { assertEq(art, 50 * 10**18); assertEq(vat.rate(), 10**27); assertEq(buffer.debt(), 50 * 10**18); - assertEq(buffer.slot(), (20_000_000 - 50) * 10**18); + assertEq(buffer.slot(), buffer.line() - 50 * 10**18); assertEq(nst.balanceOf(address(buffer)), 50 * 10**18); vm.warp(block.timestamp + 1); buffer.draw(50 * 10**18); @@ -277,7 +277,7 @@ contract AllocatorBufferTest is DssTest { assertEq(art, expectedArt); assertEq(vat.rate(), 1001 * 10**27 / 1000); assertEq(buffer.debt(), _divup(expectedArt * 1001, 1000)); - assertEq(buffer.slot(), 20_000_000 * 10**18 - _divup(expectedArt * 1001, 1000)); + assertEq(buffer.slot(), buffer.line() - _divup(expectedArt * 1001, 1000)); assertEq(nst.balanceOf(address(buffer)), 100 * 10**18); assertGt(art * vat.rate(), 100.05 * 10**45); assertLt(art * vat.rate(), 100.06 * 10**45); @@ -309,4 +309,14 @@ contract AllocatorBufferTest is DssTest { assertEq(nst.balanceOf(address(buffer)), 30 * 10**18); assertEq(nst.balanceOf(address(0xBEEF)), 20 * 10**18); } + + function testDebtOverLine() public { + buffer.init(); + buffer.file("jug", address(jug)); + buffer.draw(buffer.line()); + vm.warp(block.timestamp + 1); + jug.drip(ilk); + assertGt(buffer.debt(), buffer.line()); + assertEq(buffer.slot(), 0); + } } From 9b99efeae01e20d5a8949b61db5b01ff88aa237e Mon Sep 17 00:00:00 2001 From: sunbreak Date: Wed, 7 Jun 2023 13:40:42 -0300 Subject: [PATCH 13/74] Use Art for calculating slot --- src/AllocatorBuffer.sol | 7 ++++--- src/test/AllocatorBuffer.t.sol | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/AllocatorBuffer.sol b/src/AllocatorBuffer.sol index 99c409cf..110f9e61 100644 --- a/src/AllocatorBuffer.sol +++ b/src/AllocatorBuffer.sol @@ -114,6 +114,8 @@ contract AllocatorBuffer { } // --- getters --- + // In theory, `ilk.Art` should be equal than `urn.art` for this type of collateral, as there should only be one position per `ilk`. + // However to stick with the correct usage, `ilk.Art` is used for calculating `slot()` and `urn.art` for the `debt()` of this position. function debt() external view returns (uint256) { (, uint256 art) = vat.urns(ilk, address(this)); @@ -127,9 +129,8 @@ contract AllocatorBuffer { } function slot() external view returns (uint256) { - (, uint256 art) = vat.urns(ilk, address(this)); - (, uint256 rate,, uint256 line_,) = vat.ilks(ilk); - uint256 debt_ = art * rate; + (uint256 Art, uint256 rate,, uint256 line_,) = vat.ilks(ilk); + uint256 debt_ = Art * rate; return line_ > debt_ ? (line_ - debt_) / RAY : 0; } diff --git a/src/test/AllocatorBuffer.t.sol b/src/test/AllocatorBuffer.t.sol index 50a41ce3..0b1ac1b4 100644 --- a/src/test/AllocatorBuffer.t.sol +++ b/src/test/AllocatorBuffer.t.sol @@ -6,6 +6,7 @@ import "dss-test/DssTest.sol"; import "../AllocatorBuffer.sol"; contract VatMock { + uint256 public Art; uint256 public rate = 10**27; uint256 public line = 20_000_000 * 10**45; @@ -19,7 +20,7 @@ contract VatMock { mapping (address => uint256) public dai; function ilks(bytes32) external view returns (uint256, uint256, uint256, uint256, uint256) { - return (0, rate, 0, line, 0); + return (Art, rate, 0, line, 0); } function hope(address) external {} @@ -28,7 +29,7 @@ contract VatMock { Urn memory urn = urns[i][u]; urn.ink = dink >= 0 ? urn.ink + uint256(dink) : urn.ink - uint256(-dink); - urn.art = dart >= 0 ? urn.art + uint256(dart) : urn.art - uint256(-dart); + Art = urn.art = dart >= 0 ? urn.art + uint256(dart) : urn.art - uint256(-dart); gem[i][v] = dink >= 0 ? gem[i][v] - uint256(dink) : gem[i][v] + uint256(-dink); int256 dtab = int256(rate) * dart; From 27aca28b3eb2bd581a798ba538bf750a6dbf2774 Mon Sep 17 00:00:00 2001 From: sunbreak Date: Tue, 13 Jun 2023 12:13:24 -0300 Subject: [PATCH 14/74] Fix typo --- src/AllocatorBuffer.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AllocatorBuffer.sol b/src/AllocatorBuffer.sol index 110f9e61..1b18744c 100644 --- a/src/AllocatorBuffer.sol +++ b/src/AllocatorBuffer.sol @@ -114,7 +114,7 @@ contract AllocatorBuffer { } // --- getters --- - // In theory, `ilk.Art` should be equal than `urn.art` for this type of collateral, as there should only be one position per `ilk`. + // In theory, `ilk.Art` should be equal to `urn.art` for this type of collateral, as there should only be one position per `ilk`. // However to stick with the correct usage, `ilk.Art` is used for calculating `slot()` and `urn.art` for the `debt()` of this position. function debt() external view returns (uint256) { From 332ca1e86789eb964e834cb913ef01d9d574539b Mon Sep 17 00:00:00 2001 From: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> Date: Tue, 13 Jun 2023 12:37:09 -0300 Subject: [PATCH 15/74] Change Buffer back to Vault and add an Escrow called Buffer (#3) * Rename Buffer back to Vault * Add Escrow called Buffer * Wipe from another address * Complete buffer, add tests and minor changes --- foundry.toml | 6 +- ...catorBuffer.s.sol => AllocatorVault.s.sol} | 2 +- src/AllocatorBuffer.sol | 151 +-------- src/AllocatorVault.sol | 198 +++++++++++ src/test/AllocatorBuffer.t.sol | 310 +----------------- src/test/AllocatorVault.t.sol | 147 +++++++++ src/test/mocks/GemJoinMock.sol | 23 ++ src/test/mocks/GemMock.sol | 80 +++++ src/test/mocks/JugMock.sol | 23 ++ src/test/mocks/NstJoinMock.sol | 26 ++ src/test/mocks/VatMock.sol | 50 +++ 11 files changed, 586 insertions(+), 430 deletions(-) rename script/{AllocatorBuffer.s.sol => AllocatorVault.s.sol} (82%) create mode 100644 src/AllocatorVault.sol create mode 100644 src/test/AllocatorVault.t.sol create mode 100644 src/test/mocks/GemJoinMock.sol create mode 100644 src/test/mocks/GemMock.sol create mode 100644 src/test/mocks/JugMock.sol create mode 100644 src/test/mocks/NstJoinMock.sol create mode 100644 src/test/mocks/VatMock.sol diff --git a/foundry.toml b/foundry.toml index 4ff40c48..877d016c 100644 --- a/foundry.toml +++ b/foundry.toml @@ -2,5 +2,9 @@ src = "src" out = "out" libs = ["lib"] +solc = "0.8.16" +optimizer = true +optimizer_runs = 200 +verbosity = 3 -# See more config options https://github.com/foundry-rs/foundry/tree/master/config \ No newline at end of file +# See more config options https://github.com/foundry-rs/foundry/tree/master/config diff --git a/script/AllocatorBuffer.s.sol b/script/AllocatorVault.s.sol similarity index 82% rename from script/AllocatorBuffer.s.sol rename to script/AllocatorVault.s.sol index 01d01f5d..4f5e8655 100644 --- a/script/AllocatorBuffer.s.sol +++ b/script/AllocatorVault.s.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.16; import "forge-std/Script.sol"; -contract AllocatorBufferScript is Script { +contract AllocatorVaultScript is Script { function setUp() public {} function run() public { diff --git a/src/AllocatorBuffer.sol b/src/AllocatorBuffer.sol index 1b18744c..d517122a 100644 --- a/src/AllocatorBuffer.sol +++ b/src/AllocatorBuffer.sol @@ -1,5 +1,4 @@ -// SPDX-FileCopyrightText: © 2020 Lev Livnev -// SPDX-FileCopyrightText: © 2021 Dai Foundation +// SPDX-FileCopyrightText: © 2023 Dai Foundation // SPDX-License-Identifier: AGPL-3.0-or-later // // This program is free software: you can redistribute it and/or modify @@ -17,66 +16,22 @@ pragma solidity ^0.8.16; -interface VatLike { - function ilks(bytes32) external view returns (uint256, uint256, uint256, uint256, uint256); - function live() external view returns (uint256); - function urns(bytes32, address) external view returns (uint256, uint256); - function frob(bytes32, address, address, address, int256, int256) external; - function hope(address) external; -} - -interface JugLike { - function drip(bytes32) external returns (uint256); -} - interface TokenLike { - function totalSupply() external view returns (uint256); function approve(address, uint256) external; - function transfer(address, uint256) external; -} - -interface GemJoinLike { - function gem() external view returns (TokenLike); - function ilk() external view returns (bytes32); - function vat() external view returns (address); - function join(address, uint256) external; -} - -interface NstJoinLike { - function nst() external view returns (TokenLike); - function vat() external view returns (address); - function exit(address, uint256) external; - function join(address, uint256) external; + function transferFrom(address, address, uint256) external; } contract AllocatorBuffer { - // --- storage variables --- mapping(address => uint256) public wards; - JugLike public jug; - - // --- constants --- - - uint256 constant WAD = 10**18; - uint256 constant RAY = 10**27; - - // --- immutables --- - - VatLike immutable public vat; - bytes32 immutable public ilk; - GemJoinLike immutable public gemJoin; - NstJoinLike immutable public nstJoin; - TokenLike immutable public nst; // --- events --- event Rely(address indexed usr); event Deny(address indexed usr); - event File(bytes32 indexed what, address data); - event Draw(address indexed funnel, address indexed to, uint256 wad); - event Take(address indexed funnel, address indexed to, uint256 wad); - event Wipe(address indexed funnel, uint256 wad); + event Approve(address indexed token, address indexed spender, uint256 amount); + event Deposit(address indexed token, address indexed sender, uint256 amount); // --- modifiers --- @@ -87,65 +42,13 @@ contract AllocatorBuffer { // --- constructor --- - constructor(address vat_, address gemJoin_, address nstJoin_) { - vat = VatLike(vat_); - - gemJoin = GemJoinLike(gemJoin_); - nstJoin = NstJoinLike(nstJoin_); - - require(vat_ == gemJoin.vat() && vat_ == nstJoin.vat(), "AllocatorBuffer/vat-not-match"); - - ilk = GemJoinLike(gemJoin_).ilk(); - nst = NstJoinLike(nstJoin_).nst(); - - VatLike(vat_).hope(nstJoin_); - nst.approve(nstJoin_, type(uint256).max); - + constructor() { wards[msg.sender] = 1; emit Rely(msg.sender); } - // --- math --- - - function _divup(uint256 x, uint256 y) internal pure returns (uint256 z) { - unchecked { - z = x != 0 ? ((x - 1) / y) + 1 : 0; - } - } - - // --- getters --- - // In theory, `ilk.Art` should be equal to `urn.art` for this type of collateral, as there should only be one position per `ilk`. - // However to stick with the correct usage, `ilk.Art` is used for calculating `slot()` and `urn.art` for the `debt()` of this position. - - function debt() external view returns (uint256) { - (, uint256 art) = vat.urns(ilk, address(this)); - (, uint256 rate,,,) = vat.ilks(ilk); - return _divup(art * rate, RAY); - } - - function line() external view returns (uint256) { - (,,, uint256 line_,) = vat.ilks(ilk); - return line_ / RAY; - } - - function slot() external view returns (uint256) { - (uint256 Art, uint256 rate,, uint256 line_,) = vat.ilks(ilk); - uint256 debt_ = Art * rate; - return line_ > debt_ ? (line_ - debt_) / RAY : 0; - } - // --- administration --- - function init() external auth { - TokenLike gem = gemJoin.gem(); - uint256 supply = gem.totalSupply(); - require(supply == 10**6 * WAD, "AllocatorBuffer/supply-not-one-million-wad"); - - gem.approve(address(gemJoin), supply); - gemJoin.join(address(this), supply); - vat.frob(ilk, address(this), address(this), address(0), int256(supply), 0); - } - function rely(address usr) external auth { wards[usr] = 1; emit Rely(usr); @@ -156,41 +59,19 @@ contract AllocatorBuffer { emit Deny(usr); } - function file(bytes32 what, address data) external auth { - if (what == "jug") { - jug = JugLike(data); - } else revert("AllocatorBuffer/file-unrecognized-param"); - emit File(what, data); - } + // --- functions --- - // --- funnels execution --- - - function draw(address to, uint256 wad) public auth { - uint256 rate = jug.drip(ilk); - uint256 dart = _divup(wad * RAY, rate); - require(dart <= uint256(type(int256).max), "AllocatorBuffer/overflow"); - vat.frob(ilk, address(this), address(0), address(this), 0, int256(dart)); - nstJoin.exit(to, wad); - emit Draw(msg.sender, to, wad); + function approve( + address token, + address spender, + uint256 amount + ) external auth { + TokenLike(token).approve(spender, amount); + emit Approve(token, spender, amount); } - function draw(uint256 wad) external { - draw(address(this), wad); + function deposit(address token, uint256 amount, address /* owner */) external { + TokenLike(token).transferFrom(msg.sender, address(this), amount); + emit Deposit(token, msg.sender, amount); } - - function take(address to, uint256 wad) external auth { - nst.transfer(to, wad); - emit Take(msg.sender, to, wad); - } - - function wipe(uint256 wad) external auth { - nstJoin.join(address(this), wad); - uint256 rate = jug.drip(ilk); - uint256 dart = wad * RAY / rate; - require(dart <= uint256(type(int256).max), "AllocatorBuffer/overflow"); - vat.frob(ilk, address(this), address(this), address(this), 0, -int256(dart)); - emit Wipe(msg.sender, wad); - } - - // TODO: evaluate if quit function is necessary and how it should be } diff --git a/src/AllocatorVault.sol b/src/AllocatorVault.sol new file mode 100644 index 00000000..bfff0863 --- /dev/null +++ b/src/AllocatorVault.sol @@ -0,0 +1,198 @@ +// SPDX-FileCopyrightText: © 2020 Lev Livnev +// SPDX-FileCopyrightText: © 2021 Dai Foundation +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +pragma solidity ^0.8.16; + +interface VatLike { + function ilks(bytes32) external view returns (uint256, uint256, uint256, uint256, uint256); + function live() external view returns (uint256); + function urns(bytes32, address) external view returns (uint256, uint256); + function frob(bytes32, address, address, address, int256, int256) external; + function hope(address) external; +} + +interface JugLike { + function drip(bytes32) external returns (uint256); +} + +interface TokenLike { + function totalSupply() external view returns (uint256); + function approve(address, uint256) external; + function transferFrom(address, address, uint256) external; +} + +interface GemJoinLike { + function gem() external view returns (TokenLike); + function ilk() external view returns (bytes32); + function vat() external view returns (address); + function join(address, uint256) external; +} + +interface NstJoinLike { + function nst() external view returns (TokenLike); + function vat() external view returns (address); + function exit(address, uint256) external; + function join(address, uint256) external; +} + +contract AllocatorVault { + + // --- storage variables --- + + mapping(address => uint256) public wards; + JugLike public jug; + + // --- constants --- + + uint256 constant WAD = 10**18; + uint256 constant RAY = 10**27; + + // --- immutables --- + + address immutable public buffer; + VatLike immutable public vat; + bytes32 immutable public ilk; + GemJoinLike immutable public gemJoin; + NstJoinLike immutable public nstJoin; + TokenLike immutable public nst; + + // --- events --- + + event Rely(address indexed usr); + event Deny(address indexed usr); + event File(bytes32 indexed what, address data); + event Draw(address indexed funnel, address indexed to, uint256 wad); + event Take(address indexed funnel, address indexed to, uint256 wad); + event Wipe(address indexed funnel, uint256 wad); + + // --- modifiers --- + + modifier auth() { + require(wards[msg.sender] == 1, "AllocatorVault/not-authorized"); + _; + } + + // --- constructor --- + + constructor(address buffer_, address vat_, address gemJoin_, address nstJoin_) { + buffer = buffer_; + vat = VatLike(vat_); + + gemJoin = GemJoinLike(gemJoin_); + nstJoin = NstJoinLike(nstJoin_); + + require(vat_ == gemJoin.vat() && vat_ == nstJoin.vat(), "AllocatorVault/vat-not-match"); + + ilk = GemJoinLike(gemJoin_).ilk(); + nst = NstJoinLike(nstJoin_).nst(); + + VatLike(vat_).hope(nstJoin_); + nst.approve(nstJoin_, type(uint256).max); + + wards[msg.sender] = 1; + emit Rely(msg.sender); + } + + // --- math --- + + function _divup(uint256 x, uint256 y) internal pure returns (uint256 z) { + unchecked { + z = x != 0 ? ((x - 1) / y) + 1 : 0; + } + } + + // --- getters --- + // In theory, `ilk.Art` should be equal to `urn.art` for this type of collateral, as there should only be one position per `ilk`. + // However to stick with the correct usage, `ilk.Art` is used for calculating `slot()` and `urn.art` for the `debt()` of this position. + + function debt() external view returns (uint256) { + (, uint256 art) = vat.urns(ilk, address(this)); + (, uint256 rate,,,) = vat.ilks(ilk); + return _divup(art * rate, RAY); + } + + function line() external view returns (uint256) { + (,,, uint256 line_,) = vat.ilks(ilk); + return line_ / RAY; + } + + function slot() external view returns (uint256) { + (uint256 Art, uint256 rate,, uint256 line_,) = vat.ilks(ilk); + uint256 debt_ = Art * rate; + return line_ > debt_ ? (line_ - debt_) / RAY : 0; + } + + // --- administration --- + + function init() external auth { + TokenLike gem = gemJoin.gem(); + uint256 supply = gem.totalSupply(); + require(supply == 10**6 * WAD, "AllocatorVault/supply-not-one-million-wad"); + + gem.approve(address(gemJoin), supply); + gemJoin.join(address(this), supply); + vat.frob(ilk, address(this), address(this), address(0), int256(supply), 0); + } + + function rely(address usr) external auth { + wards[usr] = 1; + emit Rely(usr); + } + + function deny(address usr) external auth { + wards[usr] = 0; + emit Deny(usr); + } + + function file(bytes32 what, address data) external auth { + if (what == "jug") { + jug = JugLike(data); + } else revert("AllocatorVault/file-unrecognized-param"); + emit File(what, data); + } + + // --- funnels execution --- + + function draw(address to, uint256 wad) public auth { + uint256 rate = jug.drip(ilk); + uint256 dart = _divup(wad * RAY, rate); + require(dart <= uint256(type(int256).max), "AllocatorVault/overflow"); + vat.frob(ilk, address(this), address(0), address(this), 0, int256(dart)); + nstJoin.exit(to, wad); + emit Draw(msg.sender, to, wad); + } + + function draw(uint256 wad) external { + draw(buffer, wad); + } + + function wipe(address from, uint256 wad) public auth { + nst.transferFrom(from, address(this), wad); + nstJoin.join(address(this), wad); + uint256 rate = jug.drip(ilk); + uint256 dart = wad * RAY / rate; + require(dart <= uint256(type(int256).max), "AllocatorVault/overflow"); + vat.frob(ilk, address(this), address(this), address(this), 0, -int256(dart)); + emit Wipe(msg.sender, wad); + } + + function wipe(uint256 wad) external { + wipe(buffer, wad); + } + + // TODO: evaluate if quit function is necessary and how it should be +} diff --git a/src/test/AllocatorBuffer.t.sol b/src/test/AllocatorBuffer.t.sol index 0b1ac1b4..9583f1ef 100644 --- a/src/test/AllocatorBuffer.t.sol +++ b/src/test/AllocatorBuffer.t.sol @@ -3,218 +3,18 @@ pragma solidity ^0.8.16; import "dss-test/DssTest.sol"; -import "../AllocatorBuffer.sol"; - -contract VatMock { - uint256 public Art; - uint256 public rate = 10**27; - uint256 public line = 20_000_000 * 10**45; - - struct Urn { - uint256 ink; - uint256 art; - } - - mapping (bytes32 => mapping (address => Urn )) public urns; - mapping (bytes32 => mapping (address => uint)) public gem; - mapping (address => uint256) public dai; - - function ilks(bytes32) external view returns (uint256, uint256, uint256, uint256, uint256) { - return (Art, rate, 0, line, 0); - } - - function hope(address) external {} - - function frob(bytes32 i, address u, address v, address w, int256 dink, int256 dart) external { - Urn memory urn = urns[i][u]; - - urn.ink = dink >= 0 ? urn.ink + uint256(dink) : urn.ink - uint256(-dink); - Art = urn.art = dart >= 0 ? urn.art + uint256(dart) : urn.art - uint256(-dart); - - gem[i][v] = dink >= 0 ? gem[i][v] - uint256(dink) : gem[i][v] + uint256(-dink); - int256 dtab = int256(rate) * dart; - dai[w] = dtab >= 0 ? dai[w] + uint256(dtab) : dai[w] - uint256(-dtab); - - urns[i][u] = urn; - } - - function move(address src, address dst, uint256 rad) external { - dai[src] = dai[src] - rad; - dai[dst] = dai[dst] + rad; - } - - function slip(bytes32 ilk, address usr, int256 wad) external { - gem[ilk][usr] = wad >= 0 ? gem[ilk][usr] + uint256(wad) : gem[ilk][usr] - uint256(-wad); - } - - function fold(uint256 rate_) external { - rate = rate + rate_; - } -} - -contract JugMock { - VatMock vat; - - uint256 duty = 1001 * 10**27 / 1000; - uint256 rho = block.timestamp; - - constructor(VatMock vat_) { - vat = vat_; - } - - function drip(bytes32) external returns (uint256 rate) { - uint256 add = (duty - 10**27) * (block.timestamp - rho); - rate = vat.rate() + add; - vat.fold(add); - rho = block.timestamp; - } -} - -contract GemMock { - mapping (address => uint256) public balanceOf; - mapping (address => mapping (address => uint256)) public allowance; - - uint256 public totalSupply; - - constructor(uint256 initialSupply) { - mint(msg.sender, initialSupply); - } - - function approve(address spender, uint256 value) external returns (bool) { - allowance[msg.sender][spender] = value; - return true; - } - - function transfer(address to, uint256 value) external returns (bool) { - uint256 balance = balanceOf[msg.sender]; - require(balance >= value, "Gem/insufficient-balance"); - - unchecked { - balanceOf[msg.sender] = balance - value; - balanceOf[to] += value; - } - return true; - } - - function transferFrom(address from, address to, uint256 value) external returns (bool) { - uint256 balance = balanceOf[from]; - require(balance >= value, "Gem/insufficient-balance"); - - if (from != msg.sender) { - uint256 allowed = allowance[from][msg.sender]; - if (allowed != type(uint256).max) { - require(allowed >= value, "Gem/insufficient-allowance"); - - unchecked { - allowance[from][msg.sender] = allowed - value; - } - } - } - - unchecked { - balanceOf[from] = balance - value; - balanceOf[to] += value; - } - return true; - } - - function mint(address to, uint256 value) public { - unchecked { - balanceOf[to] = balanceOf[to] + value; - } - totalSupply = totalSupply + value; - } - - function burn(address from, uint256 value) external { - uint256 balance = balanceOf[from]; - require(balance >= value, "Gem/insufficient-balance"); - - if (from != msg.sender) { - uint256 allowed = allowance[from][msg.sender]; - if (allowed != type(uint256).max) { - require(allowed >= value, "Gem/insufficient-allowance"); - - unchecked { - allowance[from][msg.sender] = allowed - value; - } - } - } - - unchecked { - balanceOf[from] = balance - value; - totalSupply = totalSupply - value; - } - } -} - -contract GemJoinMock { - VatMock public vat; - bytes32 public ilk; - GemMock public gem; - - constructor(VatMock vat_, bytes32 ilk_, GemMock gem_) { - vat = vat_; - ilk = ilk_; - gem = gem_; - } - - function join(address usr, uint256 wad) external { - vat.slip(ilk, usr, int256(wad)); - gem.transferFrom(msg.sender, address(this), wad); - } -} - -contract NstJoinMock { - VatMock public vat; - GemMock public nst; - - constructor(VatMock vat_, GemMock nst_) { - vat = vat_; - nst = nst_; - } - - function join(address usr, uint256 wad) external { - vat.move(address(this), usr, wad * 10**27); - nst.burn(msg.sender, wad); - } - - function exit(address usr, uint256 wad) external { - vat.move(msg.sender, address(this), wad * 10**27); - nst.mint(usr, wad); - } -} +import { AllocatorBuffer } from "../AllocatorBuffer.sol"; +import { GemMock } from "./mocks/GemMock.sol"; contract AllocatorBufferTest is DssTest { using stdStorage for StdStorage; - VatMock public vat; - JugMock public jug; GemMock public gem; - GemJoinMock public gemJoin; - GemMock public nst; - NstJoinMock public nstJoin; AllocatorBuffer public buffer; - bytes32 public ilk; - - function _divup(uint256 x, uint256 y) internal pure returns (uint256 z) { - unchecked { - z = x != 0 ? ((x - 1) / y) + 1 : 0; - } - } function setUp() public { - ilk = "TEST-ILK"; - vat = new VatMock(); - jug = new JugMock(vat); - gem = new GemMock(1_000_000 * 10**18); - gemJoin = new GemJoinMock(vat, ilk, gem); - nst = new GemMock(0); - nstJoin = new NstJoinMock(vat, nst); - buffer = new AllocatorBuffer(address(vat), address(gemJoin), address(nstJoin)); - gem.transfer(address(buffer), 1_000_000 * 10**18); - - // Add some existing DAI assigned to nstJoin to avoid a particular error - stdstore.target(address(vat)).sig("dai(address)").with_key(address(nstJoin)).depth(0).checked_write(100_000 * 10**45); + gem = new GemMock(1_000_000 * 10**18); + buffer = new AllocatorBuffer(); } function testAuth() public { @@ -222,102 +22,26 @@ contract AllocatorBufferTest is DssTest { } function testModifiers() public { - bytes4[] memory authedMethods = new bytes4[](5); - authedMethods[0] = buffer.init.selector; - authedMethods[1] = bytes4(keccak256("draw(address,uint256)")); - authedMethods[2] = bytes4(keccak256("draw(uint256)")); - authedMethods[3] = buffer.take.selector; - authedMethods[4] = buffer.wipe.selector; + bytes4[] memory authedMethods = new bytes4[](1); + authedMethods[0] = buffer.approve.selector; vm.startPrank(address(0xBEEF)); checkModifier(address(buffer), "AllocatorBuffer/not-authorized", authedMethods); vm.stopPrank(); } - function testFile() public { - checkFileAddress(address(buffer), "AllocatorBuffer", ["jug"]); - } - - function testInit() public { - assertEq(gem.balanceOf(address(buffer)), gem.totalSupply()); - assertEq(gem.balanceOf(address(gemJoin)), 0); - (uint256 ink, ) = vat.urns(ilk, address(buffer)); - assertEq(ink, 0); - buffer.init(); - assertEq(gem.balanceOf(address(buffer)), 0); - assertEq(gem.balanceOf(address(gemJoin)), gem.totalSupply()); - (ink, ) = vat.urns(ilk, address(buffer)); - assertEq(ink, gem.totalSupply()); - } - - function testInitNotTotalSupply() public { - deal(address(gem), address(buffer), gem.balanceOf(address(buffer)) - 1); - vm.expectRevert("Gem/insufficient-balance"); - buffer.init(); - } - - uint256 div = 1001; // Hack to solve a compiling issue - - function testDrawWipe() public { - buffer.init(); - buffer.file("jug", address(jug)); - assertEq(buffer.line(), 20_000_000 * 10**18); - (, uint256 art) = vat.urns(ilk, address(buffer)); - assertEq(art, 0); - buffer.draw(50 * 10**18); - (, art) = vat.urns(ilk, address(buffer)); - assertEq(art, 50 * 10**18); - assertEq(vat.rate(), 10**27); - assertEq(buffer.debt(), 50 * 10**18); - assertEq(buffer.slot(), buffer.line() - 50 * 10**18); - assertEq(nst.balanceOf(address(buffer)), 50 * 10**18); - vm.warp(block.timestamp + 1); - buffer.draw(50 * 10**18); - (, art) = vat.urns(ilk, address(buffer)); - uint256 expectedArt = 50 * 10**18 + _divup(50 * 10**18 * 1000, div); - assertEq(art, expectedArt); - assertEq(vat.rate(), 1001 * 10**27 / 1000); - assertEq(buffer.debt(), _divup(expectedArt * 1001, 1000)); - assertEq(buffer.slot(), buffer.line() - _divup(expectedArt * 1001, 1000)); - assertEq(nst.balanceOf(address(buffer)), 100 * 10**18); - assertGt(art * vat.rate(), 100.05 * 10**45); - assertLt(art * vat.rate(), 100.06 * 10**45); - vm.expectRevert("Gem/insufficient-balance"); - buffer.wipe(100.06 ether); - deal(address(nst), address(buffer), 100.06 * 10**18, true); - assertEq(nst.balanceOf(address(buffer)), 100.06 * 10**18); - vm.expectRevert(); - buffer.wipe(100.06 ether); // It will try to wipe more art than existing, then reverts - buffer.wipe(100.05 ether); - assertEq(nst.balanceOf(address(buffer)), 0.01 * 10**18); - (, art) = vat.urns(ilk, address(buffer)); - assertEq(art, 1); // Dust which is impossible to wipe - } - - function testDrawOtherAddress() public { - buffer.init(); - buffer.file("jug", address(jug)); - buffer.draw(address(0xBEEF), 50 * 10**18); - assertEq(nst.balanceOf(address(0xBEEF)), 50 * 10**18); - } - - function testDrawAndTake() public { - buffer.init(); - buffer.file("jug", address(jug)); - buffer.draw(50 * 10**18); - assertEq(nst.balanceOf(address(buffer)), 50 * 10**18); - buffer.take(address(0xBEEF), 20 * 10**18); - assertEq(nst.balanceOf(address(buffer)), 30 * 10**18); - assertEq(nst.balanceOf(address(0xBEEF)), 20 * 10**18); + function testApprove() public { + assertEq(gem.allowance(address(buffer), address(0xBEEF)), 0); + buffer.approve(address(gem), address(0xBEEF), 10); + assertEq(gem.allowance(address(buffer), address(0xBEEF)), 10); } - function testDebtOverLine() public { - buffer.init(); - buffer.file("jug", address(jug)); - buffer.draw(buffer.line()); - vm.warp(block.timestamp + 1); - jug.drip(ilk); - assertGt(buffer.debt(), buffer.line()); - assertEq(buffer.slot(), 0); + function testDeposit() public { + assertEq(gem.balanceOf(address(this)), gem.totalSupply()); + assertEq(gem.balanceOf(address(buffer)), 0); + gem.approve(address(buffer), 10); + buffer.deposit(address(gem), 10, address(0)); + assertEq(gem.balanceOf(address(this)), gem.totalSupply() - 10); + assertEq(gem.balanceOf(address(buffer)), 10); } } diff --git a/src/test/AllocatorVault.t.sol b/src/test/AllocatorVault.t.sol new file mode 100644 index 00000000..050e63eb --- /dev/null +++ b/src/test/AllocatorVault.t.sol @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.8.16; + +import "dss-test/DssTest.sol"; +import { AllocatorVault } from "../AllocatorVault.sol"; +import { AllocatorBuffer } from "../AllocatorBuffer.sol"; +import { VatMock } from "./mocks/VatMock.sol"; +import { JugMock } from "./mocks/JugMock.sol"; +import { GemMock } from "./mocks/GemMock.sol"; +import { GemJoinMock } from "./mocks/GemJoinMock.sol"; +import { NstJoinMock } from "./mocks/NstJoinMock.sol"; + +contract AllocatorVaultTest is DssTest { + using stdStorage for StdStorage; + + VatMock public vat; + JugMock public jug; + GemMock public gem; + GemJoinMock public gemJoin; + GemMock public nst; + NstJoinMock public nstJoin; + AllocatorBuffer public buffer; + AllocatorVault public vault; + bytes32 public ilk; + + function _divup(uint256 x, uint256 y) internal pure returns (uint256 z) { + unchecked { + z = x != 0 ? ((x - 1) / y) + 1 : 0; + } + } + + function setUp() public { + ilk = "TEST-ILK"; + vat = new VatMock(); + jug = new JugMock(vat); + gem = new GemMock(1_000_000 * 10**18); + gemJoin = new GemJoinMock(vat, ilk, gem); + nst = new GemMock(0); + nstJoin = new NstJoinMock(vat, nst); + buffer = new AllocatorBuffer(); + vault = new AllocatorVault(address(buffer), address(vat), address(gemJoin), address(nstJoin)); + buffer.approve(address(nst), address(vault), type(uint256).max); + gem.transfer(address(vault), 1_000_000 * 10**18); + + // Add some existing DAI assigned to nstJoin to avoid a particular error + stdstore.target(address(vat)).sig("dai(address)").with_key(address(nstJoin)).depth(0).checked_write(100_000 * 10**45); + } + + function testAuth() public { + checkAuth(address(vault), "AllocatorVault"); + } + + function testModifiers() public { + bytes4[] memory authedMethods = new bytes4[](5); + authedMethods[0] = vault.init.selector; + authedMethods[1] = bytes4(keccak256("draw(address,uint256)")); + authedMethods[2] = bytes4(keccak256("draw(uint256)")); + authedMethods[3] = bytes4(keccak256("wipe(address,uint256)")); + authedMethods[4] = bytes4(keccak256("wipe(uint256)")); + + vm.startPrank(address(0xBEEF)); + checkModifier(address(vault), "AllocatorVault/not-authorized", authedMethods); + vm.stopPrank(); + } + + function testFile() public { + checkFileAddress(address(vault), "AllocatorVault", ["jug"]); + } + + function testInit() public { + assertEq(gem.balanceOf(address(vault)), gem.totalSupply()); + assertEq(gem.balanceOf(address(gemJoin)), 0); + (uint256 ink, ) = vat.urns(ilk, address(vault)); + assertEq(ink, 0); + vault.init(); + assertEq(gem.balanceOf(address(vault)), 0); + assertEq(gem.balanceOf(address(gemJoin)), gem.totalSupply()); + (ink, ) = vat.urns(ilk, address(vault)); + assertEq(ink, gem.totalSupply()); + } + + function testInitNotTotalSupply() public { + deal(address(gem), address(vault), gem.balanceOf(address(vault)) - 1); + vm.expectRevert("Gem/insufficient-balance"); + vault.init(); + } + + uint256 div = 1001; // Hack to solve a compiling issue + + function testDrawWipe() public { + vault.init(); + vault.file("jug", address(jug)); + assertEq(vault.line(), 20_000_000 * 10**18); + (, uint256 art) = vat.urns(ilk, address(buffer)); + assertEq(art, 0); + vault.draw(50 * 10**18); + (, art) = vat.urns(ilk, address(vault)); + assertEq(art, 50 * 10**18); + assertEq(vat.rate(), 10**27); + assertEq(vault.debt(), 50 * 10**18); + assertEq(vault.slot(), vault.line() - 50 * 10**18); + assertEq(nst.balanceOf(address(buffer)), 50 * 10**18); + vm.warp(block.timestamp + 1); + vault.draw(50 * 10**18); + (, art) = vat.urns(ilk, address(vault)); + uint256 expectedArt = 50 * 10**18 + _divup(50 * 10**18 * 1000, div); + assertEq(art, expectedArt); + assertEq(vat.rate(), 1001 * 10**27 / 1000); + assertEq(vault.debt(), _divup(expectedArt * 1001, 1000)); + assertEq(vault.slot(), vault.line() - _divup(expectedArt * 1001, 1000)); + assertEq(nst.balanceOf(address(buffer)), 100 * 10**18); + assertGt(art * vat.rate(), 100.05 * 10**45); + assertLt(art * vat.rate(), 100.06 * 10**45); + vm.expectRevert("Gem/insufficient-balance"); + vault.wipe(100.06 ether); + deal(address(nst), address(buffer), 100.06 * 10**18, true); + assertEq(nst.balanceOf(address(buffer)), 100.06 * 10**18); + vm.expectRevert(); + vault.wipe(100.06 ether); // It will try to wipe more art than existing, then reverts + vault.wipe(100.05 ether); + assertEq(nst.balanceOf(address(buffer)), 0.01 * 10**18); + (, art) = vat.urns(ilk, address(vault)); + assertEq(art, 1); // Dust which is impossible to wipe + } + + function testDrawAndWipeOtherAddress() public { + vault.init(); + vault.file("jug", address(jug)); + vault.draw(address(0xBEEF), 50 * 10**18); + assertEq(nst.balanceOf(address(0xBEEF)), 50 * 10**18); + vm.prank(address(0xBEEF)); + nst.approve(address(vault), 50 * 10**18); + vault.wipe(address(0xBEEF), 50 * 10**18); + assertEq(nst.balanceOf(address(0xBEEF)), 0); + } + + function testDebtOverLine() public { + vault.init(); + vault.file("jug", address(jug)); + vault.draw(vault.line()); + vm.warp(block.timestamp + 1); + jug.drip(ilk); + assertGt(vault.debt(), vault.line()); + assertEq(vault.slot(), 0); + } +} diff --git a/src/test/mocks/GemJoinMock.sol b/src/test/mocks/GemJoinMock.sol new file mode 100644 index 00000000..f1bbfa34 --- /dev/null +++ b/src/test/mocks/GemJoinMock.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.8.16; + +import { VatMock } from "./VatMock.sol"; +import { GemMock } from "./GemMock.sol"; + +contract GemJoinMock { + VatMock public vat; + bytes32 public ilk; + GemMock public gem; + + constructor(VatMock vat_, bytes32 ilk_, GemMock gem_) { + vat = vat_; + ilk = ilk_; + gem = gem_; + } + + function join(address usr, uint256 wad) external { + vat.slip(ilk, usr, int256(wad)); + gem.transferFrom(msg.sender, address(this), wad); + } +} diff --git a/src/test/mocks/GemMock.sol b/src/test/mocks/GemMock.sol new file mode 100644 index 00000000..789e88a4 --- /dev/null +++ b/src/test/mocks/GemMock.sol @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.8.16; + +contract GemMock { + mapping (address => uint256) public balanceOf; + mapping (address => mapping (address => uint256)) public allowance; + + uint256 public totalSupply; + + constructor(uint256 initialSupply) { + mint(msg.sender, initialSupply); + } + + function approve(address spender, uint256 value) external returns (bool) { + allowance[msg.sender][spender] = value; + return true; + } + + function transfer(address to, uint256 value) external returns (bool) { + uint256 balance = balanceOf[msg.sender]; + require(balance >= value, "Gem/insufficient-balance"); + + unchecked { + balanceOf[msg.sender] = balance - value; + balanceOf[to] += value; + } + return true; + } + + function transferFrom(address from, address to, uint256 value) external returns (bool) { + uint256 balance = balanceOf[from]; + require(balance >= value, "Gem/insufficient-balance"); + + if (from != msg.sender) { + uint256 allowed = allowance[from][msg.sender]; + if (allowed != type(uint256).max) { + require(allowed >= value, "Gem/insufficient-allowance"); + + unchecked { + allowance[from][msg.sender] = allowed - value; + } + } + } + + unchecked { + balanceOf[from] = balance - value; + balanceOf[to] += value; + } + return true; + } + + function mint(address to, uint256 value) public { + unchecked { + balanceOf[to] = balanceOf[to] + value; + } + totalSupply = totalSupply + value; + } + + function burn(address from, uint256 value) external { + uint256 balance = balanceOf[from]; + require(balance >= value, "Gem/insufficient-balance"); + + if (from != msg.sender) { + uint256 allowed = allowance[from][msg.sender]; + if (allowed != type(uint256).max) { + require(allowed >= value, "Gem/insufficient-allowance"); + + unchecked { + allowance[from][msg.sender] = allowed - value; + } + } + } + + unchecked { + balanceOf[from] = balance - value; + totalSupply = totalSupply - value; + } + } +} diff --git a/src/test/mocks/JugMock.sol b/src/test/mocks/JugMock.sol new file mode 100644 index 00000000..ee8ab733 --- /dev/null +++ b/src/test/mocks/JugMock.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.8.16; + +import { VatMock } from "./VatMock.sol"; + +contract JugMock { + VatMock vat; + + uint256 duty = 1001 * 10**27 / 1000; + uint256 rho = block.timestamp; + + constructor(VatMock vat_) { + vat = vat_; + } + + function drip(bytes32) external returns (uint256 rate) { + uint256 add = (duty - 10**27) * (block.timestamp - rho); + rate = vat.rate() + add; + vat.fold(add); + rho = block.timestamp; + } +} diff --git a/src/test/mocks/NstJoinMock.sol b/src/test/mocks/NstJoinMock.sol new file mode 100644 index 00000000..84bfc1ae --- /dev/null +++ b/src/test/mocks/NstJoinMock.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.8.16; + +import { VatMock } from "./VatMock.sol"; +import { GemMock } from "./GemMock.sol"; + +contract NstJoinMock { + VatMock public vat; + GemMock public nst; + + constructor(VatMock vat_, GemMock nst_) { + vat = vat_; + nst = nst_; + } + + function join(address usr, uint256 wad) external { + vat.move(address(this), usr, wad * 10**27); + nst.burn(msg.sender, wad); + } + + function exit(address usr, uint256 wad) external { + vat.move(msg.sender, address(this), wad * 10**27); + nst.mint(usr, wad); + } +} diff --git a/src/test/mocks/VatMock.sol b/src/test/mocks/VatMock.sol new file mode 100644 index 00000000..1880ec21 --- /dev/null +++ b/src/test/mocks/VatMock.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.8.16; + +contract VatMock { + uint256 public Art; + uint256 public rate = 10**27; + uint256 public line = 20_000_000 * 10**45; + + struct Urn { + uint256 ink; + uint256 art; + } + + mapping (bytes32 => mapping (address => Urn )) public urns; + mapping (bytes32 => mapping (address => uint)) public gem; + mapping (address => uint256) public dai; + + function ilks(bytes32) external view returns (uint256, uint256, uint256, uint256, uint256) { + return (Art, rate, 0, line, 0); + } + + function hope(address) external {} + + function frob(bytes32 i, address u, address v, address w, int256 dink, int256 dart) external { + Urn memory urn = urns[i][u]; + + urn.ink = dink >= 0 ? urn.ink + uint256(dink) : urn.ink - uint256(-dink); + Art = urn.art = dart >= 0 ? urn.art + uint256(dart) : urn.art - uint256(-dart); + + gem[i][v] = dink >= 0 ? gem[i][v] - uint256(dink) : gem[i][v] + uint256(-dink); + int256 dtab = int256(rate) * dart; + dai[w] = dtab >= 0 ? dai[w] + uint256(dtab) : dai[w] - uint256(-dtab); + + urns[i][u] = urn; + } + + function move(address src, address dst, uint256 rad) external { + dai[src] = dai[src] - rad; + dai[dst] = dai[dst] + rad; + } + + function slip(bytes32 ilk, address usr, int256 wad) external { + gem[ilk][usr] = wad >= 0 ? gem[ilk][usr] + uint256(wad) : gem[ilk][usr] - uint256(-wad); + } + + function fold(uint256 rate_) external { + rate = rate + rate_; + } +} From 8b97ec38becaae4162e7589b2a401133336c4859 Mon Sep 17 00:00:00 2001 From: sunbreak Date: Tue, 13 Jun 2023 12:59:18 -0300 Subject: [PATCH 16/74] Move test directory and add CI for tests --- .github/workflows/test.yml | 28 ++++++------------------ {src/test => test}/AllocatorBuffer.t.sol | 2 +- {src/test => test}/AllocatorOracle.t.sol | 2 +- {src/test => test}/AllocatorVault.t.sol | 4 ++-- {src/test => test}/mocks/GemJoinMock.sol | 0 {src/test => test}/mocks/GemMock.sol | 0 {src/test => test}/mocks/JugMock.sol | 0 {src/test => test}/mocks/NstJoinMock.sol | 0 {src/test => test}/mocks/VatMock.sol | 0 9 files changed, 11 insertions(+), 25 deletions(-) rename {src/test => test}/AllocatorBuffer.t.sol (95%) rename {src/test => test}/AllocatorOracle.t.sol (98%) rename {src/test => test}/AllocatorVault.t.sol (97%) rename {src/test => test}/mocks/GemJoinMock.sol (100%) rename {src/test => test}/mocks/GemMock.sol (100%) rename {src/test => test}/mocks/JugMock.sol (100%) rename {src/test => test}/mocks/NstJoinMock.sol (100%) rename {src/test => test}/mocks/VatMock.sol (100%) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 09880b1d..272cc4ad 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,34 +1,20 @@ -name: test +name: Tests -on: workflow_dispatch - -env: - FOUNDRY_PROFILE: ci +on: [push, pull_request] jobs: - check: - strategy: - fail-fast: true - - name: Foundry project + tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - with: - submodules: recursive - name: Install Foundry uses: foundry-rs/foundry-toolchain@v1 with: version: nightly - - name: Run Forge build - run: | - forge --version - forge build --sizes - id: build + - name: Install Dependencies + run: forge install - - name: Run Forge tests - run: | - forge test -vvv - id: test + - name: Run tests + run: forge test diff --git a/src/test/AllocatorBuffer.t.sol b/test/AllocatorBuffer.t.sol similarity index 95% rename from src/test/AllocatorBuffer.t.sol rename to test/AllocatorBuffer.t.sol index 9583f1ef..c8135948 100644 --- a/src/test/AllocatorBuffer.t.sol +++ b/test/AllocatorBuffer.t.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.16; import "dss-test/DssTest.sol"; -import { AllocatorBuffer } from "../AllocatorBuffer.sol"; +import { AllocatorBuffer } from "../src/AllocatorBuffer.sol"; import { GemMock } from "./mocks/GemMock.sol"; contract AllocatorBufferTest is DssTest { diff --git a/src/test/AllocatorOracle.t.sol b/test/AllocatorOracle.t.sol similarity index 98% rename from src/test/AllocatorOracle.t.sol rename to test/AllocatorOracle.t.sol index a779b3b2..e4579271 100644 --- a/src/test/AllocatorOracle.t.sol +++ b/test/AllocatorOracle.t.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.16; import "dss-test/DssTest.sol"; -import "../AllocatorOracle.sol"; +import "../src/AllocatorOracle.sol"; contract AllocatorOracleTest is DssTest { AllocatorOracle public oracle; diff --git a/src/test/AllocatorVault.t.sol b/test/AllocatorVault.t.sol similarity index 97% rename from src/test/AllocatorVault.t.sol rename to test/AllocatorVault.t.sol index 050e63eb..c1d7c209 100644 --- a/src/test/AllocatorVault.t.sol +++ b/test/AllocatorVault.t.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.16; import "dss-test/DssTest.sol"; -import { AllocatorVault } from "../AllocatorVault.sol"; -import { AllocatorBuffer } from "../AllocatorBuffer.sol"; +import { AllocatorVault } from "../src/AllocatorVault.sol"; +import { AllocatorBuffer } from "../src/AllocatorBuffer.sol"; import { VatMock } from "./mocks/VatMock.sol"; import { JugMock } from "./mocks/JugMock.sol"; import { GemMock } from "./mocks/GemMock.sol"; diff --git a/src/test/mocks/GemJoinMock.sol b/test/mocks/GemJoinMock.sol similarity index 100% rename from src/test/mocks/GemJoinMock.sol rename to test/mocks/GemJoinMock.sol diff --git a/src/test/mocks/GemMock.sol b/test/mocks/GemMock.sol similarity index 100% rename from src/test/mocks/GemMock.sol rename to test/mocks/GemMock.sol diff --git a/src/test/mocks/JugMock.sol b/test/mocks/JugMock.sol similarity index 100% rename from src/test/mocks/JugMock.sol rename to test/mocks/JugMock.sol diff --git a/src/test/mocks/NstJoinMock.sol b/test/mocks/NstJoinMock.sol similarity index 100% rename from src/test/mocks/NstJoinMock.sol rename to test/mocks/NstJoinMock.sol diff --git a/src/test/mocks/VatMock.sol b/test/mocks/VatMock.sol similarity index 100% rename from src/test/mocks/VatMock.sol rename to test/mocks/VatMock.sol From 8fd99a4d011dd1b9f4f53bfe0ced0f241dc534d1 Mon Sep 17 00:00:00 2001 From: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> Date: Wed, 14 Jun 2023 15:56:37 -0300 Subject: [PATCH 17/74] Add Roles contract (#4) * Add AllocatorRoles * First check roles * Fix for error messaging + add test for roles in the buffer + some renaming and order * Fix test * Add constructor, events and fix parameter of one function * Update README * Add tests + some renaming * Minor changes * Fix indentation * Simplify casting * More casting simplification --- README | 2 +- src/AllocatorRoles.sol | 105 ++++++++++++++++++++++++++++++++ src/AllocatorVault.sol | 20 ++++++- test/AllocatorRoles.t.sol | 122 ++++++++++++++++++++++++++++++++++++++ test/AllocatorVault.t.sol | 13 +++- test/mocks/AuthedMock.sol | 34 +++++++++++ test/mocks/RolesMock.sol | 15 +++++ 7 files changed, 307 insertions(+), 4 deletions(-) create mode 100644 src/AllocatorRoles.sol create mode 100644 test/AllocatorRoles.t.sol create mode 100644 test/mocks/AuthedMock.sol create mode 100644 test/mocks/RolesMock.sol diff --git a/README b/README index 7175dafb..3dc5f4e8 100644 --- a/README +++ b/README @@ -1,2 +1,2 @@ -Part of this code was inspired by https://github.com/makerdao/rwa-toolkit/blob/master/src/urns/RwaUrn.sol mainly authored by livnev. +Part of this code was inspired by https://github.com/makerdao/rwa-toolkit/blob/master/src/urns/RwaUrn.sol mainly authored by livnev and https://github.com/dapphub/ds-roles/blob/master/src/roles.sol authored by DappHub. Since it should belong to the MakerDAO community the Copyright from our additions has been transferred to Dai Foundation. diff --git a/src/AllocatorRoles.sol b/src/AllocatorRoles.sol new file mode 100644 index 00000000..20220517 --- /dev/null +++ b/src/AllocatorRoles.sol @@ -0,0 +1,105 @@ +// SPDX-FileCopyrightText: © 2017 DappHub, LLC +// SPDX-FileCopyrightText: © 2023 Dai Foundation +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +pragma solidity ^0.8.16; + +contract AllocatorRoles +{ + // --- storage variables --- + + mapping(address => uint256) public wards; + mapping(address => bytes32) public userRoles; + mapping(address => mapping(bytes4 => bytes32)) public actionsRoles; + mapping(address => mapping(bytes4 => uint256)) public publicActions; + + // --- events --- + + event Rely(address indexed usr); + event Deny(address indexed usr); + event SetUserRole(address indexed who, uint8 indexed role, bool enabled); + event SetPublicAction(address indexed target, bytes4 indexed sig, bool enabled); + event SetRoleAction(uint8 indexed role, address indexed target, bytes4 indexed sig, bool enabled); + + // --- modifiers --- + + modifier auth() { + require(wards[msg.sender] == 1, "AllocatorRoles/not-authorized"); + _; + } + + // --- constructor --- + + constructor() { + wards[msg.sender] = 1; + emit Rely(msg.sender); + } + + // --- getters --- + + function hasUserRole(address who, uint8 role) external view returns (bool) { + return bytes32(0) != userRoles[who] & bytes32(2 ** uint256(role)); + } + + // --- internals --- + + function _bitNot(bytes32 input) internal pure returns (bytes32 output) { + output = (input ^ bytes32(type(uint256).max)); + } + + // --- administration --- + + function rely(address usr) external auth { + wards[usr] = 1; + emit Rely(usr); + } + + function deny(address usr) external auth { + wards[usr] = 0; + emit Deny(usr); + } + + function setUserRole(address who, uint8 role, bool enabled) public auth { + bytes32 mask = bytes32(2 ** uint256(role)); + if (enabled) { + userRoles[who] |= mask; + } else { + userRoles[who] &= _bitNot(mask); + } + emit SetUserRole(who, role, enabled); + } + + function setPublicAction(address target, bytes4 sig, bool enabled) external auth { + publicActions[target][sig] = enabled ? 1 : 0; + emit SetPublicAction(target, sig, enabled); + } + + function setRoleAction(uint8 role, address target, bytes4 sig, bool enabled) external auth { + bytes32 mask = bytes32(2 ** uint256(role)); + if (enabled) { + actionsRoles[target][sig] |= mask; + } else { + actionsRoles[target][sig] &= _bitNot(mask); + } + emit SetRoleAction(role, target, sig, enabled); + } + + // --- caller --- + + function canCall(address caller, address target, bytes4 sig) external view returns (bool ok) { + ok = userRoles[caller] & actionsRoles[target][sig] != bytes32(0) || publicActions[target][sig] == 1; + } +} diff --git a/src/AllocatorVault.sol b/src/AllocatorVault.sol index bfff0863..4d73585f 100644 --- a/src/AllocatorVault.sol +++ b/src/AllocatorVault.sol @@ -54,6 +54,7 @@ contract AllocatorVault { // --- storage variables --- mapping(address => uint256) public wards; + address public roles; JugLike public jug; // --- constants --- @@ -82,7 +83,20 @@ contract AllocatorVault { // --- modifiers --- modifier auth() { - require(wards[msg.sender] == 1, "AllocatorVault/not-authorized"); + address roles_ = roles; + bool access; + if (roles_ != address(0)) { + (bool ok, bytes memory ret) = roles_.call( + abi.encodeWithSignature( + "canCall(address,address,bytes4)", + msg.sender, + address(this), + msg.sig + ) + ); + access = ok && ret.length == 32 && abi.decode(ret, (bool)); + } + require(access || wards[msg.sender] == 1, "AllocatorVault/not-authorized"); _; } @@ -159,7 +173,9 @@ contract AllocatorVault { } function file(bytes32 what, address data) external auth { - if (what == "jug") { + if (what == "roles") { + roles = data; + } else if (what == "jug") { jug = JugLike(data); } else revert("AllocatorVault/file-unrecognized-param"); emit File(what, data); diff --git a/test/AllocatorRoles.t.sol b/test/AllocatorRoles.t.sol new file mode 100644 index 00000000..a61f1493 --- /dev/null +++ b/test/AllocatorRoles.t.sol @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.8.16; + +import "dss-test/DssTest.sol"; +import "../src/AllocatorRoles.sol"; +import { AuthedMock } from "./mocks/AuthedMock.sol"; + +contract AllocatorRolesTest is DssTest { + AllocatorRoles roles; + AuthedMock authed; + + function setUp() public { + roles = new AllocatorRoles(); + authed = new AuthedMock(address(roles)); + } + + function testAuth() public { + checkAuth(address(roles), "AllocatorRoles"); + } + + function testModifiers() public { + bytes4[] memory authedMethods = new bytes4[](3); + authedMethods[0] = roles.setUserRole.selector; + authedMethods[1] = roles.setPublicAction.selector; + authedMethods[2] = roles.setRoleAction.selector; + + vm.startPrank(address(0xBEEF)); + checkModifier(address(roles), "AllocatorRoles/not-authorized", authedMethods); + vm.stopPrank(); + } + + function testBasics() public { + uint8 admin_role = 0; + uint8 mod_role = 1; + uint8 user_role = 2; + uint8 max_role = 255; + + assertTrue(!roles.hasUserRole(address(this), admin_role)); + assertTrue(!roles.hasUserRole(address(this), mod_role)); + assertTrue(!roles.hasUserRole(address(this), user_role)); + assertTrue(!roles.hasUserRole(address(this), max_role)); + assertEq32(bytes32(hex"0000000000000000000000000000000000000000000000000000000000000000"), roles.userRoles(address(this))); + + roles.setUserRole(address(this), admin_role, true); + + assertTrue( roles.hasUserRole(address(this), admin_role)); + assertTrue(!roles.hasUserRole(address(this), mod_role)); + assertTrue(!roles.hasUserRole(address(this), user_role)); + assertTrue(!roles.hasUserRole(address(this), max_role)); + assertEq32(bytes32(hex"0000000000000000000000000000000000000000000000000000000000000001"), roles.userRoles(address(this))); + + assertTrue(!roles.canCall(address(this), address(authed), bytes4(keccak256("exec()")))); + vm.expectRevert("AuthedMock/not-authorized"); + authed.exec(); + + roles.setRoleAction(admin_role, address(authed), bytes4(keccak256("exec()")), true); + + assertTrue(roles.canCall(address(this), address(authed), bytes4(keccak256("exec()")))); + authed.exec(); + assertTrue(authed.flag()); + + roles.setRoleAction(admin_role, address(authed), bytes4(keccak256("exec()")), false); + assertTrue(!roles.canCall(address(this), address(authed), bytes4(keccak256("exec()")))); + vm.expectRevert("AuthedMock/not-authorized"); + authed.exec(); + + roles.setUserRole(address(this), mod_role, true); + + assertTrue( roles.hasUserRole(address(this), admin_role)); + assertTrue( roles.hasUserRole(address(this), mod_role)); + assertTrue(!roles.hasUserRole(address(this), user_role)); + assertTrue(!roles.hasUserRole(address(this), max_role)); + assertEq32(bytes32(hex"0000000000000000000000000000000000000000000000000000000000000003"), roles.userRoles(address(this))); + + roles.setUserRole(address(this), user_role, true); + + assertTrue( roles.hasUserRole(address(this), admin_role)); + assertTrue( roles.hasUserRole(address(this), mod_role)); + assertTrue( roles.hasUserRole(address(this), user_role)); + assertTrue(!roles.hasUserRole(address(this), max_role)); + assertEq32(bytes32(hex"0000000000000000000000000000000000000000000000000000000000000007"), roles.userRoles(address(this))); + + roles.setUserRole(address(this), mod_role, false); + + assertTrue( roles.hasUserRole(address(this), admin_role)); + assertTrue(!roles.hasUserRole(address(this), mod_role)); + assertTrue( roles.hasUserRole(address(this), user_role)); + assertTrue(!roles.hasUserRole(address(this), max_role)); + assertEq32(bytes32(hex"0000000000000000000000000000000000000000000000000000000000000005"), roles.userRoles(address(this))); + + roles.setUserRole(address(this), max_role, true); + + assertTrue( roles.hasUserRole(address(this), admin_role)); + assertTrue(!roles.hasUserRole(address(this), mod_role)); + assertTrue( roles.hasUserRole(address(this), user_role)); + assertTrue( roles.hasUserRole(address(this), max_role)); + assertEq32(bytes32(hex"8000000000000000000000000000000000000000000000000000000000000005"), roles.userRoles(address(this))); + + roles.setRoleAction(max_role, address(authed), bytes4(keccak256("exec()")), true); + assertTrue(roles.canCall(address(this), address(authed), bytes4(keccak256("exec()")))); + authed.exec(); + } + + function testPublicActions() public { + assertEq(roles.publicActions(address(authed), bytes4(keccak256("exec()"))), 0); + assertTrue(!roles.canCall(address(this), address(authed), bytes4(keccak256("exec()")))); + vm.expectRevert("AuthedMock/not-authorized"); + authed.exec(); + + roles.setPublicAction(address(authed), bytes4(keccak256("exec()")), true); + assertEq(roles.publicActions(address(authed), bytes4(keccak256("exec()"))), 1); + assertTrue(roles.canCall(address(this), address(authed), bytes4(keccak256("exec()")))); + authed.exec(); + + roles.setPublicAction(address(authed), bytes4(keccak256("exec()")), false); + assertEq(roles.publicActions(address(authed), bytes4(keccak256("exec()"))), 0); + assertTrue(!roles.canCall(address(this), address(authed), bytes4(keccak256("exec()")))); + vm.expectRevert("AuthedMock/not-authorized"); + authed.exec(); + } +} diff --git a/test/AllocatorVault.t.sol b/test/AllocatorVault.t.sol index c1d7c209..10e1baaf 100644 --- a/test/AllocatorVault.t.sol +++ b/test/AllocatorVault.t.sol @@ -5,6 +5,7 @@ pragma solidity ^0.8.16; import "dss-test/DssTest.sol"; import { AllocatorVault } from "../src/AllocatorVault.sol"; import { AllocatorBuffer } from "../src/AllocatorBuffer.sol"; +import { RolesMock } from "./mocks/RolesMock.sol"; import { VatMock } from "./mocks/VatMock.sol"; import { JugMock } from "./mocks/JugMock.sol"; import { GemMock } from "./mocks/GemMock.sol"; @@ -65,7 +66,17 @@ contract AllocatorVaultTest is DssTest { } function testFile() public { - checkFileAddress(address(vault), "AllocatorVault", ["jug"]); + checkFileAddress(address(vault), "AllocatorVault", ["roles", "jug"]); + } + + function testRoles() public { + RolesMock roles = new RolesMock(); + vault.file("roles", address(roles)); + vm.startPrank(address(0xBEEF)); + vm.expectRevert("AllocatorVault/not-authorized"); + vault.file("jug", address(0)); + roles.setOk(true); + vault.file("jug", address(0)); } function testInit() public { diff --git a/test/mocks/AuthedMock.sol b/test/mocks/AuthedMock.sol new file mode 100644 index 00000000..c4fa2426 --- /dev/null +++ b/test/mocks/AuthedMock.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.8.16; + +contract AuthedMock { + address public roles; + bool public flag; + + constructor(address roles_) { + roles = roles_; + } + + modifier auth() { + address roles_ = roles; + bool access; + if (roles_ != address(0)) { + (bool ok, bytes memory ret) = roles_.call( + abi.encodeWithSignature( + "canCall(address,address,bytes4)", + msg.sender, + address(this), + msg.sig + ) + ); + access = ok && ret.length == 32 && abi.decode(ret, (bool)); + } + require(access, "AuthedMock/not-authorized"); + _; + } + + function exec() public auth { + flag = true; + } +} diff --git a/test/mocks/RolesMock.sol b/test/mocks/RolesMock.sol new file mode 100644 index 00000000..98973fba --- /dev/null +++ b/test/mocks/RolesMock.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.8.16; + +contract RolesMock { + bool ok; + + function setOk(bool ok_) external { + ok = ok_; + } + + function canCall(address, address, bytes4) external view returns (bool) { + return ok; + } +} From 6a671bafaad0e4902e5d05fe782933fdfad5415e Mon Sep 17 00:00:00 2001 From: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> Date: Mon, 19 Jun 2023 14:26:01 -0300 Subject: [PATCH 18/74] Make Roles a Singleton + Add AllocatorConduit interface and example (#6) * Add AllocatorConduit example * feat: Add conduit interface (#5) * feat: add initial interface * feat: add natspec, finalize interface * fix: update title * Interface rename + allocator => domain --------- Co-authored-by: sunbreak * Add conduit interface and changes to conduit example (WIP) * fix: update natspec * More interface and example changes * Fix indentation * Simplest maxDeposit and maxWithdraw implementations * Fix spacing * Implement singleton roles and make it immutable where using it (#7) * Implement singleton roles and make it immutable where using it * Renaming * Split request funds portion into a separate, optional interface (#8) * split request funds portion into a separate, optional interface * Fix example to work with new version of interfaces --------- Co-authored-by: sunbreak * Remove FundsRequestable part * domain => ilk * Minor change in authed mock * Roles: admins to ilkAdmins --------- Co-authored-by: Lucas Manuel Co-authored-by: Sam MacPherson --- src/AllocatorConduitExample.sol | 95 ++++++++++++++++++++++ src/AllocatorRoles.sol | 47 ++++++----- src/AllocatorVault.sol | 30 +++---- src/interfaces/IAllocatorConduit.sol | 75 +++++++++++++++++ test/AllocatorRoles.t.sol | 116 ++++++++++++--------------- test/AllocatorVault.t.sol | 8 +- test/mocks/AuthedMock.sol | 28 +++---- test/mocks/RolesMock.sol | 2 +- 8 files changed, 275 insertions(+), 126 deletions(-) create mode 100644 src/AllocatorConduitExample.sol create mode 100644 src/interfaces/IAllocatorConduit.sol diff --git a/src/AllocatorConduitExample.sol b/src/AllocatorConduitExample.sol new file mode 100644 index 00000000..5a67b075 --- /dev/null +++ b/src/AllocatorConduitExample.sol @@ -0,0 +1,95 @@ +// SPDX-FileCopyrightText: © 2023 Dai Foundation +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +pragma solidity ^0.8.16; + +import "./interfaces/IAllocatorConduit.sol"; + +interface RolesLike { + function canCall(bytes32, address, address, bytes4) external view returns (bool); +} + +contract AllocatorConduitExample is IAllocatorConduit { + // --- storage variables --- + + mapping(address => uint256) public wards; + mapping(bytes32 => mapping(address => uint256)) public positions; + + // --- immutables --- + + RolesLike public immutable roles; + + // --- events --- + + event Rely(address indexed usr); + event Deny(address indexed usr); + event SetRoles(bytes32 indexed ilk, address roles_); + + // --- modifiers --- + + modifier auth() { + require(wards[msg.sender] == 1, "AllocatorBuffer/not-authorized"); + _; + } + + modifier ilkAuth(bytes32 ilk) { + require(roles.canCall(ilk, msg.sender, address(this), msg.sig), "AllocatorConduitExample/ilk-not-authorized"); + _; + } + + // --- constructor --- + + constructor(address roles_) { + roles = RolesLike(roles_); + } + + // --- getters --- + + function maxDeposit(bytes32 ilk, address asset) external pure returns (uint256 maxDeposit_) { + ilk;asset; + maxDeposit_ = type(uint256).max; + } + + function maxWithdraw(bytes32 ilk, address asset) external view returns (uint256 maxWithdraw_) { + maxWithdraw_ = positions[ilk][asset]; + } + + // --- admininstration --- + + function rely(address usr) external auth { + wards[usr] = 1; + emit Rely(usr); + } + + function deny(address usr) external auth { + wards[usr] = 0; + emit Deny(usr); + } + + // --- functions --- + + function deposit(bytes32 ilk, address asset, uint256 amount) external ilkAuth(ilk) { + positions[ilk][asset] += amount; + // Implement the logic to deposit funds into the FundManager + emit Deposit(ilk, asset, amount); + } + + function withdraw(bytes32 ilk, address asset, address destination, uint256 amount) external ilkAuth(ilk) { + positions[ilk][asset] -= amount; + // Implement the logic to withdraw funds from the FundManager + emit Withdraw(ilk, asset, destination, amount); + } +} diff --git a/src/AllocatorRoles.sol b/src/AllocatorRoles.sol index 20220517..9a46b2f8 100644 --- a/src/AllocatorRoles.sol +++ b/src/AllocatorRoles.sol @@ -22,16 +22,16 @@ contract AllocatorRoles // --- storage variables --- mapping(address => uint256) public wards; - mapping(address => bytes32) public userRoles; - mapping(address => mapping(bytes4 => bytes32)) public actionsRoles; - mapping(address => mapping(bytes4 => uint256)) public publicActions; + mapping(bytes32 => address) public ilkAdmins; + mapping(bytes32 => mapping(address => bytes32)) public userRoles; + mapping(bytes32 => mapping(address => mapping(bytes4 => bytes32))) public actionsRoles; // --- events --- event Rely(address indexed usr); event Deny(address indexed usr); + event SetIlkAdmin(bytes32 indexed ilk, address user); event SetUserRole(address indexed who, uint8 indexed role, bool enabled); - event SetPublicAction(address indexed target, bytes4 indexed sig, bool enabled); event SetRoleAction(uint8 indexed role, address indexed target, bytes4 indexed sig, bool enabled); // --- modifiers --- @@ -41,6 +41,11 @@ contract AllocatorRoles _; } + modifier ilkAuth(bytes32 ilk) { + require(ilkAdmins[ilk] == msg.sender, "AllocatorRoles/ilk-not-authorized"); + _; + } + // --- constructor --- constructor() { @@ -50,8 +55,8 @@ contract AllocatorRoles // --- getters --- - function hasUserRole(address who, uint8 role) external view returns (bool) { - return bytes32(0) != userRoles[who] & bytes32(2 ** uint256(role)); + function hasUserRole(bytes32 ilk, address who, uint8 role) external view returns (bool) { + return bytes32(0) != userRoles[ilk][who] & bytes32(2 ** uint256(role)); } // --- internals --- @@ -60,7 +65,7 @@ contract AllocatorRoles output = (input ^ bytes32(type(uint256).max)); } - // --- administration --- + // --- general administration --- function rely(address usr) external auth { wards[usr] = 1; @@ -72,34 +77,36 @@ contract AllocatorRoles emit Deny(usr); } - function setUserRole(address who, uint8 role, bool enabled) public auth { + function setIlkAdmin(bytes32 ilk, address user) external auth { + ilkAdmins[ilk] = user; + emit SetIlkAdmin(ilk, user); + } + + // --- ilk administration --- + + function setUserRole(bytes32 ilk, address who, uint8 role, bool enabled) public ilkAuth(ilk) { bytes32 mask = bytes32(2 ** uint256(role)); if (enabled) { - userRoles[who] |= mask; + userRoles[ilk][who] |= mask; } else { - userRoles[who] &= _bitNot(mask); + userRoles[ilk][who] &= _bitNot(mask); } emit SetUserRole(who, role, enabled); } - function setPublicAction(address target, bytes4 sig, bool enabled) external auth { - publicActions[target][sig] = enabled ? 1 : 0; - emit SetPublicAction(target, sig, enabled); - } - - function setRoleAction(uint8 role, address target, bytes4 sig, bool enabled) external auth { + function setRoleAction(bytes32 ilk, uint8 role, address target, bytes4 sig, bool enabled) external ilkAuth(ilk) { bytes32 mask = bytes32(2 ** uint256(role)); if (enabled) { - actionsRoles[target][sig] |= mask; + actionsRoles[ilk][target][sig] |= mask; } else { - actionsRoles[target][sig] &= _bitNot(mask); + actionsRoles[ilk][target][sig] &= _bitNot(mask); } emit SetRoleAction(role, target, sig, enabled); } // --- caller --- - function canCall(address caller, address target, bytes4 sig) external view returns (bool ok) { - ok = userRoles[caller] & actionsRoles[target][sig] != bytes32(0) || publicActions[target][sig] == 1; + function canCall(bytes32 ilk, address caller, address target, bytes4 sig) external view returns (bool ok) { + ok = userRoles[ilk][caller] & actionsRoles[ilk][target][sig] != bytes32(0); } } diff --git a/src/AllocatorVault.sol b/src/AllocatorVault.sol index 4d73585f..033e3bcb 100644 --- a/src/AllocatorVault.sol +++ b/src/AllocatorVault.sol @@ -17,6 +17,10 @@ pragma solidity ^0.8.16; +interface RolesLike { + function canCall(bytes32, address, address, bytes4) external view returns (bool); +} + interface VatLike { function ilks(bytes32) external view returns (uint256, uint256, uint256, uint256, uint256); function live() external view returns (uint256); @@ -54,7 +58,6 @@ contract AllocatorVault { // --- storage variables --- mapping(address => uint256) public wards; - address public roles; JugLike public jug; // --- constants --- @@ -64,6 +67,7 @@ contract AllocatorVault { // --- immutables --- + RolesLike immutable public roles; address immutable public buffer; VatLike immutable public vat; bytes32 immutable public ilk; @@ -83,26 +87,16 @@ contract AllocatorVault { // --- modifiers --- modifier auth() { - address roles_ = roles; - bool access; - if (roles_ != address(0)) { - (bool ok, bytes memory ret) = roles_.call( - abi.encodeWithSignature( - "canCall(address,address,bytes4)", - msg.sender, - address(this), - msg.sig - ) - ); - access = ok && ret.length == 32 && abi.decode(ret, (bool)); - } - require(access || wards[msg.sender] == 1, "AllocatorVault/not-authorized"); + require(roles.canCall(ilk, msg.sender, address(this), msg.sig) || + wards[msg.sender] == 1, "AllocatorVault/not-authorized"); _; } // --- constructor --- - constructor(address buffer_, address vat_, address gemJoin_, address nstJoin_) { + constructor(address roles_, address buffer_, address vat_, address gemJoin_, address nstJoin_) { + roles = RolesLike(roles_); + buffer = buffer_; vat = VatLike(vat_); @@ -173,9 +167,7 @@ contract AllocatorVault { } function file(bytes32 what, address data) external auth { - if (what == "roles") { - roles = data; - } else if (what == "jug") { + if (what == "jug") { jug = JugLike(data); } else revert("AllocatorVault/file-unrecognized-param"); emit File(what, data); diff --git a/src/interfaces/IAllocatorConduit.sol b/src/interfaces/IAllocatorConduit.sol new file mode 100644 index 00000000..2c585e7e --- /dev/null +++ b/src/interfaces/IAllocatorConduit.sol @@ -0,0 +1,75 @@ +// SPDX-FileCopyrightText: © 2023 Dai Foundation +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +pragma solidity >=0.8.0; + +/** + * @title IAllocatorConduit + * @dev Conduits are to be used to manage investment positions for multiple Allocators. + */ +interface IAllocatorConduit { + + /** + * @dev Event emitted when a deposit is made to the Conduit. + * @param ilk The unique identifier of the ilk. + * @param asset The address of the asset deposited. + * @param amount The amount of asset deposited. + */ + event Deposit(bytes32 indexed ilk, address indexed asset, uint256 amount); + + /** + * @dev Event emitted when a withdrawal is made from the Conduit. + * @param ilk The unique identifier of the ilk. + * @param asset The address of the asset withdrawn. + * @param destination The address where the asset is sent. + * @param amount The amount of asset withdrawn. + */ + event Withdraw(bytes32 indexed ilk, address indexed asset, address destination, uint256 amount); + + /** + * @dev Function for depositing tokens into a Fund Manager. + * @param ilk The unique identifier of the ilk. + * @param asset The asset to deposit. + * @param amount The amount of tokens to deposit. + */ + function deposit(bytes32 ilk, address asset, uint256 amount) external; + + /** + * @dev Function for withdrawing tokens from a Fund Manager. + * @param ilk The unique identifier of the ilk. + * @param asset The asset to withdraw. + * @param destination The address to send the withdrawn tokens to. + * @param amount The amount of tokens to withdraw. + */ + function withdraw(bytes32 ilk, address asset, address destination, uint256 amount) external; + + /** + * @dev Function to get the maximum deposit possible for a specific asset and ilk. + * @param ilk The unique identifier of the ilk. + * @param asset The asset to check. + * @return maxDeposit_ The maximum possible deposit for the asset. + */ + function maxDeposit(bytes32 ilk, address asset) external view returns (uint256 maxDeposit_); + + /** + * @dev Function to get the maximum withdrawal possible for a specific asset and ilk. + * @param ilk The unique identifier of the ilk. + * @param asset The asset to check. + * @return maxWithdraw_ The maximum possible withdrawal for the asset. + */ + function maxWithdraw(bytes32 ilk, address asset) external view returns (uint256 maxWithdraw_); + +} diff --git a/test/AllocatorRoles.t.sol b/test/AllocatorRoles.t.sol index a61f1493..8eb1e9f0 100644 --- a/test/AllocatorRoles.t.sol +++ b/test/AllocatorRoles.t.sol @@ -9,10 +9,12 @@ import { AuthedMock } from "./mocks/AuthedMock.sol"; contract AllocatorRolesTest is DssTest { AllocatorRoles roles; AuthedMock authed; + bytes32 ilk; function setUp() public { + ilk = "aaa"; roles = new AllocatorRoles(); - authed = new AuthedMock(address(roles)); + authed = new AuthedMock(address(roles), ilk); } function testAuth() public { @@ -20,10 +22,8 @@ contract AllocatorRolesTest is DssTest { } function testModifiers() public { - bytes4[] memory authedMethods = new bytes4[](3); - authedMethods[0] = roles.setUserRole.selector; - authedMethods[1] = roles.setPublicAction.selector; - authedMethods[2] = roles.setRoleAction.selector; + bytes4[] memory authedMethods = new bytes4[](1); + authedMethods[0] = roles.setIlkAdmin.selector; vm.startPrank(address(0xBEEF)); checkModifier(address(roles), "AllocatorRoles/not-authorized", authedMethods); @@ -36,87 +36,73 @@ contract AllocatorRolesTest is DssTest { uint8 user_role = 2; uint8 max_role = 255; - assertTrue(!roles.hasUserRole(address(this), admin_role)); - assertTrue(!roles.hasUserRole(address(this), mod_role)); - assertTrue(!roles.hasUserRole(address(this), user_role)); - assertTrue(!roles.hasUserRole(address(this), max_role)); - assertEq32(bytes32(hex"0000000000000000000000000000000000000000000000000000000000000000"), roles.userRoles(address(this))); + assertTrue(!roles.hasUserRole(ilk, address(this), admin_role)); + assertTrue(!roles.hasUserRole(ilk, address(this), mod_role)); + assertTrue(!roles.hasUserRole(ilk, address(this), user_role)); + assertTrue(!roles.hasUserRole(ilk, address(this), max_role)); + assertEq32(bytes32(hex"0000000000000000000000000000000000000000000000000000000000000000"), roles.userRoles(ilk, address(this))); - roles.setUserRole(address(this), admin_role, true); + vm.expectRevert("AllocatorRoles/ilk-not-authorized"); + roles.setUserRole(ilk, address(this), admin_role, true); - assertTrue( roles.hasUserRole(address(this), admin_role)); - assertTrue(!roles.hasUserRole(address(this), mod_role)); - assertTrue(!roles.hasUserRole(address(this), user_role)); - assertTrue(!roles.hasUserRole(address(this), max_role)); - assertEq32(bytes32(hex"0000000000000000000000000000000000000000000000000000000000000001"), roles.userRoles(address(this))); + roles.setIlkAdmin(ilk, address(this)); + roles.setUserRole(ilk, address(this), admin_role, true); - assertTrue(!roles.canCall(address(this), address(authed), bytes4(keccak256("exec()")))); + assertTrue( roles.hasUserRole(ilk, address(this), admin_role)); + assertTrue(!roles.hasUserRole(ilk, address(this), mod_role)); + assertTrue(!roles.hasUserRole(ilk, address(this), user_role)); + assertTrue(!roles.hasUserRole(ilk, address(this), max_role)); + assertEq32(bytes32(hex"0000000000000000000000000000000000000000000000000000000000000001"), roles.userRoles(ilk, address(this))); + + assertTrue(!roles.canCall(ilk, address(this), address(authed), bytes4(keccak256("exec()")))); vm.expectRevert("AuthedMock/not-authorized"); authed.exec(); - roles.setRoleAction(admin_role, address(authed), bytes4(keccak256("exec()")), true); + roles.setRoleAction(ilk, admin_role, address(authed), bytes4(keccak256("exec()")), true); - assertTrue(roles.canCall(address(this), address(authed), bytes4(keccak256("exec()")))); + assertTrue(roles.canCall(ilk, address(this), address(authed), bytes4(keccak256("exec()")))); authed.exec(); assertTrue(authed.flag()); - roles.setRoleAction(admin_role, address(authed), bytes4(keccak256("exec()")), false); - assertTrue(!roles.canCall(address(this), address(authed), bytes4(keccak256("exec()")))); + roles.setRoleAction(ilk, admin_role, address(authed), bytes4(keccak256("exec()")), false); + assertTrue(!roles.canCall(ilk, address(this), address(authed), bytes4(keccak256("exec()")))); vm.expectRevert("AuthedMock/not-authorized"); authed.exec(); - roles.setUserRole(address(this), mod_role, true); - - assertTrue( roles.hasUserRole(address(this), admin_role)); - assertTrue( roles.hasUserRole(address(this), mod_role)); - assertTrue(!roles.hasUserRole(address(this), user_role)); - assertTrue(!roles.hasUserRole(address(this), max_role)); - assertEq32(bytes32(hex"0000000000000000000000000000000000000000000000000000000000000003"), roles.userRoles(address(this))); - - roles.setUserRole(address(this), user_role, true); + roles.setUserRole(ilk, address(this), mod_role, true); - assertTrue( roles.hasUserRole(address(this), admin_role)); - assertTrue( roles.hasUserRole(address(this), mod_role)); - assertTrue( roles.hasUserRole(address(this), user_role)); - assertTrue(!roles.hasUserRole(address(this), max_role)); - assertEq32(bytes32(hex"0000000000000000000000000000000000000000000000000000000000000007"), roles.userRoles(address(this))); + assertTrue( roles.hasUserRole(ilk, address(this), admin_role)); + assertTrue( roles.hasUserRole(ilk, address(this), mod_role)); + assertTrue(!roles.hasUserRole(ilk, address(this), user_role)); + assertTrue(!roles.hasUserRole(ilk, address(this), max_role)); + assertEq32(bytes32(hex"0000000000000000000000000000000000000000000000000000000000000003"), roles.userRoles(ilk, address(this))); - roles.setUserRole(address(this), mod_role, false); + roles.setUserRole(ilk, address(this), user_role, true); - assertTrue( roles.hasUserRole(address(this), admin_role)); - assertTrue(!roles.hasUserRole(address(this), mod_role)); - assertTrue( roles.hasUserRole(address(this), user_role)); - assertTrue(!roles.hasUserRole(address(this), max_role)); - assertEq32(bytes32(hex"0000000000000000000000000000000000000000000000000000000000000005"), roles.userRoles(address(this))); + assertTrue( roles.hasUserRole(ilk, address(this), admin_role)); + assertTrue( roles.hasUserRole(ilk, address(this), mod_role)); + assertTrue( roles.hasUserRole(ilk, address(this), user_role)); + assertTrue(!roles.hasUserRole(ilk, address(this), max_role)); + assertEq32(bytes32(hex"0000000000000000000000000000000000000000000000000000000000000007"), roles.userRoles(ilk, address(this))); - roles.setUserRole(address(this), max_role, true); + roles.setUserRole(ilk, address(this), mod_role, false); - assertTrue( roles.hasUserRole(address(this), admin_role)); - assertTrue(!roles.hasUserRole(address(this), mod_role)); - assertTrue( roles.hasUserRole(address(this), user_role)); - assertTrue( roles.hasUserRole(address(this), max_role)); - assertEq32(bytes32(hex"8000000000000000000000000000000000000000000000000000000000000005"), roles.userRoles(address(this))); - - roles.setRoleAction(max_role, address(authed), bytes4(keccak256("exec()")), true); - assertTrue(roles.canCall(address(this), address(authed), bytes4(keccak256("exec()")))); - authed.exec(); - } + assertTrue( roles.hasUserRole(ilk, address(this), admin_role)); + assertTrue(!roles.hasUserRole(ilk, address(this), mod_role)); + assertTrue( roles.hasUserRole(ilk, address(this), user_role)); + assertTrue(!roles.hasUserRole(ilk, address(this), max_role)); + assertEq32(bytes32(hex"0000000000000000000000000000000000000000000000000000000000000005"), roles.userRoles(ilk, address(this))); - function testPublicActions() public { - assertEq(roles.publicActions(address(authed), bytes4(keccak256("exec()"))), 0); - assertTrue(!roles.canCall(address(this), address(authed), bytes4(keccak256("exec()")))); - vm.expectRevert("AuthedMock/not-authorized"); - authed.exec(); + roles.setUserRole(ilk, address(this), max_role, true); - roles.setPublicAction(address(authed), bytes4(keccak256("exec()")), true); - assertEq(roles.publicActions(address(authed), bytes4(keccak256("exec()"))), 1); - assertTrue(roles.canCall(address(this), address(authed), bytes4(keccak256("exec()")))); - authed.exec(); + assertTrue( roles.hasUserRole(ilk, address(this), admin_role)); + assertTrue(!roles.hasUserRole(ilk, address(this), mod_role)); + assertTrue( roles.hasUserRole(ilk, address(this), user_role)); + assertTrue( roles.hasUserRole(ilk, address(this), max_role)); + assertEq32(bytes32(hex"8000000000000000000000000000000000000000000000000000000000000005"), roles.userRoles(ilk, address(this))); - roles.setPublicAction(address(authed), bytes4(keccak256("exec()")), false); - assertEq(roles.publicActions(address(authed), bytes4(keccak256("exec()"))), 0); - assertTrue(!roles.canCall(address(this), address(authed), bytes4(keccak256("exec()")))); - vm.expectRevert("AuthedMock/not-authorized"); + roles.setRoleAction(ilk, max_role, address(authed), bytes4(keccak256("exec()")), true); + assertTrue(roles.canCall(ilk, address(this), address(authed), bytes4(keccak256("exec()")))); authed.exec(); } } diff --git a/test/AllocatorVault.t.sol b/test/AllocatorVault.t.sol index 10e1baaf..457b2cfd 100644 --- a/test/AllocatorVault.t.sol +++ b/test/AllocatorVault.t.sol @@ -22,6 +22,7 @@ contract AllocatorVaultTest is DssTest { GemMock public nst; NstJoinMock public nstJoin; AllocatorBuffer public buffer; + RolesMock public roles; AllocatorVault public vault; bytes32 public ilk; @@ -40,7 +41,8 @@ contract AllocatorVaultTest is DssTest { nst = new GemMock(0); nstJoin = new NstJoinMock(vat, nst); buffer = new AllocatorBuffer(); - vault = new AllocatorVault(address(buffer), address(vat), address(gemJoin), address(nstJoin)); + roles = new RolesMock(); + vault = new AllocatorVault(address(roles), address(buffer), address(vat), address(gemJoin), address(nstJoin)); buffer.approve(address(nst), address(vault), type(uint256).max); gem.transfer(address(vault), 1_000_000 * 10**18); @@ -66,12 +68,10 @@ contract AllocatorVaultTest is DssTest { } function testFile() public { - checkFileAddress(address(vault), "AllocatorVault", ["roles", "jug"]); + checkFileAddress(address(vault), "AllocatorVault", ["jug"]); } function testRoles() public { - RolesMock roles = new RolesMock(); - vault.file("roles", address(roles)); vm.startPrank(address(0xBEEF)); vm.expectRevert("AllocatorVault/not-authorized"); vault.file("jug", address(0)); diff --git a/test/mocks/AuthedMock.sol b/test/mocks/AuthedMock.sol index c4fa2426..52fec157 100644 --- a/test/mocks/AuthedMock.sol +++ b/test/mocks/AuthedMock.sol @@ -2,29 +2,23 @@ pragma solidity ^0.8.16; +interface RolesLike { + function canCall(bytes32, address, address, bytes4) external view returns (bool); +} + contract AuthedMock { - address public roles; bool public flag; - constructor(address roles_) { - roles = roles_; + RolesLike public immutable roles; + bytes32 public immutable ilk; + + constructor(address roles_, bytes32 ilk_) { + roles = RolesLike(roles_); + ilk = ilk_; } modifier auth() { - address roles_ = roles; - bool access; - if (roles_ != address(0)) { - (bool ok, bytes memory ret) = roles_.call( - abi.encodeWithSignature( - "canCall(address,address,bytes4)", - msg.sender, - address(this), - msg.sig - ) - ); - access = ok && ret.length == 32 && abi.decode(ret, (bool)); - } - require(access, "AuthedMock/not-authorized"); + require(roles.canCall(ilk, msg.sender, address(this), msg.sig), "AuthedMock/not-authorized"); _; } diff --git a/test/mocks/RolesMock.sol b/test/mocks/RolesMock.sol index 98973fba..ccd43d10 100644 --- a/test/mocks/RolesMock.sol +++ b/test/mocks/RolesMock.sol @@ -9,7 +9,7 @@ contract RolesMock { ok = ok_; } - function canCall(address, address, bytes4) external view returns (bool) { + function canCall(bytes32, address, address, bytes4) external view returns (bool) { return ok; } } From febaad615869962dd4b6ae5d3cc770442eb97949 Mon Sep 17 00:00:00 2001 From: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> Date: Tue, 20 Jun 2023 13:14:42 -0300 Subject: [PATCH 19/74] Add Router + Modify Buffer (#9) * Add Router * Fix event * Clean ConduitMock * Update latest version WhitelistedRouter * Update files structure + Make test fully unit without RPC reliance * Add changes to Router and Buffer * Use also deposit in Router.move and remove last param of Buffer.deposit * Use IAllocatorConduit for AllocatorBuffer * Add immutable ilk in Buffer * Test Buffer getters --------- Co-authored-by: telome <> --- src/AllocatorBuffer.sol | 47 +++++++++++------ src/WhitelistedRouter.sol | 98 ++++++++++++++++++++++++++++++++++++ test/AllocatorBuffer.t.sol | 18 +++++-- test/AllocatorVault.t.sol | 2 +- test/WhitelistedRouter.t.sol | 83 ++++++++++++++++++++++++++++++ 5 files changed, 230 insertions(+), 18 deletions(-) create mode 100644 src/WhitelistedRouter.sol create mode 100644 test/WhitelistedRouter.t.sol diff --git a/src/AllocatorBuffer.sol b/src/AllocatorBuffer.sol index d517122a..97074a79 100644 --- a/src/AllocatorBuffer.sol +++ b/src/AllocatorBuffer.sol @@ -16,22 +16,28 @@ pragma solidity ^0.8.16; +import "./interfaces/IAllocatorConduit.sol"; + interface TokenLike { + function balanceOf(address) external view returns (uint256); function approve(address, uint256) external; + function transfer(address, uint256) external; function transferFrom(address, address, uint256) external; } -contract AllocatorBuffer { +contract AllocatorBuffer is IAllocatorConduit { // --- storage variables --- mapping(address => uint256) public wards; + // --- immutables --- + bytes32 immutable public ilk; + // --- events --- event Rely(address indexed usr); event Deny(address indexed usr); - event Approve(address indexed token, address indexed spender, uint256 amount); - event Deposit(address indexed token, address indexed sender, uint256 amount); + event Approve(address indexed asset, address indexed spender, uint256 amount); // --- modifiers --- @@ -42,11 +48,23 @@ contract AllocatorBuffer { // --- constructor --- - constructor() { + constructor(bytes32 ilk_) { + ilk = ilk_; + wards[msg.sender] = 1; emit Rely(msg.sender); } + // --- getters --- + + function maxDeposit(bytes32, address) external pure returns (uint256 maxDeposit_) { + maxDeposit_ = type(uint256).max; + } + + function maxWithdraw(bytes32, address asset) external view returns (uint256 maxWithdraw_) { + maxWithdraw_ = TokenLike(asset).balanceOf(address(this)); + } + // --- administration --- function rely(address usr) external auth { @@ -61,17 +79,18 @@ contract AllocatorBuffer { // --- functions --- - function approve( - address token, - address spender, - uint256 amount - ) external auth { - TokenLike(token).approve(spender, amount); - emit Approve(token, spender, amount); + function approve(address asset, address spender, uint256 amount) external auth { + TokenLike(asset).approve(spender, amount); + emit Approve(asset, spender, amount); + } + + function deposit(bytes32, address asset, uint256 amount) external { + TokenLike(asset).transferFrom(msg.sender, address(this), amount); + emit Deposit(ilk, asset, amount); } - function deposit(address token, uint256 amount, address /* owner */) external { - TokenLike(token).transferFrom(msg.sender, address(this), amount); - emit Deposit(token, msg.sender, amount); + function withdraw(bytes32, address asset, address destination, uint256 amount) external auth { + TokenLike(asset).transfer(destination, amount); + emit Withdraw(ilk, asset, destination, amount); } } diff --git a/src/WhitelistedRouter.sol b/src/WhitelistedRouter.sol new file mode 100644 index 00000000..05788e6e --- /dev/null +++ b/src/WhitelistedRouter.sol @@ -0,0 +1,98 @@ +// SPDX-FileCopyrightText: © 2020 Lev Livnev +// SPDX-FileCopyrightText: © 2021 Dai Foundation +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +pragma solidity ^0.8.16; + +interface RolesLike { + function canCall(bytes32, address, address, bytes4) external view returns (bool); +} + +interface BoxLike { + function deposit(bytes32, address, uint256) external; + function withdraw(bytes32, address, address, uint256) external; +} + +interface GemLike { + function approve(address, uint256) external; +} + +contract WhitelistedRouter { + + // --- storage variables --- + + mapping (address => uint256) public wards; // Auth + mapping (address => uint256) public boxes; // whitelisted boxes (e.g. RWA conduits, Escrow, SubDAO proxy) + + // --- immutables --- + + RolesLike immutable public roles; + bytes32 immutable public ilk; + + // --- events --- + + event Rely(address indexed usr); + event Deny(address indexed usr); + event File(bytes32 indexed what, address data, uint256 val); + event Move(address sender, address indexed asset, address indexed from, address to, uint256 amt); + + // --- modifiers --- + + modifier auth() { + require(roles.canCall(ilk, msg.sender, address(this), msg.sig) || + wards[msg.sender] == 1, "WhitelistedRouter/not-authorized"); + _; + } + + // --- constructor --- + + constructor(address roles_, bytes32 ilk_) { + roles = RolesLike(roles_); + ilk = ilk_; + + wards[msg.sender] = 1; + emit Rely(msg.sender); + } + + // --- administration --- + + function rely(address usr) external auth { + wards[usr] = 1; + emit Rely(usr); + } + + function deny(address usr) external auth { + wards[usr] = 0; + emit Deny(usr); + } + + function file(bytes32 what, address data, uint256 val) external auth { + if (what == "box") boxes[data] = val; + else revert("WhitelistedRouter/file-unrecognized-param"); + emit File(what, data, val); + } + + // --- move execution --- + + function move(address asset, address from, address to, uint256 amt) external auth { + require(boxes[from] == 1, "WhitelistedRouter/invalid-from"); + require(boxes[to] == 1, "WhitelistedRouter/invalid-to"); + BoxLike(from).withdraw(ilk, asset, address(this), amt); + GemLike(asset).approve(address(to), amt); + BoxLike(to).deposit(ilk, asset, amt); + emit Move(msg.sender, asset, from, to, amt); + } +} diff --git a/test/AllocatorBuffer.t.sol b/test/AllocatorBuffer.t.sol index c8135948..cc2baaae 100644 --- a/test/AllocatorBuffer.t.sol +++ b/test/AllocatorBuffer.t.sol @@ -9,12 +9,13 @@ import { GemMock } from "./mocks/GemMock.sol"; contract AllocatorBufferTest is DssTest { using stdStorage for StdStorage; + bytes32 public ilk = "aaa"; GemMock public gem; AllocatorBuffer public buffer; function setUp() public { gem = new GemMock(1_000_000 * 10**18); - buffer = new AllocatorBuffer(); + buffer = new AllocatorBuffer(ilk); } function testAuth() public { @@ -30,18 +31,29 @@ contract AllocatorBufferTest is DssTest { vm.stopPrank(); } + function testGetters() public { + assertEq(buffer.maxDeposit(bytes32(0), address(0)), type(uint256).max); + assertEq(buffer.maxWithdraw(bytes32(0), address(gem)), 0); + gem.approve(address(buffer), 10); + buffer.deposit(bytes32(0), address(gem), 10); + assertEq(buffer.maxWithdraw(bytes32(0), address(gem)), 10); + } + function testApprove() public { assertEq(gem.allowance(address(buffer), address(0xBEEF)), 0); buffer.approve(address(gem), address(0xBEEF), 10); assertEq(gem.allowance(address(buffer), address(0xBEEF)), 10); } - function testDeposit() public { + function testDepositWithdraw() public { assertEq(gem.balanceOf(address(this)), gem.totalSupply()); assertEq(gem.balanceOf(address(buffer)), 0); gem.approve(address(buffer), 10); - buffer.deposit(address(gem), 10, address(0)); + buffer.deposit(bytes32(0), address(gem), 10); assertEq(gem.balanceOf(address(this)), gem.totalSupply() - 10); assertEq(gem.balanceOf(address(buffer)), 10); + buffer.withdraw(bytes32(0), address(gem), address(123), 4); + assertEq(gem.balanceOf(address(buffer)), 6); + assertEq(gem.balanceOf(address(123)), 4); } } diff --git a/test/AllocatorVault.t.sol b/test/AllocatorVault.t.sol index 457b2cfd..62bfaaca 100644 --- a/test/AllocatorVault.t.sol +++ b/test/AllocatorVault.t.sol @@ -40,7 +40,7 @@ contract AllocatorVaultTest is DssTest { gemJoin = new GemJoinMock(vat, ilk, gem); nst = new GemMock(0); nstJoin = new NstJoinMock(vat, nst); - buffer = new AllocatorBuffer(); + buffer = new AllocatorBuffer(ilk); roles = new RolesMock(); vault = new AllocatorVault(address(roles), address(buffer), address(vat), address(gemJoin), address(nstJoin)); buffer.approve(address(nst), address(vault), type(uint256).max); diff --git a/test/WhitelistedRouter.t.sol b/test/WhitelistedRouter.t.sol new file mode 100644 index 00000000..d60b5a58 --- /dev/null +++ b/test/WhitelistedRouter.t.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.16; + +import "dss-test/DssTest.sol"; +import { WhitelistedRouter } from "src/WhitelistedRouter.sol"; +import { AllocatorBuffer } from "src/AllocatorBuffer.sol"; +import { GemMock } from "./mocks/GemMock.sol"; +import { RolesMock } from "./mocks/RolesMock.sol"; + +interface BalanceLike { + function balanceOf(address) external view returns (uint256); +} + +interface GemLikeLike { + function approve(address, uint256) external; + function transferFrom(address, address, uint256) external; +} + +contract WhitelistedRouterTest is DssTest { + bytes32 public ilk; + RolesMock public roles; + WhitelistedRouter public router; + address public box1; + address public box2; + address public USDC; + address public USDT; + + address constant FACILITATOR = address(0xb0b); + + function setUp() public { + ilk = "TEST-ILK"; + roles = new RolesMock(); + router = new WhitelistedRouter(address(roles), ilk); + box1 = address(new AllocatorBuffer(ilk)); + box2 = address(new AllocatorBuffer(ilk)); + USDC = address(new GemMock(0)); + USDT = address(new GemMock(0)); + AllocatorBuffer(box1).rely(address(router)); + AllocatorBuffer(box2).rely(address(router)); + router.file("box", box1, 1); + router.file("box", box2, 1); + } + + function _checkMove(bool ward, address gem, uint256 amt) internal { + if (ward) { + router.rely(FACILITATOR); + } else { + roles.setOk(true); + } + + deal(gem, box1, amt, true); + assertEq(BalanceLike(gem).balanceOf(box1), amt); + assertEq(BalanceLike(gem).balanceOf(box2), 0); + vm.startPrank(FACILITATOR); + + router.move(gem, box1, box2, amt); + + assertEq(BalanceLike(gem).balanceOf(box1), 0); + assertEq(BalanceLike(gem).balanceOf(box2), amt); + + router.move(gem, box2, box1, amt); + + assertEq(BalanceLike(gem).balanceOf(box1), amt); + assertEq(BalanceLike(gem).balanceOf(box2), 0); + vm.stopPrank(); + } + + function testMoveUSDCWard() public { + _checkMove(true, USDC, 1000 ether); + } + + function testMoveUSDCRoles() public { + _checkMove(false, USDC, 1000 ether); + } + + function testMoveUSDTWard() public { + _checkMove(true, USDT, 1000 ether); + } + + function testMoveUSDTRoles() public { + _checkMove(false, USDT, 1000 ether); + } +} From 94b35fb7295e121ce08ff66de68820abe429f425 Mon Sep 17 00:00:00 2001 From: sunbreak Date: Tue, 20 Jun 2023 14:31:14 -0300 Subject: [PATCH 20/74] Add missing events, fix others and add check in tests for all of them --- src/AllocatorRoles.sol | 8 ++++---- src/AllocatorVault.sol | 10 ++++++---- test/AllocatorBuffer.t.sol | 10 ++++++++++ test/AllocatorRoles.t.sol | 22 ++++++++++++++++++++++ test/AllocatorVault.t.sol | 24 +++++++++++++++++++++--- test/WhitelistedRouter.t.sol | 8 +++++++- 6 files changed, 70 insertions(+), 12 deletions(-) diff --git a/src/AllocatorRoles.sol b/src/AllocatorRoles.sol index 9a46b2f8..1f73c5fc 100644 --- a/src/AllocatorRoles.sol +++ b/src/AllocatorRoles.sol @@ -31,8 +31,8 @@ contract AllocatorRoles event Rely(address indexed usr); event Deny(address indexed usr); event SetIlkAdmin(bytes32 indexed ilk, address user); - event SetUserRole(address indexed who, uint8 indexed role, bool enabled); - event SetRoleAction(uint8 indexed role, address indexed target, bytes4 indexed sig, bool enabled); + event SetUserRole(bytes32 indexed ilk, address indexed who, uint8 indexed role, bool enabled); + event SetRoleAction(bytes32 indexed ilk, uint8 indexed role, address indexed target, bytes4 sig, bool enabled); // --- modifiers --- @@ -91,7 +91,7 @@ contract AllocatorRoles } else { userRoles[ilk][who] &= _bitNot(mask); } - emit SetUserRole(who, role, enabled); + emit SetUserRole(ilk, who, role, enabled); } function setRoleAction(bytes32 ilk, uint8 role, address target, bytes4 sig, bool enabled) external ilkAuth(ilk) { @@ -101,7 +101,7 @@ contract AllocatorRoles } else { actionsRoles[ilk][target][sig] &= _bitNot(mask); } - emit SetRoleAction(role, target, sig, enabled); + emit SetRoleAction(ilk, role, target, sig, enabled); } // --- caller --- diff --git a/src/AllocatorVault.sol b/src/AllocatorVault.sol index 033e3bcb..20f2b476 100644 --- a/src/AllocatorVault.sol +++ b/src/AllocatorVault.sol @@ -80,9 +80,9 @@ contract AllocatorVault { event Rely(address indexed usr); event Deny(address indexed usr); event File(bytes32 indexed what, address data); - event Draw(address indexed funnel, address indexed to, uint256 wad); - event Take(address indexed funnel, address indexed to, uint256 wad); - event Wipe(address indexed funnel, uint256 wad); + event Init(uint256 supply); + event Draw(address indexed sender, address indexed to, uint256 wad); + event Wipe(address indexed sender, address indexed from, uint256 wad); // --- modifiers --- @@ -154,6 +154,8 @@ contract AllocatorVault { gem.approve(address(gemJoin), supply); gemJoin.join(address(this), supply); vat.frob(ilk, address(this), address(this), address(0), int256(supply), 0); + + emit Init(supply); } function rely(address usr) external auth { @@ -195,7 +197,7 @@ contract AllocatorVault { uint256 dart = wad * RAY / rate; require(dart <= uint256(type(int256).max), "AllocatorVault/overflow"); vat.frob(ilk, address(this), address(this), address(this), 0, -int256(dart)); - emit Wipe(msg.sender, wad); + emit Wipe(msg.sender, from, wad); } function wipe(uint256 wad) external { diff --git a/test/AllocatorBuffer.t.sol b/test/AllocatorBuffer.t.sol index cc2baaae..9f8873c0 100644 --- a/test/AllocatorBuffer.t.sol +++ b/test/AllocatorBuffer.t.sol @@ -13,6 +13,10 @@ contract AllocatorBufferTest is DssTest { GemMock public gem; AllocatorBuffer public buffer; + event Approve(address indexed asset, address indexed spender, uint256 amount); + event Deposit(bytes32 indexed ilk, address indexed asset, uint256 amount); + event Withdraw(bytes32 indexed ilk, address indexed asset, address destination, uint256 amount); + function setUp() public { gem = new GemMock(1_000_000 * 10**18); buffer = new AllocatorBuffer(ilk); @@ -41,6 +45,8 @@ contract AllocatorBufferTest is DssTest { function testApprove() public { assertEq(gem.allowance(address(buffer), address(0xBEEF)), 0); + vm.expectEmit(true, true, true, true); + emit Approve(address(gem), address(0xBEEF), 10); buffer.approve(address(gem), address(0xBEEF), 10); assertEq(gem.allowance(address(buffer), address(0xBEEF)), 10); } @@ -49,9 +55,13 @@ contract AllocatorBufferTest is DssTest { assertEq(gem.balanceOf(address(this)), gem.totalSupply()); assertEq(gem.balanceOf(address(buffer)), 0); gem.approve(address(buffer), 10); + vm.expectEmit(true, true, true, true); + emit Deposit(buffer.ilk(), address(gem), 10); buffer.deposit(bytes32(0), address(gem), 10); assertEq(gem.balanceOf(address(this)), gem.totalSupply() - 10); assertEq(gem.balanceOf(address(buffer)), 10); + vm.expectEmit(true, true, true, true); + emit Withdraw(buffer.ilk(), address(gem), address(123), 4); buffer.withdraw(bytes32(0), address(gem), address(123), 4); assertEq(gem.balanceOf(address(buffer)), 6); assertEq(gem.balanceOf(address(123)), 4); diff --git a/test/AllocatorRoles.t.sol b/test/AllocatorRoles.t.sol index 8eb1e9f0..62447f43 100644 --- a/test/AllocatorRoles.t.sol +++ b/test/AllocatorRoles.t.sol @@ -11,6 +11,10 @@ contract AllocatorRolesTest is DssTest { AuthedMock authed; bytes32 ilk; + event SetIlkAdmin(bytes32 indexed ilk, address user); + event SetUserRole(bytes32 indexed ilk, address indexed who, uint8 indexed role, bool enabled); + event SetRoleAction(bytes32 indexed ilk, uint8 indexed role, address indexed target, bytes4 sig, bool enabled); + function setUp() public { ilk = "aaa"; roles = new AllocatorRoles(); @@ -45,7 +49,11 @@ contract AllocatorRolesTest is DssTest { vm.expectRevert("AllocatorRoles/ilk-not-authorized"); roles.setUserRole(ilk, address(this), admin_role, true); + vm.expectEmit(true, true, true, true); + emit SetIlkAdmin(ilk, address(this)); roles.setIlkAdmin(ilk, address(this)); + vm.expectEmit(true, true, true, true); + emit SetUserRole(ilk, address(this), admin_role, true); roles.setUserRole(ilk, address(this), admin_role, true); assertTrue( roles.hasUserRole(ilk, address(this), admin_role)); @@ -58,17 +66,23 @@ contract AllocatorRolesTest is DssTest { vm.expectRevert("AuthedMock/not-authorized"); authed.exec(); + vm.expectEmit(true, true, true, true); + emit SetRoleAction(ilk, admin_role, address(authed), bytes4(keccak256("exec()")), true); roles.setRoleAction(ilk, admin_role, address(authed), bytes4(keccak256("exec()")), true); assertTrue(roles.canCall(ilk, address(this), address(authed), bytes4(keccak256("exec()")))); authed.exec(); assertTrue(authed.flag()); + vm.expectEmit(true, true, true, true); + emit SetRoleAction(ilk, admin_role, address(authed), bytes4(keccak256("exec()")), false); roles.setRoleAction(ilk, admin_role, address(authed), bytes4(keccak256("exec()")), false); assertTrue(!roles.canCall(ilk, address(this), address(authed), bytes4(keccak256("exec()")))); vm.expectRevert("AuthedMock/not-authorized"); authed.exec(); + vm.expectEmit(true, true, true, true); + emit SetUserRole(ilk, address(this), mod_role, true); roles.setUserRole(ilk, address(this), mod_role, true); assertTrue( roles.hasUserRole(ilk, address(this), admin_role)); @@ -77,6 +91,8 @@ contract AllocatorRolesTest is DssTest { assertTrue(!roles.hasUserRole(ilk, address(this), max_role)); assertEq32(bytes32(hex"0000000000000000000000000000000000000000000000000000000000000003"), roles.userRoles(ilk, address(this))); + vm.expectEmit(true, true, true, true); + emit SetUserRole(ilk, address(this), user_role, true); roles.setUserRole(ilk, address(this), user_role, true); assertTrue( roles.hasUserRole(ilk, address(this), admin_role)); @@ -85,6 +101,8 @@ contract AllocatorRolesTest is DssTest { assertTrue(!roles.hasUserRole(ilk, address(this), max_role)); assertEq32(bytes32(hex"0000000000000000000000000000000000000000000000000000000000000007"), roles.userRoles(ilk, address(this))); + vm.expectEmit(true, true, true, true); + emit SetUserRole(ilk, address(this), mod_role, false); roles.setUserRole(ilk, address(this), mod_role, false); assertTrue( roles.hasUserRole(ilk, address(this), admin_role)); @@ -93,6 +111,8 @@ contract AllocatorRolesTest is DssTest { assertTrue(!roles.hasUserRole(ilk, address(this), max_role)); assertEq32(bytes32(hex"0000000000000000000000000000000000000000000000000000000000000005"), roles.userRoles(ilk, address(this))); + vm.expectEmit(true, true, true, true); + emit SetUserRole(ilk, address(this), max_role, true); roles.setUserRole(ilk, address(this), max_role, true); assertTrue( roles.hasUserRole(ilk, address(this), admin_role)); @@ -101,6 +121,8 @@ contract AllocatorRolesTest is DssTest { assertTrue( roles.hasUserRole(ilk, address(this), max_role)); assertEq32(bytes32(hex"8000000000000000000000000000000000000000000000000000000000000005"), roles.userRoles(ilk, address(this))); + vm.expectEmit(true, true, true, true); + emit SetRoleAction(ilk, max_role, address(authed), bytes4(keccak256("exec()")), true); roles.setRoleAction(ilk, max_role, address(authed), bytes4(keccak256("exec()")), true); assertTrue(roles.canCall(ilk, address(this), address(authed), bytes4(keccak256("exec()")))); authed.exec(); diff --git a/test/AllocatorVault.t.sol b/test/AllocatorVault.t.sol index 62bfaaca..6fb1a2bc 100644 --- a/test/AllocatorVault.t.sol +++ b/test/AllocatorVault.t.sol @@ -26,6 +26,10 @@ contract AllocatorVaultTest is DssTest { AllocatorVault public vault; bytes32 public ilk; + event Init(uint256 supply); + event Draw(address indexed sender, address indexed to, uint256 wad); + event Wipe(address indexed sender, address indexed from, uint256 wad); + function _divup(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = x != 0 ? ((x - 1) / y) + 1 : 0; @@ -100,11 +104,15 @@ contract AllocatorVaultTest is DssTest { uint256 div = 1001; // Hack to solve a compiling issue function testDrawWipe() public { + vm.expectEmit(true, true, true, true); + emit Init(gem.totalSupply()); vault.init(); vault.file("jug", address(jug)); assertEq(vault.line(), 20_000_000 * 10**18); (, uint256 art) = vat.urns(ilk, address(buffer)); assertEq(art, 0); + vm.expectEmit(true, true, true, true); + emit Draw(address(this), address(buffer), 50 * 10**18); vault.draw(50 * 10**18); (, art) = vat.urns(ilk, address(vault)); assertEq(art, 50 * 10**18); @@ -113,6 +121,8 @@ contract AllocatorVaultTest is DssTest { assertEq(vault.slot(), vault.line() - 50 * 10**18); assertEq(nst.balanceOf(address(buffer)), 50 * 10**18); vm.warp(block.timestamp + 1); + vm.expectEmit(true, true, true, true); + emit Draw(address(this), address(buffer), 50 * 10**18); vault.draw(50 * 10**18); (, art) = vat.urns(ilk, address(vault)); uint256 expectedArt = 50 * 10**18 + _divup(50 * 10**18 * 1000, div); @@ -124,12 +134,14 @@ contract AllocatorVaultTest is DssTest { assertGt(art * vat.rate(), 100.05 * 10**45); assertLt(art * vat.rate(), 100.06 * 10**45); vm.expectRevert("Gem/insufficient-balance"); - vault.wipe(100.06 ether); + vault.wipe(100.06 * 10**18); deal(address(nst), address(buffer), 100.06 * 10**18, true); assertEq(nst.balanceOf(address(buffer)), 100.06 * 10**18); vm.expectRevert(); - vault.wipe(100.06 ether); // It will try to wipe more art than existing, then reverts - vault.wipe(100.05 ether); + vault.wipe(100.06 * 10**18); // It will try to wipe more art than existing, then reverts + vm.expectEmit(true, true, true, true); + emit Wipe(address(this), address(buffer), 100.05 * 10**18); + vault.wipe(100.05 * 10**18); assertEq(nst.balanceOf(address(buffer)), 0.01 * 10**18); (, art) = vat.urns(ilk, address(vault)); assertEq(art, 1); // Dust which is impossible to wipe @@ -138,10 +150,14 @@ contract AllocatorVaultTest is DssTest { function testDrawAndWipeOtherAddress() public { vault.init(); vault.file("jug", address(jug)); + vm.expectEmit(true, true, true, true); + emit Draw(address(this), address(0xBEEF), 50 * 10**18); vault.draw(address(0xBEEF), 50 * 10**18); assertEq(nst.balanceOf(address(0xBEEF)), 50 * 10**18); vm.prank(address(0xBEEF)); nst.approve(address(vault), 50 * 10**18); + vm.expectEmit(true, true, true, true); + emit Wipe(address(this), address(0xBEEF), 50 * 10**18); vault.wipe(address(0xBEEF), 50 * 10**18); assertEq(nst.balanceOf(address(0xBEEF)), 0); } @@ -149,6 +165,8 @@ contract AllocatorVaultTest is DssTest { function testDebtOverLine() public { vault.init(); vault.file("jug", address(jug)); + vm.expectEmit(true, true, true, true); + emit Draw(address(this), address(buffer), vault.line()); vault.draw(vault.line()); vm.warp(block.timestamp + 1); jug.drip(ilk); diff --git a/test/WhitelistedRouter.t.sol b/test/WhitelistedRouter.t.sol index d60b5a58..a0b01ac7 100644 --- a/test/WhitelistedRouter.t.sol +++ b/test/WhitelistedRouter.t.sol @@ -27,6 +27,8 @@ contract WhitelistedRouterTest is DssTest { address constant FACILITATOR = address(0xb0b); + event Move(address sender, address indexed asset, address indexed from, address to, uint256 amt); + function setUp() public { ilk = "TEST-ILK"; roles = new RolesMock(); @@ -52,12 +54,16 @@ contract WhitelistedRouterTest is DssTest { assertEq(BalanceLike(gem).balanceOf(box1), amt); assertEq(BalanceLike(gem).balanceOf(box2), 0); vm.startPrank(FACILITATOR); - + + vm.expectEmit(true, true, true, true); + emit Move(FACILITATOR, gem, box1, box2, amt); router.move(gem, box1, box2, amt); assertEq(BalanceLike(gem).balanceOf(box1), 0); assertEq(BalanceLike(gem).balanceOf(box2), amt); + vm.expectEmit(true, true, true, true); + emit Move(FACILITATOR, gem, box2, box1, amt); router.move(gem, box2, box1, amt); assertEq(BalanceLike(gem).balanceOf(box1), amt); From 7ecc43aff608db8f0fd37098d2e7705b9d0d6c9f Mon Sep 17 00:00:00 2001 From: sunbreak Date: Tue, 20 Jun 2023 16:48:27 -0300 Subject: [PATCH 21/74] Use non relative paths --- src/AllocatorBuffer.sol | 2 +- src/AllocatorConduitExample.sol | 2 +- test/AllocatorBuffer.t.sol | 4 ++-- test/AllocatorOracle.t.sol | 2 +- test/AllocatorRoles.t.sol | 4 ++-- test/AllocatorVault.t.sol | 16 ++++++++-------- test/WhitelistedRouter.t.sol | 4 ++-- test/mocks/GemJoinMock.sol | 4 ++-- test/mocks/JugMock.sol | 2 +- test/mocks/NstJoinMock.sol | 4 ++-- 10 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/AllocatorBuffer.sol b/src/AllocatorBuffer.sol index 97074a79..839b86de 100644 --- a/src/AllocatorBuffer.sol +++ b/src/AllocatorBuffer.sol @@ -16,7 +16,7 @@ pragma solidity ^0.8.16; -import "./interfaces/IAllocatorConduit.sol"; +import "src/interfaces/IAllocatorConduit.sol"; interface TokenLike { function balanceOf(address) external view returns (uint256); diff --git a/src/AllocatorConduitExample.sol b/src/AllocatorConduitExample.sol index 5a67b075..af9871b3 100644 --- a/src/AllocatorConduitExample.sol +++ b/src/AllocatorConduitExample.sol @@ -16,7 +16,7 @@ pragma solidity ^0.8.16; -import "./interfaces/IAllocatorConduit.sol"; +import "src/interfaces/IAllocatorConduit.sol"; interface RolesLike { function canCall(bytes32, address, address, bytes4) external view returns (bool); diff --git a/test/AllocatorBuffer.t.sol b/test/AllocatorBuffer.t.sol index 9f8873c0..27c74fcc 100644 --- a/test/AllocatorBuffer.t.sol +++ b/test/AllocatorBuffer.t.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.16; import "dss-test/DssTest.sol"; -import { AllocatorBuffer } from "../src/AllocatorBuffer.sol"; -import { GemMock } from "./mocks/GemMock.sol"; +import { AllocatorBuffer } from "src/AllocatorBuffer.sol"; +import { GemMock } from "test/mocks/GemMock.sol"; contract AllocatorBufferTest is DssTest { using stdStorage for StdStorage; diff --git a/test/AllocatorOracle.t.sol b/test/AllocatorOracle.t.sol index e4579271..966c61b8 100644 --- a/test/AllocatorOracle.t.sol +++ b/test/AllocatorOracle.t.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.16; import "dss-test/DssTest.sol"; -import "../src/AllocatorOracle.sol"; +import "src/AllocatorOracle.sol"; contract AllocatorOracleTest is DssTest { AllocatorOracle public oracle; diff --git a/test/AllocatorRoles.t.sol b/test/AllocatorRoles.t.sol index 62447f43..5af1a0d9 100644 --- a/test/AllocatorRoles.t.sol +++ b/test/AllocatorRoles.t.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.16; import "dss-test/DssTest.sol"; -import "../src/AllocatorRoles.sol"; -import { AuthedMock } from "./mocks/AuthedMock.sol"; +import "src/AllocatorRoles.sol"; +import { AuthedMock } from "test/mocks/AuthedMock.sol"; contract AllocatorRolesTest is DssTest { AllocatorRoles roles; diff --git a/test/AllocatorVault.t.sol b/test/AllocatorVault.t.sol index 6fb1a2bc..b54ff5d5 100644 --- a/test/AllocatorVault.t.sol +++ b/test/AllocatorVault.t.sol @@ -3,14 +3,14 @@ pragma solidity ^0.8.16; import "dss-test/DssTest.sol"; -import { AllocatorVault } from "../src/AllocatorVault.sol"; -import { AllocatorBuffer } from "../src/AllocatorBuffer.sol"; -import { RolesMock } from "./mocks/RolesMock.sol"; -import { VatMock } from "./mocks/VatMock.sol"; -import { JugMock } from "./mocks/JugMock.sol"; -import { GemMock } from "./mocks/GemMock.sol"; -import { GemJoinMock } from "./mocks/GemJoinMock.sol"; -import { NstJoinMock } from "./mocks/NstJoinMock.sol"; +import { AllocatorVault } from "src/AllocatorVault.sol"; +import { AllocatorBuffer } from "src/AllocatorBuffer.sol"; +import { RolesMock } from "test/mocks/RolesMock.sol"; +import { VatMock } from "test/mocks/VatMock.sol"; +import { JugMock } from "test/mocks/JugMock.sol"; +import { GemMock } from "test/mocks/GemMock.sol"; +import { GemJoinMock } from "test/mocks/GemJoinMock.sol"; +import { NstJoinMock } from "test/mocks/NstJoinMock.sol"; contract AllocatorVaultTest is DssTest { using stdStorage for StdStorage; diff --git a/test/WhitelistedRouter.t.sol b/test/WhitelistedRouter.t.sol index a0b01ac7..17371e54 100644 --- a/test/WhitelistedRouter.t.sol +++ b/test/WhitelistedRouter.t.sol @@ -4,8 +4,8 @@ pragma solidity ^0.8.16; import "dss-test/DssTest.sol"; import { WhitelistedRouter } from "src/WhitelistedRouter.sol"; import { AllocatorBuffer } from "src/AllocatorBuffer.sol"; -import { GemMock } from "./mocks/GemMock.sol"; -import { RolesMock } from "./mocks/RolesMock.sol"; +import { GemMock } from "test/mocks/GemMock.sol"; +import { RolesMock } from "test/mocks/RolesMock.sol"; interface BalanceLike { function balanceOf(address) external view returns (uint256); diff --git a/test/mocks/GemJoinMock.sol b/test/mocks/GemJoinMock.sol index f1bbfa34..e07e306c 100644 --- a/test/mocks/GemJoinMock.sol +++ b/test/mocks/GemJoinMock.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.16; -import { VatMock } from "./VatMock.sol"; -import { GemMock } from "./GemMock.sol"; +import { VatMock } from "test/mocks/VatMock.sol"; +import { GemMock } from "test/mocks/GemMock.sol"; contract GemJoinMock { VatMock public vat; diff --git a/test/mocks/JugMock.sol b/test/mocks/JugMock.sol index ee8ab733..c5c430f4 100644 --- a/test/mocks/JugMock.sol +++ b/test/mocks/JugMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.16; -import { VatMock } from "./VatMock.sol"; +import { VatMock } from "test/mocks/VatMock.sol"; contract JugMock { VatMock vat; diff --git a/test/mocks/NstJoinMock.sol b/test/mocks/NstJoinMock.sol index 84bfc1ae..20913ffc 100644 --- a/test/mocks/NstJoinMock.sol +++ b/test/mocks/NstJoinMock.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.16; -import { VatMock } from "./VatMock.sol"; -import { GemMock } from "./GemMock.sol"; +import { VatMock } from "test/mocks/VatMock.sol"; +import { GemMock } from "test/mocks/GemMock.sol"; contract NstJoinMock { VatMock public vat; From 2995cc69a9573e554c8f4f24755ec909b856d5e2 Mon Sep 17 00:00:00 2001 From: sunbreak Date: Wed, 21 Jun 2023 11:19:20 -0300 Subject: [PATCH 22/74] Change withdraw interface and implementations --- src/AllocatorBuffer.sol | 4 +++- src/AllocatorConduitExample.sol | 6 ++++-- src/interfaces/IAllocatorConduit.sol | 11 ++++++----- test/AllocatorBuffer.t.sol | 5 +++++ 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/AllocatorBuffer.sol b/src/AllocatorBuffer.sol index 839b86de..715f87ec 100644 --- a/src/AllocatorBuffer.sol +++ b/src/AllocatorBuffer.sol @@ -89,7 +89,9 @@ contract AllocatorBuffer is IAllocatorConduit { emit Deposit(ilk, asset, amount); } - function withdraw(bytes32, address asset, address destination, uint256 amount) external auth { + function withdraw(bytes32, address asset, address destination, uint256 maxAmount) external auth returns (uint256 amount) { + uint256 balance = TokenLike(asset).balanceOf(address(this)); + amount = balance < maxAmount ? balance : maxAmount; TokenLike(asset).transfer(destination, amount); emit Withdraw(ilk, asset, destination, amount); } diff --git a/src/AllocatorConduitExample.sol b/src/AllocatorConduitExample.sol index af9871b3..ac29f512 100644 --- a/src/AllocatorConduitExample.sol +++ b/src/AllocatorConduitExample.sol @@ -87,8 +87,10 @@ contract AllocatorConduitExample is IAllocatorConduit { emit Deposit(ilk, asset, amount); } - function withdraw(bytes32 ilk, address asset, address destination, uint256 amount) external ilkAuth(ilk) { - positions[ilk][asset] -= amount; + function withdraw(bytes32 ilk, address asset, address destination, uint256 maxAmount) external ilkAuth(ilk) returns (uint256 amount) { + uint256 balance = positions[ilk][asset]; + amount = balance < maxAmount ? balance : maxAmount; + positions[ilk][asset] = balance - amount; // Implement the logic to withdraw funds from the FundManager emit Withdraw(ilk, asset, destination, amount); } diff --git a/src/interfaces/IAllocatorConduit.sol b/src/interfaces/IAllocatorConduit.sol index 2c585e7e..14cf8b88 100644 --- a/src/interfaces/IAllocatorConduit.sol +++ b/src/interfaces/IAllocatorConduit.sol @@ -49,12 +49,13 @@ interface IAllocatorConduit { /** * @dev Function for withdrawing tokens from a Fund Manager. - * @param ilk The unique identifier of the ilk. - * @param asset The asset to withdraw. - * @param destination The address to send the withdrawn tokens to. - * @param amount The amount of tokens to withdraw. + * @param ilk The unique identifier of the ilk. + * @param asset The asset to withdraw. + * @param destination The address to send the withdrawn tokens to. + * @param maxAmount The max amount of tokens to withdraw. + * @return amount The amount of tokens withdrawn. */ - function withdraw(bytes32 ilk, address asset, address destination, uint256 amount) external; + function withdraw(bytes32 ilk, address asset, address destination, uint256 maxAmount) external returns (uint256 amount); /** * @dev Function to get the maximum deposit possible for a specific asset and ilk. diff --git a/test/AllocatorBuffer.t.sol b/test/AllocatorBuffer.t.sol index 27c74fcc..486f0270 100644 --- a/test/AllocatorBuffer.t.sol +++ b/test/AllocatorBuffer.t.sol @@ -65,5 +65,10 @@ contract AllocatorBufferTest is DssTest { buffer.withdraw(bytes32(0), address(gem), address(123), 4); assertEq(gem.balanceOf(address(buffer)), 6); assertEq(gem.balanceOf(address(123)), 4); + vm.expectEmit(true, true, true, true); + emit Withdraw(buffer.ilk(), address(gem), address(123), 6); + buffer.withdraw(bytes32(0), address(gem), address(123), 7); + assertEq(gem.balanceOf(address(buffer)), 0); + assertEq(gem.balanceOf(address(123)), 10); } } From 0346df267f0358f64d79ec7ee9a52db6153867a9 Mon Sep 17 00:00:00 2001 From: sunbreak Date: Wed, 21 Jun 2023 11:44:18 -0300 Subject: [PATCH 23/74] Add comment and few checks in test --- src/interfaces/IAllocatorConduit.sol | 2 +- test/AllocatorBuffer.t.sol | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/interfaces/IAllocatorConduit.sol b/src/interfaces/IAllocatorConduit.sol index 14cf8b88..086409b4 100644 --- a/src/interfaces/IAllocatorConduit.sol +++ b/src/interfaces/IAllocatorConduit.sol @@ -52,7 +52,7 @@ interface IAllocatorConduit { * @param ilk The unique identifier of the ilk. * @param asset The asset to withdraw. * @param destination The address to send the withdrawn tokens to. - * @param maxAmount The max amount of tokens to withdraw. + * @param maxAmount The max amount of tokens to withdraw. Setting to "type(uint256).max" will ensure to withdraw all available liquidity. * @return amount The amount of tokens withdrawn. */ function withdraw(bytes32 ilk, address asset, address destination, uint256 maxAmount) external returns (uint256 amount); diff --git a/test/AllocatorBuffer.t.sol b/test/AllocatorBuffer.t.sol index 486f0270..dfb4c7d6 100644 --- a/test/AllocatorBuffer.t.sol +++ b/test/AllocatorBuffer.t.sol @@ -62,12 +62,12 @@ contract AllocatorBufferTest is DssTest { assertEq(gem.balanceOf(address(buffer)), 10); vm.expectEmit(true, true, true, true); emit Withdraw(buffer.ilk(), address(gem), address(123), 4); - buffer.withdraw(bytes32(0), address(gem), address(123), 4); + assertEq(buffer.withdraw(bytes32(0), address(gem), address(123), 4), 4); assertEq(gem.balanceOf(address(buffer)), 6); assertEq(gem.balanceOf(address(123)), 4); vm.expectEmit(true, true, true, true); emit Withdraw(buffer.ilk(), address(gem), address(123), 6); - buffer.withdraw(bytes32(0), address(gem), address(123), 7); + assertEq(buffer.withdraw(bytes32(0), address(gem), address(123), 7), 6); assertEq(gem.balanceOf(address(buffer)), 0); assertEq(gem.balanceOf(address(123)), 10); } From e4d2bb75ea70df98ee6f8e6110e535b18791c5ce Mon Sep 17 00:00:00 2001 From: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> Date: Fri, 30 Jun 2023 12:03:49 -0300 Subject: [PATCH 24/74] Remove Router + Add Registry + Modify Buffer, IConduit and example (#13) * Remove Router + Add Registry + Modify Buffer, IConduit and example * Remove deposit and withdraw from Buffer + extending conduit example --- src/AllocatorBuffer.sol | 33 +--------- src/AllocatorConduitExample.sol | 34 ++++++++-- src/AllocatorRegistry.sol | 63 ++++++++++++++++++ src/WhitelistedRouter.sol | 98 ---------------------------- src/interfaces/IAllocatorConduit.sol | 6 +- test/AllocatorBuffer.t.sol | 40 +++--------- test/AllocatorRegistry.t.sol | 37 +++++++++++ test/AllocatorVault.t.sol | 2 +- test/WhitelistedRouter.t.sol | 89 ------------------------- 9 files changed, 141 insertions(+), 261 deletions(-) create mode 100644 src/AllocatorRegistry.sol delete mode 100644 src/WhitelistedRouter.sol create mode 100644 test/AllocatorRegistry.t.sol delete mode 100644 test/WhitelistedRouter.t.sol diff --git a/src/AllocatorBuffer.sol b/src/AllocatorBuffer.sol index 715f87ec..3be37f58 100644 --- a/src/AllocatorBuffer.sol +++ b/src/AllocatorBuffer.sol @@ -16,8 +16,6 @@ pragma solidity ^0.8.16; -import "src/interfaces/IAllocatorConduit.sol"; - interface TokenLike { function balanceOf(address) external view returns (uint256); function approve(address, uint256) external; @@ -25,14 +23,11 @@ interface TokenLike { function transferFrom(address, address, uint256) external; } -contract AllocatorBuffer is IAllocatorConduit { +contract AllocatorBuffer { // --- storage variables --- mapping(address => uint256) public wards; - // --- immutables --- - bytes32 immutable public ilk; - // --- events --- event Rely(address indexed usr); @@ -48,23 +43,11 @@ contract AllocatorBuffer is IAllocatorConduit { // --- constructor --- - constructor(bytes32 ilk_) { - ilk = ilk_; - + constructor() { wards[msg.sender] = 1; emit Rely(msg.sender); } - // --- getters --- - - function maxDeposit(bytes32, address) external pure returns (uint256 maxDeposit_) { - maxDeposit_ = type(uint256).max; - } - - function maxWithdraw(bytes32, address asset) external view returns (uint256 maxWithdraw_) { - maxWithdraw_ = TokenLike(asset).balanceOf(address(this)); - } - // --- administration --- function rely(address usr) external auth { @@ -83,16 +66,4 @@ contract AllocatorBuffer is IAllocatorConduit { TokenLike(asset).approve(spender, amount); emit Approve(asset, spender, amount); } - - function deposit(bytes32, address asset, uint256 amount) external { - TokenLike(asset).transferFrom(msg.sender, address(this), amount); - emit Deposit(ilk, asset, amount); - } - - function withdraw(bytes32, address asset, address destination, uint256 maxAmount) external auth returns (uint256 amount) { - uint256 balance = TokenLike(asset).balanceOf(address(this)); - amount = balance < maxAmount ? balance : maxAmount; - TokenLike(asset).transfer(destination, amount); - emit Withdraw(ilk, asset, destination, amount); - } } diff --git a/src/AllocatorConduitExample.sol b/src/AllocatorConduitExample.sol index ac29f512..48dd0f21 100644 --- a/src/AllocatorConduitExample.sol +++ b/src/AllocatorConduitExample.sol @@ -22,6 +22,19 @@ interface RolesLike { function canCall(bytes32, address, address, bytes4) external view returns (bool); } +interface RegistryLike { + function buffers(bytes32) external view returns (address); +} + +interface BufferLike { + function approve(address, address, uint256) external; +} + +interface TokenLike { + function transfer(address, uint256) external; + function transferFrom(address, address, uint256) external; +} + contract AllocatorConduitExample is IAllocatorConduit { // --- storage variables --- @@ -30,7 +43,8 @@ contract AllocatorConduitExample is IAllocatorConduit { // --- immutables --- - RolesLike public immutable roles; + RolesLike public immutable roles; + RegistryLike public immutable registry; // --- events --- @@ -52,8 +66,9 @@ contract AllocatorConduitExample is IAllocatorConduit { // --- constructor --- - constructor(address roles_) { + constructor(address roles_, address registry_) { roles = RolesLike(roles_); + registry = RegistryLike(registry_); } // --- getters --- @@ -82,16 +97,21 @@ contract AllocatorConduitExample is IAllocatorConduit { // --- functions --- function deposit(bytes32 ilk, address asset, uint256 amount) external ilkAuth(ilk) { + address buffer = registry.buffers(ilk); + address manager; // Implement destination logic + BufferLike(buffer).approve(asset, address(this), amount); + TokenLike(asset).transferFrom(buffer, manager, amount); positions[ilk][asset] += amount; - // Implement the logic to deposit funds into the FundManager - emit Deposit(ilk, asset, amount); + emit Deposit(ilk, asset, buffer, amount); } - function withdraw(bytes32 ilk, address asset, address destination, uint256 maxAmount) external ilkAuth(ilk) returns (uint256 amount) { + function withdraw(bytes32 ilk, address asset, uint256 maxAmount) external ilkAuth(ilk) returns (uint256 amount) { uint256 balance = positions[ilk][asset]; amount = balance < maxAmount ? balance : maxAmount; positions[ilk][asset] = balance - amount; - // Implement the logic to withdraw funds from the FundManager - emit Withdraw(ilk, asset, destination, amount); + address buffer = registry.buffers(ilk); + address manager; // Implement source logic + TokenLike(asset).transferFrom(manager, buffer, amount); + emit Withdraw(ilk, asset, buffer, amount); } } diff --git a/src/AllocatorRegistry.sol b/src/AllocatorRegistry.sol new file mode 100644 index 00000000..c33592e6 --- /dev/null +++ b/src/AllocatorRegistry.sol @@ -0,0 +1,63 @@ +// SPDX-FileCopyrightText: © 2023 Dai Foundation +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +pragma solidity ^0.8.16; + +contract AllocatorRegistry { + // --- storage variables --- + + mapping(address => uint256) public wards; + mapping(bytes32 => address) public buffers; + + // --- events --- + + event Rely(address indexed usr); + event Deny(address indexed usr); + event File(bytes32 indexed ilk, bytes32 indexed what, address data); + + // --- modifiers --- + + modifier auth() { + require(wards[msg.sender] == 1, "AllocatorRegistry/not-authorized"); + _; + } + + // --- constructor --- + + constructor() { + wards[msg.sender] = 1; + emit Rely(msg.sender); + } + + // --- administration --- + + function rely(address usr) external auth { + wards[usr] = 1; + emit Rely(usr); + } + + function deny(address usr) external auth { + wards[usr] = 0; + emit Deny(usr); + } + + function file(bytes32 ilk, bytes32 what, address data) external auth { + if (what == "buffer") { + buffers[ilk] = data; + } else revert("AllocatorRegistry/file-unrecognized-param"); + emit File(ilk, what, data); + } +} diff --git a/src/WhitelistedRouter.sol b/src/WhitelistedRouter.sol deleted file mode 100644 index 05788e6e..00000000 --- a/src/WhitelistedRouter.sol +++ /dev/null @@ -1,98 +0,0 @@ -// SPDX-FileCopyrightText: © 2020 Lev Livnev -// SPDX-FileCopyrightText: © 2021 Dai Foundation -// SPDX-License-Identifier: AGPL-3.0-or-later -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -pragma solidity ^0.8.16; - -interface RolesLike { - function canCall(bytes32, address, address, bytes4) external view returns (bool); -} - -interface BoxLike { - function deposit(bytes32, address, uint256) external; - function withdraw(bytes32, address, address, uint256) external; -} - -interface GemLike { - function approve(address, uint256) external; -} - -contract WhitelistedRouter { - - // --- storage variables --- - - mapping (address => uint256) public wards; // Auth - mapping (address => uint256) public boxes; // whitelisted boxes (e.g. RWA conduits, Escrow, SubDAO proxy) - - // --- immutables --- - - RolesLike immutable public roles; - bytes32 immutable public ilk; - - // --- events --- - - event Rely(address indexed usr); - event Deny(address indexed usr); - event File(bytes32 indexed what, address data, uint256 val); - event Move(address sender, address indexed asset, address indexed from, address to, uint256 amt); - - // --- modifiers --- - - modifier auth() { - require(roles.canCall(ilk, msg.sender, address(this), msg.sig) || - wards[msg.sender] == 1, "WhitelistedRouter/not-authorized"); - _; - } - - // --- constructor --- - - constructor(address roles_, bytes32 ilk_) { - roles = RolesLike(roles_); - ilk = ilk_; - - wards[msg.sender] = 1; - emit Rely(msg.sender); - } - - // --- administration --- - - function rely(address usr) external auth { - wards[usr] = 1; - emit Rely(usr); - } - - function deny(address usr) external auth { - wards[usr] = 0; - emit Deny(usr); - } - - function file(bytes32 what, address data, uint256 val) external auth { - if (what == "box") boxes[data] = val; - else revert("WhitelistedRouter/file-unrecognized-param"); - emit File(what, data, val); - } - - // --- move execution --- - - function move(address asset, address from, address to, uint256 amt) external auth { - require(boxes[from] == 1, "WhitelistedRouter/invalid-from"); - require(boxes[to] == 1, "WhitelistedRouter/invalid-to"); - BoxLike(from).withdraw(ilk, asset, address(this), amt); - GemLike(asset).approve(address(to), amt); - BoxLike(to).deposit(ilk, asset, amt); - emit Move(msg.sender, asset, from, to, amt); - } -} diff --git a/src/interfaces/IAllocatorConduit.sol b/src/interfaces/IAllocatorConduit.sol index 086409b4..74a47f80 100644 --- a/src/interfaces/IAllocatorConduit.sol +++ b/src/interfaces/IAllocatorConduit.sol @@ -26,9 +26,10 @@ interface IAllocatorConduit { * @dev Event emitted when a deposit is made to the Conduit. * @param ilk The unique identifier of the ilk. * @param asset The address of the asset deposited. + * @param origin The address where the asset is coming from. * @param amount The amount of asset deposited. */ - event Deposit(bytes32 indexed ilk, address indexed asset, uint256 amount); + event Deposit(bytes32 indexed ilk, address indexed asset, address origin, uint256 amount); /** * @dev Event emitted when a withdrawal is made from the Conduit. @@ -51,11 +52,10 @@ interface IAllocatorConduit { * @dev Function for withdrawing tokens from a Fund Manager. * @param ilk The unique identifier of the ilk. * @param asset The asset to withdraw. - * @param destination The address to send the withdrawn tokens to. * @param maxAmount The max amount of tokens to withdraw. Setting to "type(uint256).max" will ensure to withdraw all available liquidity. * @return amount The amount of tokens withdrawn. */ - function withdraw(bytes32 ilk, address asset, address destination, uint256 maxAmount) external returns (uint256 amount); + function withdraw(bytes32 ilk, address asset, uint256 maxAmount) external returns (uint256 amount); /** * @dev Function to get the maximum deposit possible for a specific asset and ilk. diff --git a/test/AllocatorBuffer.t.sol b/test/AllocatorBuffer.t.sol index dfb4c7d6..0476eddd 100644 --- a/test/AllocatorBuffer.t.sol +++ b/test/AllocatorBuffer.t.sol @@ -9,17 +9,14 @@ import { GemMock } from "test/mocks/GemMock.sol"; contract AllocatorBufferTest is DssTest { using stdStorage for StdStorage; - bytes32 public ilk = "aaa"; GemMock public gem; AllocatorBuffer public buffer; event Approve(address indexed asset, address indexed spender, uint256 amount); - event Deposit(bytes32 indexed ilk, address indexed asset, uint256 amount); - event Withdraw(bytes32 indexed ilk, address indexed asset, address destination, uint256 amount); function setUp() public { gem = new GemMock(1_000_000 * 10**18); - buffer = new AllocatorBuffer(ilk); + buffer = new AllocatorBuffer(); } function testAuth() public { @@ -35,40 +32,19 @@ contract AllocatorBufferTest is DssTest { vm.stopPrank(); } - function testGetters() public { - assertEq(buffer.maxDeposit(bytes32(0), address(0)), type(uint256).max); - assertEq(buffer.maxWithdraw(bytes32(0), address(gem)), 0); - gem.approve(address(buffer), 10); - buffer.deposit(bytes32(0), address(gem), 10); - assertEq(buffer.maxWithdraw(bytes32(0), address(gem)), 10); - } - - function testApprove() public { - assertEq(gem.allowance(address(buffer), address(0xBEEF)), 0); - vm.expectEmit(true, true, true, true); - emit Approve(address(gem), address(0xBEEF), 10); - buffer.approve(address(gem), address(0xBEEF), 10); - assertEq(gem.allowance(address(buffer), address(0xBEEF)), 10); - } - - function testDepositWithdraw() public { + function testTransferApproveWithdraw() public { assertEq(gem.balanceOf(address(this)), gem.totalSupply()); assertEq(gem.balanceOf(address(buffer)), 0); - gem.approve(address(buffer), 10); - vm.expectEmit(true, true, true, true); - emit Deposit(buffer.ilk(), address(gem), 10); - buffer.deposit(bytes32(0), address(gem), 10); + gem.transfer(address(buffer), 10); assertEq(gem.balanceOf(address(this)), gem.totalSupply() - 10); assertEq(gem.balanceOf(address(buffer)), 10); + assertEq(gem.allowance(address(buffer), address(this)), 0); vm.expectEmit(true, true, true, true); - emit Withdraw(buffer.ilk(), address(gem), address(123), 4); - assertEq(buffer.withdraw(bytes32(0), address(gem), address(123), 4), 4); + emit Approve(address(gem), address(this), 4); + buffer.approve(address(gem), address(this), 4); + assertEq(gem.allowance(address(buffer), address(this)), 4); + gem.transferFrom(address(buffer), address(123), 4); assertEq(gem.balanceOf(address(buffer)), 6); assertEq(gem.balanceOf(address(123)), 4); - vm.expectEmit(true, true, true, true); - emit Withdraw(buffer.ilk(), address(gem), address(123), 6); - assertEq(buffer.withdraw(bytes32(0), address(gem), address(123), 7), 6); - assertEq(gem.balanceOf(address(buffer)), 0); - assertEq(gem.balanceOf(address(123)), 10); } } diff --git a/test/AllocatorRegistry.t.sol b/test/AllocatorRegistry.t.sol new file mode 100644 index 00000000..a24abeca --- /dev/null +++ b/test/AllocatorRegistry.t.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.8.16; + +import "dss-test/DssTest.sol"; +import { AllocatorRegistry } from "src/AllocatorRegistry.sol"; + +contract AllocatorRegistryTest is DssTest { + AllocatorRegistry public registry; + + event File(bytes32 indexed ilk, bytes32 indexed what, address data); + + function setUp() public { + registry = new AllocatorRegistry(); + } + + function testAuth() public { + checkAuth(address(registry), "AllocatorRegistry"); + } + + function testFileIlkAddress() public { + // First check an invalid value + vm.expectRevert("AllocatorRegistry/file-unrecognized-param"); + registry.file("any", "an invalid value", address(123)); + + // Update value + vm.expectEmit(true, true, true, true); + emit File("any", "buffer", address(123)); + registry.file("any", "buffer", address(123)); + assertEq(registry.buffers("any"), address(123)); + + // Finally check that file is authed + registry.deny(address(this)); + vm.expectRevert("AllocatorRegistry/not-authorized"); + registry.file("any", "data", address(123)); + } +} diff --git a/test/AllocatorVault.t.sol b/test/AllocatorVault.t.sol index b54ff5d5..a5df72d3 100644 --- a/test/AllocatorVault.t.sol +++ b/test/AllocatorVault.t.sol @@ -44,7 +44,7 @@ contract AllocatorVaultTest is DssTest { gemJoin = new GemJoinMock(vat, ilk, gem); nst = new GemMock(0); nstJoin = new NstJoinMock(vat, nst); - buffer = new AllocatorBuffer(ilk); + buffer = new AllocatorBuffer(); roles = new RolesMock(); vault = new AllocatorVault(address(roles), address(buffer), address(vat), address(gemJoin), address(nstJoin)); buffer.approve(address(nst), address(vault), type(uint256).max); diff --git a/test/WhitelistedRouter.t.sol b/test/WhitelistedRouter.t.sol deleted file mode 100644 index 17371e54..00000000 --- a/test/WhitelistedRouter.t.sol +++ /dev/null @@ -1,89 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.16; - -import "dss-test/DssTest.sol"; -import { WhitelistedRouter } from "src/WhitelistedRouter.sol"; -import { AllocatorBuffer } from "src/AllocatorBuffer.sol"; -import { GemMock } from "test/mocks/GemMock.sol"; -import { RolesMock } from "test/mocks/RolesMock.sol"; - -interface BalanceLike { - function balanceOf(address) external view returns (uint256); -} - -interface GemLikeLike { - function approve(address, uint256) external; - function transferFrom(address, address, uint256) external; -} - -contract WhitelistedRouterTest is DssTest { - bytes32 public ilk; - RolesMock public roles; - WhitelistedRouter public router; - address public box1; - address public box2; - address public USDC; - address public USDT; - - address constant FACILITATOR = address(0xb0b); - - event Move(address sender, address indexed asset, address indexed from, address to, uint256 amt); - - function setUp() public { - ilk = "TEST-ILK"; - roles = new RolesMock(); - router = new WhitelistedRouter(address(roles), ilk); - box1 = address(new AllocatorBuffer(ilk)); - box2 = address(new AllocatorBuffer(ilk)); - USDC = address(new GemMock(0)); - USDT = address(new GemMock(0)); - AllocatorBuffer(box1).rely(address(router)); - AllocatorBuffer(box2).rely(address(router)); - router.file("box", box1, 1); - router.file("box", box2, 1); - } - - function _checkMove(bool ward, address gem, uint256 amt) internal { - if (ward) { - router.rely(FACILITATOR); - } else { - roles.setOk(true); - } - - deal(gem, box1, amt, true); - assertEq(BalanceLike(gem).balanceOf(box1), amt); - assertEq(BalanceLike(gem).balanceOf(box2), 0); - vm.startPrank(FACILITATOR); - - vm.expectEmit(true, true, true, true); - emit Move(FACILITATOR, gem, box1, box2, amt); - router.move(gem, box1, box2, amt); - - assertEq(BalanceLike(gem).balanceOf(box1), 0); - assertEq(BalanceLike(gem).balanceOf(box2), amt); - - vm.expectEmit(true, true, true, true); - emit Move(FACILITATOR, gem, box2, box1, amt); - router.move(gem, box2, box1, amt); - - assertEq(BalanceLike(gem).balanceOf(box1), amt); - assertEq(BalanceLike(gem).balanceOf(box2), 0); - vm.stopPrank(); - } - - function testMoveUSDCWard() public { - _checkMove(true, USDC, 1000 ether); - } - - function testMoveUSDCRoles() public { - _checkMove(false, USDC, 1000 ether); - } - - function testMoveUSDTWard() public { - _checkMove(true, USDT, 1000 ether); - } - - function testMoveUSDTRoles() public { - _checkMove(false, USDT, 1000 ether); - } -} From 715606f1e036879d219bfee970a778eacbf8d78a Mon Sep 17 00:00:00 2001 From: sunbreak Date: Fri, 21 Jul 2023 12:36:10 -0300 Subject: [PATCH 25/74] Upgrade dss-test --- lib/dss-test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dss-test b/lib/dss-test index 9d755781..df7b13ea 160000 --- a/lib/dss-test +++ b/lib/dss-test @@ -1 +1 @@ -Subproject commit 9d7557817af849273ec1d952cc953b212f19025f +Subproject commit df7b13ead253f4b831df2464f7d74f28a091a790 From d1e14ab135422093124b5d365bdbb4cfecedfb90 Mon Sep 17 00:00:00 2001 From: telome <130504305+telome@users.noreply.github.com> Date: Mon, 31 Jul 2023 18:19:10 +0100 Subject: [PATCH 26/74] Swapper + Depositor (#2) * Add AllocatorRoles * First check roles * Fix for error messaging + add test for roles in the buffer + some renaming and order * Add tests + some renaming * More casting simplification * Add draft swapper * Separate facilitators from keepers * Account for ES * Fix nits * Move to subfolders * Move tests * Use storage weights * Remove pip * Add box authorisation sanity check * Update src/funnels/Swapper.sol Co-authored-by: oldchili <130549691+oldchili@users.noreply.github.com> * Address first batch of review comments * Rename vars * Use fixed lots * Add countdowns * Allow other gem decimals * Remove wipe call * Removing deposit call * Add README for latest design * Update README re whitelist * Update README to laster design iteration * Clarify README * Add updated Swapper * Add Router * Fix event * Clean ConduitMock * Update to approve+deposit architecture * Rename WhitelistedRouter.move * Move gem from buffer * Make Swapper generic * Add roles to Swapper * Add SwapperRunner * Update Swapper tests * Update router tests * Fix rebase * Use AllocatorBuffer instead of mock * Use fork * Rename swap role * Add Depositor * Fix rebase * Add Depositor rate limit * Add SwapDepositor * Fix cap check * Fix comment * Simplify usage of StableSwapper + fix tests * Add swap threshold * Remove this version of Router * Prepare structure for easier merge of dev * Rename GemLikes * Add _ prefix to internal functions * Move dust transfer to outer call * Allow for fee collection without liquidity removal * Using deposit cap per gem * Remove SwapDepositor * Add collect function to Depositor * Reorg directories * Rename maxSrcAmts -> caps + split Swapper tests * Add auth tests * Set StableSwapper config in one go * Apply suggestions from code review Co-authored-by: oldchili <130549691+oldchili@users.noreply.github.com> * Use immutable for buffer & swapper * Use reqOut instead of minPrice * Pre-calculate optimal deposit amounts * Add comments + fix events * Add fee collectFees flag + comment warning about minOut/reqOut mismatch * Add liquidity move test * Clean up StableSwapper access control * Split depositor tests * Add event tests * Remove buffer_ refs * Add revert tests * Add src checks * More tests for before and after hop operations * Remove redundant blank lines * More tests for StableSwapper * Remove redundant blank line in Depositor.t.sol * Remove unused TestUtils * Depositor interacts with pool directly * Add stable depositor * Align min/max/req var names * Add StableDepositor tests, missing collect * Now really add tests * Revert Depositor.t.sol changes * Apply suggestions from code review Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> * MintCallback revert message, tests * Actually add test, minor changes * Move automation's collect to keeper * Remove setApprovalForAll from buffer * Remove setApprovalForAll interface * Make facilitator warded, bots=>buds * Standarize short functions to multi-line, spaces * Remove more spaces in front of events * Reorder immutables according to ctr params * Fix spaces before immutable comments * Move PairConfig comments to the struct definition * Set swapper as SwapperLike directly * Add new lines at end of files * Fix some license identifiers * Pack hop,zzz,cap in swapper * Pack hop,zzz in depositor * Use buffer explicitly in MintCallbackData * Add UniV3 callee tests * Fix whitespaces * Increase slippage tolerance for testSwapLongPath * Use USDT instead of WETH in callee tests * Update test/funnels/callees/UniV3SwapperCallee.t.sol Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> * Use single struct for configuration * Minor fix * Use math libs from dss-kiln * Apply suggestions from code review Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> * Update test/funnels/Swapper.t.sol Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> * Update test/funnels/Swapper.t.sol Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> * Make sure zzz does not change in setLimits test * Align amt=>collect, test events with snapshot (except withdraw) * Test zzz also for Depositor's setLimits * Apply suggestions from code review Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> Co-authored-by: telome <130504305+telome@users.noreply.github.com> * Update src/funnels/Depositor.sol Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> * Move constant ot after immutable * Use named params in collect's burn call * Address Depositor.t.sol review comments * Apply suggestions from code review Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> * Return fees from Depositor.withdraw + misc (#22) * Return fees in Depositor * Fully check Depositor.Withdraw events * Withdraw to return fees0 and fees1, rename to those in collect * Test also withdraw events data * gem0, gem1 => src, dst in Swapper * Minor neats * Align vars and structs documentation, Capitalize comments * Clean up merge duplication * Remove spacing --------- Co-authored-by: telome <> Co-authored-by: oldchili <130549691+oldchili@users.noreply.github.com> Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> * Update test/funnels/automation/StableDepositor.t.sol Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> * Read position (#25) * Add getPosition * Return fees in Depositor * Fully check Depositor.Withdraw events * Withdraw to return fees0 and fees1, rename to those in collect * Test also withdraw events data * gem0, gem1 => src, dst in Swapper * Minor neats * Align vars and structs documentation, Capitalize comments * Clean up merge duplication --------- Co-authored-by: oldchili <130549691+oldchili@users.noreply.github.com> Co-authored-by: telome <> * Minor modifications to funnels tests + change default verbosity (#24) * Modify funnel test + change default verbosity * More changes to tests * Remove check that is semantically doesn't say much * Remove unused variables * Remove unused variables * Remove TestUtils (#27) * Smarter rate limiter using partial amounts (#26) * Swapper: Rate limit using partial amount * StableSwapper: add hop * Swapper reorder fields in limits structure * Partial amounts for Depositor and StableDepositor * Use same order * Change amts if greater than new cap in setLimits * amt => due * Add some missing variable documentation * Add missing zzz update * Fix name test contract * Improve storage packing + make deposit mapping keys more specific * Set due and zzz to 0 on SetLimits * Fix missing update of zzz * Add missing check + fix error message * Improve test coverage * Fix some comments * Set zzz to 0 in setConfig * Fix comments * Remove some unchecked blocks for better theoretical code correctness * Easier comparison to reason about * Fix for using just two slots in StableDepositor * Fix spacing * Fix comment * Minor change in test * nits * Minor * Minor * Avoid swapping directly to buffer (#28) * Avoid swapping directly to buffer * No need to get prev balance * Minor change in test * Revert "Minor change in test" This reverts commit 08e8cee1d14298fc5e43b071fda587b6eb601ead. --------- Co-authored-by: sunbreak * min => req * Minors Co-authored-by: oldchili <130549691+oldchili@users.noreply.github.com> * hop => era, zzz => end * More hop => era * Match order struct values Depositor with Swapper as it is also more logical packing * Fix aligment * StableDepositor: Make num signed int for separating deposit from withdraw (#29) * Changes in comments Co-authored-by: telome <130504305+telome@users.noreply.github.com> --------- Co-authored-by: oldchili <130549691+oldchili@users.noreply.github.com> Co-authored-by: telome <130504305+telome@users.noreply.github.com> * Rename Depositor to DepositorUniV3 + Callee renaming + Minor comment fix in Swapper (#30) * Rename Depositor to DepositorUniV3 + Minor comment fix in Swapper * UniV3SwapperCallee => SwapperCalleeUniV3 * Swapper Depositor Neats (#32) * Remove TODO of cheaper SLOAD * LiquidityAmounts - standard header, remove unused functions * Change licenses * Conduits Automated Mover (#33) * Conduit mover - initial version * Reordering and neats * Turn AllocatorConduitExample to a mock * Update test/funnels/automation/ConduitMover.t.sol Co-authored-by: telome <130504305+telome@users.noreply.github.com> --------- Co-authored-by: telome <130504305+telome@users.noreply.github.com> --------- Co-authored-by: sunbreak Co-authored-by: telome <> Co-authored-by: oldchili <130549691+oldchili@users.noreply.github.com> Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> --- .github/workflows/test.yml | 2 + .gitignore | 1 + foundry.toml | 2 +- src/funnels/DepositorUniV3.sol | 331 +++++++ src/funnels/Swapper.sol | 113 +++ src/funnels/automation/ConduitMover.sol | 107 +++ .../automation/StableDepositorUniV3.sol | 218 +++++ src/funnels/automation/StableSwapper.sol | 109 +++ src/funnels/callees/SwapperCalleeUniV3.sol | 66 ++ src/funnels/uniV3/FullMath.sol | 133 +++ src/funnels/uniV3/LiquidityAmounts.sol | 86 ++ src/funnels/uniV3/TickMath.sol | 258 ++++++ test/funnels/DepositorUniV3.t.sol | 816 ++++++++++++++++++ test/funnels/Swapper.t.sol | 197 +++++ test/funnels/automation/ConduitMover.t.sol | 168 ++++ .../automation/StableDepositorUniV3.t.sol | 274 ++++++ test/funnels/automation/StableSwapper.t.sol | 192 +++++ test/funnels/callees/SwapperCalleeUniV3.t.sol | 67 ++ .../mocks/AllocatorConduitMock.sol | 17 +- 19 files changed, 3144 insertions(+), 13 deletions(-) create mode 100644 src/funnels/DepositorUniV3.sol create mode 100644 src/funnels/Swapper.sol create mode 100644 src/funnels/automation/ConduitMover.sol create mode 100644 src/funnels/automation/StableDepositorUniV3.sol create mode 100644 src/funnels/automation/StableSwapper.sol create mode 100644 src/funnels/callees/SwapperCalleeUniV3.sol create mode 100644 src/funnels/uniV3/FullMath.sol create mode 100644 src/funnels/uniV3/LiquidityAmounts.sol create mode 100644 src/funnels/uniV3/TickMath.sol create mode 100644 test/funnels/DepositorUniV3.t.sol create mode 100644 test/funnels/Swapper.t.sol create mode 100644 test/funnels/automation/ConduitMover.t.sol create mode 100644 test/funnels/automation/StableDepositorUniV3.t.sol create mode 100644 test/funnels/automation/StableSwapper.t.sol create mode 100644 test/funnels/callees/SwapperCalleeUniV3.t.sol rename src/AllocatorConduitExample.sol => test/mocks/AllocatorConduitMock.sol (84%) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 272cc4ad..b5f0b324 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,3 +18,5 @@ jobs: - name: Run tests run: forge test + env: + ETH_RPC_URL: ${{ secrets.ETH_RPC_URL }} diff --git a/.gitignore b/.gitignore index 85198aaa..941feff6 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ docs/ # Dotenv file .env +tmp diff --git a/foundry.toml b/foundry.toml index 877d016c..1bc5d09b 100644 --- a/foundry.toml +++ b/foundry.toml @@ -5,6 +5,6 @@ libs = ["lib"] solc = "0.8.16" optimizer = true optimizer_runs = 200 -verbosity = 3 +verbosity = 1 # See more config options https://github.com/foundry-rs/foundry/tree/master/config diff --git a/src/funnels/DepositorUniV3.sol b/src/funnels/DepositorUniV3.sol new file mode 100644 index 00000000..884641b1 --- /dev/null +++ b/src/funnels/DepositorUniV3.sol @@ -0,0 +1,331 @@ +// SPDX-FileCopyrightText: © 2023 Dai Foundation +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +pragma solidity ^0.8.16; + +import {LiquidityAmounts} from "src/funnels/uniV3/LiquidityAmounts.sol"; +import {TickMath} from "src/funnels/uniV3/TickMath.sol"; + +interface RolesLike { + function canCall(bytes32, address, address, bytes4) external view returns (bool); +} + +interface GemLike { + function transferFrom(address, address, uint256) external; +} + +// https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/contracts/UniswapV3Pool.sol +interface UniV3PoolLike { + function positions(bytes32) external view returns ( + uint128 liquidity, + uint256 feeGrowthInside0LastX128, + uint256 feeGrowthInside1LastX128, + uint128 tokensOwed0, + uint128 tokensOwed1 + ); + + function slot0() external view returns ( + uint160 sqrtPriceX96, + int24 tick, + uint16 observationIndex, + uint16 observationCardinality, + uint16 observationCardinalityNext, + uint8 feeProtocol, + bool unlocked + ); + + function mint( + address recipient, + int24 tickLower, + int24 tickUpper, + uint128 amount, + bytes calldata data + ) external returns (uint256 amount0, uint256 amount1); + + function burn( + int24 tickLower, + int24 tickUpper, + uint128 amount + ) external returns (uint256 amount0, uint256 amount1); + + function collect( + address recipient, + int24 tickLower, + int24 tickUpper, + uint128 amount0Requested, + uint128 amount1Requested + ) external returns (uint128 amount0, uint128 amount1); +} + +contract DepositorUniV3 { + mapping (address => uint256) public wards; // Admins + mapping (address => mapping (address => mapping (uint24 => PairLimit))) public limits; // Rate limit parameters per (gem0, gem1, fee) pool + + RolesLike public immutable roles; // Contract managing access control for this DepositorUniV3 + bytes32 public immutable ilk; // Collateral type + address public immutable uniV3Factory; // Uniswap V3 factory + address public immutable buffer; // Contract from/to which the two tokens that make up the liquidity position are pulled/pushed + + struct PairLimit { + uint96 cap0; // Maximum amount of gem0 that can be added or removed as liquidity each era for a (gem0, gem1, fee) pool + uint96 cap1; // Maximum amount of gem1 that can be added or removed as liquidity each era for a (gem0, gem1, fee) pool + uint32 era; // Cooldown period it has to wait for renewing the due amounts to each cap for a (gem0, gem1, fee) pool + uint96 due0; // Pending amount of gem0 that can still be added or removed until next era for a (gem0, gem1, fee) pool + uint96 due1; // Pending amount of gem1 that can still be added or removed until next era for a (gem0, gem1, fee) pool + uint32 end; // Timestamp of when the current batch ends for a (gem0, gem1, fee) pool + } + + event Rely(address indexed usr); + event Deny(address indexed usr); + event SetLimits(address indexed gem0, address indexed gem1, uint24 indexed fee, uint96 cap0, uint96 cap1, uint32 era); + event Deposit(address indexed sender, address indexed gem0, address indexed gem1, uint128 liquidity, uint256 amt0, uint256 amt1); + event Withdraw(address indexed sender, address indexed gem0, address indexed gem1, uint128 liquidity, uint256 amt0, uint256 amt1, uint256 fees0, uint256 fees1); + event Collect(address indexed sender, address indexed gem0, address indexed gem1, uint256 fees0, uint256 fees1); + + constructor(address roles_, bytes32 ilk_, address uniV3Factory_, address buffer_) { + roles = RolesLike(roles_); + ilk = ilk_; + uniV3Factory = uniV3Factory_; + buffer = buffer_; + + wards[msg.sender] = 1; + emit Rely(msg.sender); + } + + modifier auth() { + require(roles.canCall(ilk, msg.sender, address(this), msg.sig) || wards[msg.sender] == 1, "DepositorUniV3/not-authorized"); + _; + } + + function rely(address usr) external auth { + wards[usr] = 1; + emit Rely(usr); + } + + function deny(address usr) external auth { + wards[usr] = 0; + emit Deny(usr); + } + + function setLimits(address gem0, address gem1, uint24 fee, uint96 cap0, uint96 cap1, uint32 era) external auth { + require(gem0 < gem1, "DepositorUniV3/wrong-gem-order"); + limits[gem0][gem1][fee] = PairLimit({ + cap0: cap0, + cap1: cap1, + era: era, + due0: 0, + due1: 0, + end: 0 + }); + emit SetLimits(gem0, gem1, fee, cap0, cap1, era); + } + + // https://github.com/Uniswap/v3-periphery/blob/464a8a49611272f7349c970e0fadb7ec1d3c1086/contracts/libraries/PoolAddress.sol#L33 + function _getPool(address gem0, address gem1, uint24 fee) internal view returns (UniV3PoolLike pool) { + pool = UniV3PoolLike(address(uint160(uint256(keccak256(abi.encodePacked( + hex'ff', + uniV3Factory, + keccak256(abi.encode(gem0, gem1, fee)), + bytes32(0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54) // POOL_INIT_CODE_HASH + )))))); + } + + function getPosition( + address gem0, + address gem1, + uint24 fee, + int24 tickLower, + int24 tickUpper + ) external view returns ( + uint128 liquidity, + uint256 feeGrowthInside0LastX128, + uint256 feeGrowthInside1LastX128, + uint128 tokensOwed0, + uint128 tokensOwed1 + ) { + return _getPool(gem0, gem1, fee). + positions(keccak256(abi.encodePacked(address(this), tickLower, tickUpper))); + } + + function _getLiquidityForAmts( + UniV3PoolLike pool, + int24 tickLower, + int24 tickUpper, + uint256 amt0Desired, + uint256 amt1Desired + ) internal view returns (uint128 liquidity) { + (uint160 sqrtPriceX96, , , , , , ) = pool.slot0(); + uint160 sqrtRatioAX96 = TickMath.getSqrtRatioAtTick(tickLower); + uint160 sqrtRatioBX96 = TickMath.getSqrtRatioAtTick(tickUpper); + + liquidity = LiquidityAmounts.getLiquidityForAmounts( + sqrtPriceX96, + sqrtRatioAX96, + sqrtRatioBX96, + amt0Desired, + amt1Desired + ); + } + + struct MintCallbackData { + address gem0; + address gem1; + uint24 fee; + } + + // https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/contracts/interfaces/callback/IUniswapV3MintCallback.sol#L6 + function uniswapV3MintCallback( + uint256 amt0Owed, + uint256 amt1Owed, + bytes calldata data + ) external { + MintCallbackData memory decoded = abi.decode(data, (MintCallbackData)); + address pool = address(_getPool(decoded.gem0, decoded.gem1, decoded.fee)); + require(msg.sender == pool, "DepositorUniV3/sender-not-a-pool"); + + if (amt0Owed > 0) GemLike(decoded.gem0).transferFrom(buffer, msg.sender, amt0Owed); + if (amt0Owed > 0) GemLike(decoded.gem1).transferFrom(buffer, msg.sender, amt1Owed); + } + + struct LiquidityParams { + address gem0; + address gem1; + uint24 fee; + int24 tickLower; + int24 tickUpper; + uint128 liquidity; // Useful for clearing out the entire liquidity of a position + uint256 amt0Desired; // Relevant only if liquidity == 0 + uint256 amt1Desired; // Relevant only if liquidity == 0 + uint256 amt0Min; + uint256 amt1Min; + } + + function deposit(LiquidityParams memory p) + external + auth + returns (uint128 liquidity, uint256 amt0, uint256 amt1) + { + require(p.gem0 < p.gem1, "DepositorUniV3/wrong-gem-order"); + + PairLimit memory limit; + limit.due0 = limits[p.gem0][p.gem1][p.fee].due0; + limit.due1 = limits[p.gem0][p.gem1][p.fee].due1; + limit.end = limits[p.gem0][p.gem1][p.fee].end; + + if (block.timestamp >= limit.end) { + // Reset batch + limit.due0 = limits[p.gem0][p.gem1][p.fee].cap0; + limit.due1 = limits[p.gem0][p.gem1][p.fee].cap1; + limit.era = limits[p.gem0][p.gem1][p.fee].era; + limit.end = uint32(block.timestamp) + limit.era; + } + + UniV3PoolLike pool = _getPool(p.gem0, p.gem1, p.fee); + liquidity = (p.liquidity == 0) + ? _getLiquidityForAmts(pool, p.tickLower, p.tickUpper, p.amt0Desired, p.amt1Desired) + : p.liquidity; + + (amt0, amt1) = pool.mint({ + recipient: address(this), + tickLower: p.tickLower, + tickUpper: p.tickUpper, + amount : liquidity, + data : abi.encode(MintCallbackData({gem0: p.gem0, gem1: p.gem1, fee: p.fee})) + }); + require(amt0 >= p.amt0Min && amt1 >= p.amt1Min, "DepositorUniV3/exceeds-slippage"); + require(amt0 <= limit.due0 && amt1 <= limit.due1, "DepositorUniV3/exceeds-due-amt"); + + limits[p.gem0][p.gem1][p.fee].due0 = limit.due0 - uint96(amt0); + limits[p.gem0][p.gem1][p.fee].due1 = limit.due1 - uint96(amt1); + limits[p.gem0][p.gem1][p.fee].end = limit.end; + + emit Deposit(msg.sender, p.gem0, p.gem1, liquidity, amt0, amt1); + } + + function withdraw(LiquidityParams memory p, bool takeFees) + external + auth + returns (uint128 liquidity, uint256 amt0, uint256 amt1, uint256 fees0, uint256 fees1) + { + require(p.gem0 < p.gem1, "DepositorUniV3/wrong-gem-order"); + + PairLimit memory limit; + limit.due0 = limits[p.gem0][p.gem1][p.fee].due0; + limit.due1 = limits[p.gem0][p.gem1][p.fee].due1; + limit.end = limits[p.gem0][p.gem1][p.fee].end; + + if (block.timestamp >= limit.end) { + // Reset batch + limit.due0 = limits[p.gem0][p.gem1][p.fee].cap0; + limit.due1 = limits[p.gem0][p.gem1][p.fee].cap1; + limit.era = limits[p.gem0][p.gem1][p.fee].era; + limit.end = uint32(block.timestamp) + limit.era; + } + + UniV3PoolLike pool = _getPool(p.gem0, p.gem1, p.fee); + liquidity = (p.liquidity == 0) + ? _getLiquidityForAmts(pool, p.tickLower, p.tickUpper, p.amt0Desired, p.amt1Desired) + : p.liquidity; + + (amt0, amt1) = pool.burn({ tickLower: p.tickLower, tickUpper: p.tickUpper, amount: liquidity }); + require(amt0 >= p.amt0Min && amt1 >= p.amt1Min, "DepositorUniV3/exceeds-slippage"); + require(amt0 <= limit.due0 && amt1 <= limit.due1, "DepositorUniV3/exceeds-due-amt"); + + limits[p.gem0][p.gem1][p.fee].due0 = limit.due0 - uint96(amt0); + limits[p.gem0][p.gem1][p.fee].due1 = limit.due1 - uint96(amt1); + limits[p.gem0][p.gem1][p.fee].end = limit.end; + + (uint256 collected0, uint256 collected1) = pool.collect({ + recipient : buffer, + tickLower : p.tickLower, + tickUpper : p.tickUpper, + amount0Requested: takeFees ? type(uint128).max : uint128(amt0), + amount1Requested: takeFees ? type(uint128).max : uint128(amt1) + }); + (fees0, fees1) = (collected0 - amt0, collected1 - amt1); + + emit Withdraw(msg.sender, p.gem0, p.gem1, liquidity, amt0, amt1, fees0, fees1); + } + + struct CollectParams { + address gem0; + address gem1; + uint24 fee; + int24 tickLower; + int24 tickUpper; + } + + function collect(CollectParams memory p) + external + auth + returns (uint256 fees0, uint256 fees1) + { + require(p.gem0 < p.gem1, "DepositorUniV3/wrong-gem-order"); + + UniV3PoolLike pool = _getPool(p.gem0, p.gem1, p.fee); + pool.burn({ tickLower: p.tickLower, tickUpper: p.tickUpper, amount: 0 }); // Update the position's owed fees + + (fees0, fees1) = pool.collect({ + recipient : buffer, + tickLower : p.tickLower, + tickUpper : p.tickUpper, + amount0Requested: type(uint128).max, + amount1Requested: type(uint128).max + }); + + emit Collect(msg.sender, p.gem0, p.gem1, fees0, fees1); + } +} diff --git a/src/funnels/Swapper.sol b/src/funnels/Swapper.sol new file mode 100644 index 00000000..97628df4 --- /dev/null +++ b/src/funnels/Swapper.sol @@ -0,0 +1,113 @@ +// SPDX-FileCopyrightText: © 2023 Dai Foundation +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +pragma solidity ^0.8.16; + +interface RolesLike { + function canCall(bytes32, address, address, bytes4) external view returns (bool); +} + +interface GemLike { + function balanceOf(address) external view returns (uint256); + function transfer(address, uint256) external; + function transferFrom(address, address, uint256) external; +} + +interface CalleeLike { + function swap(address, address, uint256, uint256, address, bytes calldata) external; +} + +contract Swapper { + mapping (address => uint256) public wards; // Admins + mapping (address => mapping (address => PairLimit)) public limits; // Rate limit parameters per src->dst pair + + RolesLike public immutable roles; // Contract managing access control for this Swapper + bytes32 public immutable ilk; // Collateral type + address public immutable buffer; // Contract from which the GEM to sell is pulled and to which the bought GEM is pushed + + struct PairLimit { + uint96 cap; // Maximum amount of src token that can be swapped each era for a src->dst pair + uint32 era; // Cooldown period it has to wait for renewing the due amount to cap for src to dst swap + uint96 due; // Pending amount of src token that can still be swapped until next era + uint32 end; // Timestamp of when the current batch ends + } + + event Rely(address indexed usr); + event Deny(address indexed usr); + event SetLimits(address indexed src, address indexed dst, uint96 cap, uint32 era); + event Swap(address indexed sender, address indexed src, address indexed dst, uint256 amt, uint256 out); + + constructor(address roles_, bytes32 ilk_, address buffer_) { + roles = RolesLike(roles_); + ilk = ilk_; + buffer = buffer_; + wards[msg.sender] = 1; + emit Rely(msg.sender); + } + + modifier auth() { + require(roles.canCall(ilk, msg.sender, address(this), msg.sig) || wards[msg.sender] == 1, "Swapper/not-authorized"); + _; + } + + function rely(address usr) external auth { + wards[usr] = 1; + emit Rely(usr); + } + + function deny(address usr) external auth { + wards[usr] = 0; + emit Deny(usr); + } + + function setLimits(address src, address dst, uint96 cap, uint32 era) external auth { + limits[src][dst] = PairLimit({ + cap: cap, + era: era, + due: 0, + end: 0 + }); + emit SetLimits(src, dst, cap, era); + } + + function swap(address src, address dst, uint256 amt, uint256 minOut, address callee, bytes calldata data) external auth returns (uint256 out) { + PairLimit memory limit = limits[src][dst]; + + if (block.timestamp >= limit.end) { + // Reset batch + limit.due = limit.cap; + limit.end = uint32(block.timestamp) + limit.era; + } + + require(amt <= limit.due, "Swapper/exceeds-due-amt"); + + unchecked { + limits[src][dst].due = limit.due - uint96(amt); + limits[src][dst].end = limit.end; + } + + GemLike(src).transferFrom(buffer, callee, amt); + + // Avoid swapping directly to buffer to prevent piggybacking another operation to satisfy the balance check + CalleeLike(callee).swap(src, dst, amt, minOut, address(this), data); + + out = GemLike(dst).balanceOf(address(this)); + require(out >= minOut, "Swapper/too-few-dst-received"); + + GemLike(dst).transfer(buffer, out); + emit Swap(msg.sender, src, dst, amt, out); + } +} diff --git a/src/funnels/automation/ConduitMover.sol b/src/funnels/automation/ConduitMover.sol new file mode 100644 index 00000000..e2b67dc3 --- /dev/null +++ b/src/funnels/automation/ConduitMover.sol @@ -0,0 +1,107 @@ +// SPDX-FileCopyrightText: © 2023 Dai Foundation +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +pragma solidity ^0.8.16; + +interface ConduitLike { + function deposit(bytes32, address, uint256) external; + function withdraw(bytes32, address, uint256) external; +} + +contract ConduitMover { + mapping (address => uint256) public wards; // Admins + mapping (address => uint256) public buds; // Whitelisted keepers + mapping (address => mapping (address => mapping (address => MoveConfig))) public configs; // Configuration for keepers + + bytes32 public immutable ilk; // Collateral type + address public immutable buffer; // The address of the buffer contract + + struct MoveConfig { + uint64 num; // The remaining number of times that a `from` to `to` gem move can be performed by keepers + uint32 hop; // Cooldown period it has to wait between `from` to `to` gem moves + uint32 zzz; // Timestamp of the last `from` to `to` gem move + uint128 lot; // The amount to move every hop for a `from` to `to` gem move + } + + event Rely(address indexed usr); + event Deny(address indexed usr); + event Kiss(address indexed usr); + event Diss(address indexed usr); + event SetConfig(address indexed from, address indexed to, address indexed gem, uint64 num, uint32 hop, uint128 lot); + event Move(address indexed from, address indexed to, address indexed gem, uint128 lot); + + constructor(bytes32 ilk_, address buffer_) { + buffer = buffer_; + ilk = ilk_; + + wards[msg.sender] = 1; + emit Rely(msg.sender); + } + + modifier auth { + require(wards[msg.sender] == 1, "ConduitMover/not-authorized"); + _; + } + + modifier toll { + require(buds[msg.sender] == 1, "ConduitMover/non-keeper"); + _; + } + + function rely(address usr) external auth { + wards[usr] = 1; + emit Rely(usr); + } + + function deny(address usr) external auth { + wards[usr] = 0; + emit Deny(usr); + } + + function kiss(address usr) external auth { + buds[usr] = 1; + emit Kiss(usr); + } + + function diss(address usr) external auth { + buds[usr] = 0; + emit Diss(usr); + } + + function setConfig(address from, address to, address gem, uint64 num, uint32 hop, uint128 lot) external auth { + configs[from][to][gem] = MoveConfig({ + num: num, + hop: hop, + zzz: 0, + lot: lot + }); + emit SetConfig(from, to, gem, num, hop, lot); + } + + function move(address from, address to, address gem) toll external { + MoveConfig memory cfg = configs[from][to][gem]; + + require(cfg.num > 0, "ConduitMover/exceeds-num"); + require(block.timestamp >= cfg.zzz + cfg.hop, "ConduitMover/too-soon"); + configs[from][to][gem].num = cfg.num - 1; + configs[from][to][gem].zzz = uint32(block.timestamp); + + ConduitLike(from).withdraw(ilk, gem, cfg.lot); + ConduitLike(to).deposit(ilk, gem, cfg.lot); + + emit Move(from, to, gem, cfg.lot); + } +} diff --git a/src/funnels/automation/StableDepositorUniV3.sol b/src/funnels/automation/StableDepositorUniV3.sol new file mode 100644 index 00000000..787e9b35 --- /dev/null +++ b/src/funnels/automation/StableDepositorUniV3.sol @@ -0,0 +1,218 @@ +// SPDX-FileCopyrightText: © 2023 Dai Foundation +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +pragma solidity ^0.8.16; + +interface DepositorUniV3Like { + struct LiquidityParams { + address gem0; + address gem1; + uint24 fee; + int24 tickLower; + int24 tickUpper; + uint128 liquidity; + uint256 amt0Desired; // Relevant only if liquidity == 0 + uint256 amt1Desired; // Relevant only if liquidity == 0 + uint256 amt0Min; + uint256 amt1Min; + } + + function deposit(LiquidityParams memory params) external returns ( + uint128 liquidity, + uint256 amt0, + uint256 amt1 + ); + + function withdraw(LiquidityParams memory p, bool takeFee) external returns ( + uint128 liquidity, + uint256 amt0, + uint256 amt1, + uint256 fees0, + uint256 fees1 + ); + + struct CollectParams { + address gem0; + address gem1; + uint24 fee; + int24 tickLower; + int24 tickUpper; + } + + function collect(CollectParams memory p) external returns ( + uint256 fees0, + uint256 fees1 + ); +} + +contract StableDepositorUniV3 { + mapping (address => uint256) public wards; // Admins + mapping (address => uint256) public buds; // Whitelisted keepers + mapping (address => mapping (address => mapping (uint24 => mapping (int24 => mapping (int24 => PairConfig))))) public configs; // Configuration for keepers + + DepositorUniV3Like public immutable depositor; // DepositorUniV3 for this StableDepositorUniV3 + + struct PairConfig { + int32 num; // The remaining number of times that a (gem0, gem1) operation can be performed by keepers (> 0: deposit, < 0: withdraw) + uint32 zzz; // Timestamp of the last deposit/withdraw execution + uint96 amt0; // Amount of gem0 to deposit/withdraw each (gem0, gem1) operation + uint96 amt1; // Amount of gem1 to deposit/withdraw each (gem0, gem1) operation + uint96 req0; // The minimum required deposit/withdraw amount of gem0 to insist on in each (gem0, gem1) operation + uint96 req1; // The minimum required deposit/withdraw amount of gem1 to insist on in each (gem0, gem1) operation + uint32 hop; // Cooldown period it has to wait between deposit/withdraw executions + } + + event Rely(address indexed usr); + event Deny(address indexed usr); + event Kiss(address indexed usr); + event Diss(address indexed usr); + event SetConfig(address indexed gem0, address indexed gem1, uint24 indexed fee, int24 tickLower, int24 tickUpper, int32 num, uint32 hop, uint96 amt0, uint96 amt1, uint96 req0, uint96 req1); + + constructor(address _depositor) { + depositor = DepositorUniV3Like(_depositor); + + wards[msg.sender] = 1; + emit Rely(msg.sender); + } + + modifier auth { + require(wards[msg.sender] == 1, "StableDepositorUniV3/not-authorized"); + _; + } + + // Permissionned to whitelisted keepers + modifier toll { + require(buds[msg.sender] == 1, "StableDepositorUniV3/non-keeper"); + _; + } + + function rely(address usr) external auth { + wards[usr] = 1; + emit Rely(usr); + } + + function deny(address usr) external auth { + wards[usr] = 0; + emit Deny(usr); + } + + function kiss(address usr) external auth { + buds[usr] = 1; + emit Kiss(usr); + } + + function diss(address usr) external auth { + buds[usr] = 0; + emit Diss(usr); + } + + function setConfig(address gem0, address gem1, uint24 fee, int24 tickLower, int24 tickUpper, int32 num, uint32 hop, uint96 amt0, uint96 amt1, uint96 req0, uint96 req1) external auth { + require(gem0 < gem1, "StableDepositorUniV3/wrong-gem-order"); + configs[gem0][gem1][fee][tickLower][tickUpper] = PairConfig({ + num: num, + zzz: 0, + amt0: amt0, + amt1: amt1, + req0: req0, + req1: req1, + hop: hop + }); + emit SetConfig(gem0, gem1, fee, tickLower, tickUpper, num, hop, amt0, amt1, req0, req1); + } + + // Note: the keeper's minAmts value must be updated whenever configs[gem0][gem1][fee][tickLower][tickUpper] is changed. + // Failing to do so may result in this call reverting or in taking on more slippage than intended (up to a limit controlled by configs[gem0][gem1][fee][tickLower][tickUpper].req0/1). + function deposit(address gem0, address gem1, uint24 fee, int24 tickLower, int24 tickUpper, uint128 amt0Min, uint128 amt1Min) + toll + external + returns (uint128 liquidity, uint256 amt0, uint256 amt1) + { + PairConfig memory cfg = configs[gem0][gem1][fee][tickLower][tickUpper]; + + require(cfg.num > 0, "StableDepositorUniV3/exceeds-num"); + require(block.timestamp >= cfg.zzz + cfg.hop, "StableDepositorUniV3/too-soon"); + configs[gem0][gem1][fee][tickLower][tickUpper].num = cfg.num - 1; + configs[gem0][gem1][fee][tickLower][tickUpper].zzz = uint32(block.timestamp); + + if (amt0Min == 0) amt0Min = cfg.req0; + if (amt1Min == 0) amt1Min = cfg.req1; + require(amt0Min >= cfg.req0, "StableDepositorUniV3/min-amt0-too-small"); + require(amt1Min >= cfg.req1, "StableDepositorUniV3/min-amt1-too-small"); + + DepositorUniV3Like.LiquidityParams memory p = DepositorUniV3Like.LiquidityParams({ + gem0 : gem0, + gem1 : gem1, + fee : fee, + tickLower : tickLower, + tickUpper : tickUpper, + liquidity : 0, // Use desired amounts + amt0Desired: cfg.amt0, + amt1Desired: cfg.amt1, + amt0Min : amt0Min, + amt1Min : amt1Min + }); + (liquidity, amt0, amt1) = depositor.deposit(p); + } + + // Note: the keeper's minAmts value must be updated whenever configs[gem0][gem1][fee][tickLower][tickUpper] is changed. + // Failing to do so may result in this call reverting or in taking on more slippage than intended (up to a limit controlled by configs[gem0][gem1][fee][tickLower][tickUpper].req0/1). + function withdraw(address gem0, address gem1, uint24 fee, int24 tickLower, int24 tickUpper, uint128 amt0Min, uint128 amt1Min) + toll + external + returns (uint128 liquidity, uint256 amt0, uint256 amt1, uint256 fees0, uint256 fees1) + { + PairConfig memory cfg = configs[gem0][gem1][fee][tickLower][tickUpper]; + + require(cfg.num < 0, "StableDepositorUniV3/exceeds-num"); + require(block.timestamp >= cfg.zzz + cfg.hop, "StableDepositorUniV3/too-soon"); + configs[gem0][gem1][fee][tickLower][tickUpper].num = cfg.num + 1; + configs[gem0][gem1][fee][tickLower][tickUpper].zzz = uint32(block.timestamp); + + if (amt0Min == 0) amt0Min = cfg.req0; + if (amt1Min == 0) amt1Min = cfg.req1; + require(amt0Min >= cfg.req0, "StableDepositorUniV3/min-amt0-too-small"); + require(amt1Min >= cfg.req1, "StableDepositorUniV3/min-amt1-too-small"); + + DepositorUniV3Like.LiquidityParams memory p = DepositorUniV3Like.LiquidityParams({ + gem0 : gem0, + gem1 : gem1, + fee : fee, + tickLower : tickLower, + tickUpper : tickUpper, + liquidity : 0, // Use desired amounts + amt0Desired: cfg.amt0, + amt1Desired: cfg.amt1, + amt0Min : amt0Min, + amt1Min : amt1Min + }); + (liquidity, amt0, amt1, fees0, fees1) = depositor.withdraw(p, true); + } + + function collect(address gem0, address gem1, uint24 fee, int24 tickLower, int24 tickUpper) + toll + external + returns (uint256 fees0, uint256 fees1) + { + DepositorUniV3Like.CollectParams memory collectParams = DepositorUniV3Like.CollectParams({ + gem0 : gem0, + gem1 : gem1, + fee : fee, + tickLower: tickLower, + tickUpper: tickUpper + }); + (fees0, fees1) = depositor.collect(collectParams); + } +} diff --git a/src/funnels/automation/StableSwapper.sol b/src/funnels/automation/StableSwapper.sol new file mode 100644 index 00000000..9340c8e6 --- /dev/null +++ b/src/funnels/automation/StableSwapper.sol @@ -0,0 +1,109 @@ +// SPDX-FileCopyrightText: © 2023 Dai Foundation +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +pragma solidity ^0.8.16; + +interface SwapperLike { + function swap(address, address, uint256, uint256, address, bytes calldata) external returns (uint256); +} + +contract StableSwapper { + mapping (address => uint256) public wards; // Admins + mapping (address => uint256) public buds; // Whitelisted keepers + mapping (address => mapping (address => PairConfig)) public configs; // Configuration for keepers + + SwapperLike public immutable swapper; // Swapper for this StableSwapper + + struct PairConfig { + uint128 num; // The remaining number of times that a src to dst swap can be performed by keepers + uint32 hop; // Cooldown period it has to wait between swap executions + uint32 zzz; // Timestamp of the last swap execution + uint96 lot; // The amount swapped by keepers from src to dst every hop + uint96 req; // The minimum required output amount to insist on in the swap form src to dst + } + + uint256 internal constant WAD = 10 ** 18; + + event Rely(address indexed usr); + event Deny(address indexed usr); + event Kiss(address indexed usr); + event Diss(address indexed usr); + event SetConfig(address indexed src, address indexed dst, uint128 num, uint32 hop, uint96 lot, uint96 req); + + constructor(address swapper_) { + swapper = SwapperLike(swapper_); + wards[msg.sender] = 1; + emit Rely(msg.sender); + } + + modifier auth { + require(wards[msg.sender] == 1, "StableSwapper/not-authorized"); + _; + } + + // permissionned to whitelisted keepers + modifier toll { + require(buds[msg.sender] == 1, "StableSwapper/non-keeper"); + _; + } + + function rely(address usr) external auth { + wards[usr] = 1; + emit Rely(usr); + } + + function deny(address usr) external auth { + wards[usr] = 0; + emit Deny(usr); + } + + function kiss(address usr) external auth { + buds[usr] = 1; + emit Kiss(usr); + } + + function diss(address usr) external auth { + buds[usr] = 0; + emit Diss(usr); + } + + function setConfig(address src, address dst, uint128 num, uint32 hop, uint96 lot, uint96 req) external auth { + configs[src][dst] = PairConfig({ + num: num, + hop: hop, + zzz: 0, + lot: lot, + req: req + }); + emit SetConfig(src, dst, num, hop, lot, req); + } + + // Note: the keeper's minOut value must be updated whenever configs[src][dst] is changed. + // Failing to do so may result in this call reverting or in taking on more slippage than intended (up to a limit controlled by configs[src][dst].min). + function swap(address src, address dst, uint256 minOut, address callee, bytes calldata data) toll external returns (uint256 out) { + PairConfig memory cfg = configs[src][dst]; + + require(cfg.num > 0, "StableSwapper/exceeds-num"); + require(block.timestamp >= cfg.zzz + cfg.hop, "StableSwapper/too-soon"); + configs[src][dst].num = cfg.num - 1; + configs[src][dst].zzz = uint32(block.timestamp); + + if (minOut == 0) minOut = cfg.req; + require(minOut >= cfg.req, "StableSwapper/min-too-small"); + + out = swapper.swap(src, dst, cfg.lot, minOut, callee, data); + } +} diff --git a/src/funnels/callees/SwapperCalleeUniV3.sol b/src/funnels/callees/SwapperCalleeUniV3.sol new file mode 100644 index 00000000..1a6c6bd3 --- /dev/null +++ b/src/funnels/callees/SwapperCalleeUniV3.sol @@ -0,0 +1,66 @@ +// SPDX-FileCopyrightText: © 2023 Dai Foundation +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +pragma solidity ^0.8.16; + +interface ApproveLike { + function approve(address, uint256) external returns (bool); +} + +// https://github.com/Uniswap/v3-periphery/blob/b06959dd01f5999aa93e1dc530fe573c7bb295f6/contracts/SwapRlefter.sol +interface SwapRouterLike { + function exactInput(ExactInputParams calldata params) external returns (uint256 amountOut); + + // https://github.com/Uniswap/v3-periphery/blob/b06959dd01f5999aa93e1dc530fe573c7bb295f6/contracts/interfaces/ISwapRouter.sol#L26 + // https://docs.uniswap.org/protocol/guides/swaps/multihop-swaps#input-parameters + struct ExactInputParams { + bytes path; + address recipient; + uint256 deadline; + uint256 amountIn; + uint256 amountOutMinimum; + } +} + +contract SwapperCalleeUniV3 { + address public immutable uniV3Router; + + constructor(address _uniV3Router) { + uniV3Router = _uniV3Router; + } + + function swap(address src, address dst, uint256 amt, uint256 minOut, address to, bytes calldata data) external { + bytes memory path = data; + + address firstToken; + address lastToken; + assembly { + firstToken := div(mload(add(path, 0x20)), 0x1000000000000000000000000) + lastToken := div(mload(sub(add(add(path, 0x20), mload(path)), 0x14)), 0x1000000000000000000000000) + } + require(src == firstToken && dst == lastToken, "SwapperCalleeUniV3/invalid-path"); + + ApproveLike(src).approve(uniV3Router, amt); + SwapRouterLike.ExactInputParams memory params = SwapRouterLike.ExactInputParams({ + path: path, + recipient: to, + deadline: block.timestamp, + amountIn: amt, + amountOutMinimum: minOut + }); + SwapRouterLike(uniV3Router).exactInput(params); + } +} diff --git a/src/funnels/uniV3/FullMath.sol b/src/funnels/uniV3/FullMath.sol new file mode 100644 index 00000000..b73761f5 --- /dev/null +++ b/src/funnels/uniV3/FullMath.sol @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-3.0 + +// Based on https://github.com/gelatodigital/g-uni-v1-core/blob/bea63422e2155242b051896b635508b7a99d2a1a/contracts/vendor/uniswap/FullMath.sol +// Uniswap version - https://github.com/Uniswap/v3-core/blob/412d9b236a1e75a98568d49b1aeb21e3a1430544/contracts/libraries/FullMath.sol + +pragma solidity ^0.8.16; + +/// @title Contains 512-bit math functions +/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision +/// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits +library FullMath { + /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 + /// @param a The multiplicand + /// @param b The multiplier + /// @param denominator The divisor + /// @return result The 256-bit result + /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv + function mulDiv( + uint256 a, + uint256 b, + uint256 denominator + ) internal pure returns (uint256 result) { + unchecked { + // 512-bit multiply [prod1 prod0] = a * b + // Compute the product mod 2**256 and mod 2**256 - 1 + // then use the Chinese Remainder Theorem to reconstruct + // the 512 bit result. The result is stored in two 256 + // variables such that product = prod1 * 2**256 + prod0 + uint256 prod0; // Least significant 256 bits of the product + uint256 prod1; // Most significant 256 bits of the product + assembly { + let mm := mulmod(a, b, not(0)) + prod0 := mul(a, b) + prod1 := sub(sub(mm, prod0), lt(mm, prod0)) + } + + // Handle non-overflow cases, 256 by 256 division + if (prod1 == 0) { + require(denominator > 0); + assembly { + result := div(prod0, denominator) + } + return result; + } + + // Make sure the result is less than 2**256. + // Also prevents denominator == 0 + require(denominator > prod1); + + /////////////////////////////////////////////// + // 512 by 256 division. + /////////////////////////////////////////////// + + // Make division exact by subtracting the remainder from [prod1 prod0] + // Compute remainder using mulmod + uint256 remainder; + assembly { + remainder := mulmod(a, b, denominator) + } + // Subtract 256 bit number from 512 bit number + assembly { + prod1 := sub(prod1, gt(remainder, prod0)) + prod0 := sub(prod0, remainder) + } + + // Factor powers of two out of denominator + // Compute largest power of two divisor of denominator. + // Always >= 1. + // EDIT for 0.8 compatibility: + // see: https://ethereum.stackexchange.com/questions/96642/unary-operator-cannot-be-applied-to-type-uint256 + uint256 twos = denominator & (~denominator + 1); + + // Divide denominator by power of two + assembly { + denominator := div(denominator, twos) + } + + // Divide [prod1 prod0] by the factors of two + assembly { + prod0 := div(prod0, twos) + } + // Shift in bits from prod1 into prod0. For this we need + // to flip `twos` such that it is 2**256 / twos. + // If twos is zero, then it becomes one + assembly { + twos := add(div(sub(0, twos), twos), 1) + } + prod0 |= prod1 * twos; + + // Invert denominator mod 2**256 + // Now that denominator is an odd number, it has an inverse + // modulo 2**256 such that denominator * inv = 1 mod 2**256. + // Compute the inverse by starting with a seed that is correct + // correct for four bits. That is, denominator * inv = 1 mod 2**4 + uint256 inv = (3 * denominator) ^ 2; + // Now use Newton-Raphson iteration to improve the precision. + // Thanks to Hensel's lifting lemma, this also works in modular + // arithmetic, doubling the correct bits in each step. + inv *= 2 - denominator * inv; // inverse mod 2**8 + inv *= 2 - denominator * inv; // inverse mod 2**16 + inv *= 2 - denominator * inv; // inverse mod 2**32 + inv *= 2 - denominator * inv; // inverse mod 2**64 + inv *= 2 - denominator * inv; // inverse mod 2**128 + inv *= 2 - denominator * inv; // inverse mod 2**256 + + // Because the division is now exact we can divide by multiplying + // with the modular inverse of denominator. This will give us the + // correct result modulo 2**256. Since the precoditions guarantee + // that the outcome is less than 2**256, this is the final result. + // We don't need to compute the high bits of the result and prod1 + // is no longer required. + result = prod0 * inv; + return result; + } + } + + /// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 + /// @param a The multiplicand + /// @param b The multiplier + /// @param denominator The divisor + /// @return result The 256-bit result + function mulDivRoundingUp( + uint256 a, + uint256 b, + uint256 denominator + ) internal pure returns (uint256 result) { + result = mulDiv(a, b, denominator); + if (mulmod(a, b, denominator) > 0) { + require(result < type(uint256).max); + result++; + } + } +} diff --git a/src/funnels/uniV3/LiquidityAmounts.sol b/src/funnels/uniV3/LiquidityAmounts.sol new file mode 100644 index 00000000..a6aeaeb2 --- /dev/null +++ b/src/funnels/uniV3/LiquidityAmounts.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +// Based on https://github.com/Uniswap/v3-periphery/blob/6cce88e63e176af1ddb6cc56e029110289622317/contracts/libraries/LiquidityAmounts.sol + +pragma solidity >=0.5.0; + +import "./FullMath.sol"; + +/// @title FixedPoint96 +/// @notice A library for handling binary fixed point numbers, see https://en.wikipedia.org/wiki/Q_(number_format) +/// @dev Used in SqrtPriceMath.sol +library FixedPoint96 { + uint8 internal constant RESOLUTION = 96; + uint256 internal constant Q96 = 0x1000000000000000000000000; +} + +/// @title Liquidity amount functions +/// @notice Provides functions for computing liquidity amounts from token amounts and prices +library LiquidityAmounts { + /// @notice Downcasts uint256 to uint128 + /// @param x The uint258 to be downcasted + /// @return y The passed value, downcasted to uint128 + function toUint128(uint256 x) private pure returns (uint128 y) { + require((y = uint128(x)) == x); + } + + /// @notice Computes the amount of liquidity received for a given amount of token0 and price range + /// @dev Calculates amount0 * (sqrt(upper) * sqrt(lower)) / (sqrt(upper) - sqrt(lower)) + /// @param sqrtRatioAX96 A sqrt price representing the first tick boundary + /// @param sqrtRatioBX96 A sqrt price representing the second tick boundary + /// @param amount0 The amount0 being sent in + /// @return liquidity The amount of returned liquidity + function getLiquidityForAmount0( + uint160 sqrtRatioAX96, + uint160 sqrtRatioBX96, + uint256 amount0 + ) internal pure returns (uint128 liquidity) { + if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); + uint256 intermediate = FullMath.mulDiv(sqrtRatioAX96, sqrtRatioBX96, FixedPoint96.Q96); + return toUint128(FullMath.mulDiv(amount0, intermediate, sqrtRatioBX96 - sqrtRatioAX96)); + } + + /// @notice Computes the amount of liquidity received for a given amount of token1 and price range + /// @dev Calculates amount1 / (sqrt(upper) - sqrt(lower)). + /// @param sqrtRatioAX96 A sqrt price representing the first tick boundary + /// @param sqrtRatioBX96 A sqrt price representing the second tick boundary + /// @param amount1 The amount1 being sent in + /// @return liquidity The amount of returned liquidity + function getLiquidityForAmount1( + uint160 sqrtRatioAX96, + uint160 sqrtRatioBX96, + uint256 amount1 + ) internal pure returns (uint128 liquidity) { + if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); + return toUint128(FullMath.mulDiv(amount1, FixedPoint96.Q96, sqrtRatioBX96 - sqrtRatioAX96)); + } + + /// @notice Computes the maximum amount of liquidity received for a given amount of token0, token1, the current + /// pool prices and the prices at the tick boundaries + /// @param sqrtRatioX96 A sqrt price representing the current pool prices + /// @param sqrtRatioAX96 A sqrt price representing the first tick boundary + /// @param sqrtRatioBX96 A sqrt price representing the second tick boundary + /// @param amount0 The amount of token0 being sent in + /// @param amount1 The amount of token1 being sent in + /// @return liquidity The maximum amount of liquidity received + function getLiquidityForAmounts( + uint160 sqrtRatioX96, + uint160 sqrtRatioAX96, + uint160 sqrtRatioBX96, + uint256 amount0, + uint256 amount1 + ) internal pure returns (uint128 liquidity) { + if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); + + if (sqrtRatioX96 <= sqrtRatioAX96) { + liquidity = getLiquidityForAmount0(sqrtRatioAX96, sqrtRatioBX96, amount0); + } else if (sqrtRatioX96 < sqrtRatioBX96) { + uint128 liquidity0 = getLiquidityForAmount0(sqrtRatioX96, sqrtRatioBX96, amount0); + uint128 liquidity1 = getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioX96, amount1); + + liquidity = liquidity0 < liquidity1 ? liquidity0 : liquidity1; + } else { + liquidity = getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioBX96, amount1); + } + } +} diff --git a/src/funnels/uniV3/TickMath.sol b/src/funnels/uniV3/TickMath.sol new file mode 100644 index 00000000..17f75475 --- /dev/null +++ b/src/funnels/uniV3/TickMath.sol @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: GPL-3.0 + +// Based on https://github.com/gelatodigital/g-uni-v1-core/blob/bea63422e2155242b051896b635508b7a99d2a1a/contracts/vendor/uniswap/TickMath.sol +// Uniswap version - https://github.com/Uniswap/v3-core/blob/412d9b236a1e75a98568d49b1aeb21e3a1430544/contracts/libraries/TickMath.sol + +pragma solidity ^0.8.16; + +/// @title Math library for computing sqrt prices from ticks and vice versa +/// @notice Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick) as fixed point Q64.96 numbers. Supports +/// prices between 2**-128 and 2**128 +library TickMath { + /// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128 + int24 internal constant MIN_TICK = -887272; + /// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128 + int24 internal constant MAX_TICK = -MIN_TICK; + + /// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK) + uint160 internal constant MIN_SQRT_RATIO = 4295128739; + /// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK) + uint160 internal constant MAX_SQRT_RATIO = + 1461446703485210103287273052203988822378723970342; + + /// @notice Calculates sqrt(1.0001^tick) * 2^96 + /// @dev Throws if |tick| > max tick + /// @param tick The input tick for the above formula + /// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0) + /// at the given tick + function getSqrtRatioAtTick(int24 tick) + internal + pure + returns (uint160 sqrtPriceX96) + { + uint256 absTick = + tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick)); + + // EDIT: 0.8 compatibility + require(absTick <= uint256(int256(MAX_TICK)), "T"); + + uint256 ratio = + absTick & 0x1 != 0 + ? 0xfffcb933bd6fad37aa2d162d1a594001 + : 0x100000000000000000000000000000000; + if (absTick & 0x2 != 0) + ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128; + if (absTick & 0x4 != 0) + ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128; + if (absTick & 0x8 != 0) + ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128; + if (absTick & 0x10 != 0) + ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128; + if (absTick & 0x20 != 0) + ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128; + if (absTick & 0x40 != 0) + ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128; + if (absTick & 0x80 != 0) + ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128; + if (absTick & 0x100 != 0) + ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128; + if (absTick & 0x200 != 0) + ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128; + if (absTick & 0x400 != 0) + ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128; + if (absTick & 0x800 != 0) + ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128; + if (absTick & 0x1000 != 0) + ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128; + if (absTick & 0x2000 != 0) + ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128; + if (absTick & 0x4000 != 0) + ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128; + if (absTick & 0x8000 != 0) + ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128; + if (absTick & 0x10000 != 0) + ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128; + if (absTick & 0x20000 != 0) + ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128; + if (absTick & 0x40000 != 0) + ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128; + if (absTick & 0x80000 != 0) + ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128; + + if (tick > 0) ratio = type(uint256).max / ratio; + + // this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96. + // we then downcast because we know the result always fits within 160 bits due to our tick input constraint + // we round up in the division so getTickAtSqrtRatio of the output price is always consistent + sqrtPriceX96 = uint160( + (ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1) + ); + } + + /// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio + /// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may + /// ever return. + /// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a Q64.96 + /// @return tick The greatest tick for which the ratio is less than or equal to the input ratio + function getTickAtSqrtRatio(uint160 sqrtPriceX96) + internal + pure + returns (int24 tick) + { + // second inequality must be < because the price can never reach the price at the max tick + require( + sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO, + "R" + ); + uint256 ratio = uint256(sqrtPriceX96) << 32; + + uint256 r = ratio; + uint256 msb = 0; + + assembly { + let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) + msb := or(msb, f) + r := shr(f, r) + } + assembly { + let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF)) + msb := or(msb, f) + r := shr(f, r) + } + assembly { + let f := shl(5, gt(r, 0xFFFFFFFF)) + msb := or(msb, f) + r := shr(f, r) + } + assembly { + let f := shl(4, gt(r, 0xFFFF)) + msb := or(msb, f) + r := shr(f, r) + } + assembly { + let f := shl(3, gt(r, 0xFF)) + msb := or(msb, f) + r := shr(f, r) + } + assembly { + let f := shl(2, gt(r, 0xF)) + msb := or(msb, f) + r := shr(f, r) + } + assembly { + let f := shl(1, gt(r, 0x3)) + msb := or(msb, f) + r := shr(f, r) + } + assembly { + let f := gt(r, 0x1) + msb := or(msb, f) + } + + if (msb >= 128) r = ratio >> (msb - 127); + else r = ratio << (127 - msb); + + int256 log_2 = (int256(msb) - 128) << 64; + + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(63, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(62, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(61, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(60, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(59, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(58, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(57, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(56, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(55, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(54, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(53, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(52, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(51, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(50, f)) + } + + int256 log_sqrt10001 = log_2 * 255738958999603826347141; // 128.128 number + + int24 tickLow = + int24( + (log_sqrt10001 - 3402992956809132418596140100660247210) >> 128 + ); + int24 tickHi = + int24( + (log_sqrt10001 + 291339464771989622907027621153398088495) >> 128 + ); + + tick = tickLow == tickHi + ? tickLow + : getSqrtRatioAtTick(tickHi) <= sqrtPriceX96 + ? tickHi + : tickLow; + } +} diff --git a/test/funnels/DepositorUniV3.t.sol b/test/funnels/DepositorUniV3.t.sol new file mode 100644 index 00000000..1bc12fda --- /dev/null +++ b/test/funnels/DepositorUniV3.t.sol @@ -0,0 +1,816 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.8.16; + +import "dss-test/DssTest.sol"; +import { DepositorUniV3 } from "src/funnels/DepositorUniV3.sol"; +import { SwapperCalleeUniV3 } from "src/funnels/callees/SwapperCalleeUniV3.sol"; +import { AllocatorRoles } from "src/AllocatorRoles.sol"; +import { AllocatorBuffer } from "src/AllocatorBuffer.sol"; + +interface GemLike { + function approve(address, uint256) external; + function balanceOf(address) external view returns (uint256); +} + +interface UniV3PoolLike { + struct PositionInfo { + uint128 liquidity; + uint256 feeGrowthInside0LastX128; + uint256 feeGrowthInside1LastX128; + uint128 tokensOwed0; + uint128 tokensOwed1; + } + + function positions(bytes32) external view returns (PositionInfo memory); +} + +interface SwapRouterLike { + function exactInput(ExactInputParams calldata params) external returns (uint256 amountOut); + + struct ExactInputParams { + bytes path; + address recipient; + uint256 deadline; + uint256 amountIn; + uint256 amountOutMinimum; + } +} + +contract DepositorUniV3Test is DssTest { + event SetLimits(address indexed gem0, address indexed gem1, uint24 indexed fee, uint96 cap0, uint96 cap1, uint32 era); + event Deposit(address indexed sender, address indexed gem0, address indexed gem1, uint128 liquidity, uint256 amt0, uint256 amt1); + event Withdraw(address indexed sender, address indexed gem0, address indexed gem1, uint128 liquidity, uint256 amt0, uint256 amt1, uint256 fees0, uint256 fees1); + event Collect(address indexed sender, address indexed gem0, address indexed gem1, uint256 fees0, uint256 fees1); + + AllocatorRoles public roles; + AllocatorBuffer public buffer; + DepositorUniV3 public depositor; + + bytes32 constant ilk = "aaa"; + bytes constant DAI_USDC_PATH = abi.encodePacked(DAI, uint24(100), USDC); + + address constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F; + address constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + address constant DAI_USDC_POOL = 0x5777d92f208679DB4b9778590Fa3CAB3aC9e2168; + address constant UNIV3_ROUTER = 0xE592427A0AEce92De3Edee1F18E0157C05861564; + address constant UNIV3_FACTORY = 0x1F98431c8aD98523631AE4a59f267346ea31F984; + + address constant FACILITATOR = address(0x1337); + uint8 constant DEPOSITOR_ROLE = uint8(2); + + int24 constant REF_TICK = -276324; // tick corresponding to 1 DAI = 1 USDC calculated as ~= math.log(10**(-12))/math.log(1.0001) + + function setUp() public { + vm.createSelectFork(vm.envString("ETH_RPC_URL")); + + buffer = new AllocatorBuffer(); + roles = new AllocatorRoles(); + depositor = new DepositorUniV3(address(roles), ilk, UNIV3_FACTORY, address(buffer)); + + roles.setIlkAdmin(ilk, address(this)); + roles.setRoleAction(ilk, DEPOSITOR_ROLE, address(depositor), depositor.deposit.selector, true); + roles.setRoleAction(ilk, DEPOSITOR_ROLE, address(depositor), depositor.withdraw.selector, true); + roles.setRoleAction(ilk, DEPOSITOR_ROLE, address(depositor), depositor.collect.selector, true); + roles.setUserRole(ilk, FACILITATOR, DEPOSITOR_ROLE, true); + + depositor.setLimits(DAI, USDC, 100, uint96(10_000 * WAD), uint96(10_000 * 10**6), 3600 seconds); + + deal(DAI, address(buffer), 1_000_000 * WAD, true); + deal(USDC, address(buffer), 1_000_000 * 10**6, true); + buffer.approve(USDC, address(depositor), type(uint256).max); + buffer.approve(DAI, address(depositor), type(uint256).max); + } + + function testConstructor() public { + DepositorUniV3 d = new DepositorUniV3(address(0xBEEF), "SubDAO 1", address(0xAAA), address(0xCCC)); + assertEq(address(d.roles()), address(0xBEEF)); + assertEq(d.ilk(), "SubDAO 1"); + assertEq(d.uniV3Factory(), address(0xAAA)); + assertEq(d.buffer(), address(0xCCC)); + assertEq(d.wards(address(this)), 1); + } + + function testAuth() public { + checkAuth(address(depositor), "DepositorUniV3"); + } + + function testModifiers() public { + bytes4[] memory authedMethods = new bytes4[](4); + authedMethods[0] = depositor.setLimits.selector; + authedMethods[1] = depositor.deposit.selector; + authedMethods[2] = depositor.withdraw.selector; + authedMethods[3] = depositor.collect.selector; + + vm.startPrank(address(0xBEEF)); + checkModifier(address(depositor), "DepositorUniV3/not-authorized", authedMethods); + vm.stopPrank(); + } + + function testSetLimits() public { + // deposit to make sure end and both due are set + DepositorUniV3.LiquidityParams memory dp = DepositorUniV3.LiquidityParams({ + gem0: DAI, + gem1: USDC, + fee: uint24(100), + tickLower: REF_TICK-100, + tickUpper: REF_TICK+100, + liquidity: 0, + amt0Desired: 500 * WAD, + amt1Desired: 500 * 10**6, + amt0Min: 490 * WAD, + amt1Min: 490 * 10**6 + }); + vm.prank(FACILITATOR); depositor.deposit(dp); + + (,,, uint96 due0Before, uint96 due1Before, uint32 endBefore) = depositor.limits(DAI, USDC, 100); + assertGt(due0Before, 0); + assertGt(due1Before, 0); + assertGt(endBefore, 0); + + vm.warp(block.timestamp + 1 hours); + + vm.expectEmit(true, true, true, true); + emit SetLimits(DAI, USDC, 100, 3, 4, 5); + vm.prank(address(this)); depositor.setLimits(DAI, USDC, 100, 3, 4, 5); + (uint96 cap0, uint96 cap1, uint32 era, uint96 due0, uint96 due1, uint32 end) = depositor.limits(DAI, USDC, 100); + assertEq(cap0, 3); + assertEq(cap1, 4); + assertEq(era, 5); + assertEq(due0, 0); + assertEq(due1, 0); + assertEq(end, 0); + } + + function testRoles() public { + vm.expectRevert("DepositorUniV3/not-authorized"); + vm.prank(address(0xBEEF)); depositor.setLimits(address(0), address(1), 0, 0, 0, 0); + roles.setRoleAction(ilk, uint8(0xF1), address(depositor), depositor.setLimits.selector, true); + roles.setUserRole(ilk, address(0xBEEF), uint8(0xF1), true); + vm.prank(address(0xBEEF)); depositor.setLimits(address(0), address(1), 0, 0, 0, 0); + } + + // https://github.com/Uniswap/v3-periphery/blob/464a8a49611272f7349c970e0fadb7ec1d3c1086/contracts/libraries/PoolAddress.sol#L33 + function _getPool(address gem0, address gem1, uint24 fee) internal pure returns (UniV3PoolLike pool) { + pool = UniV3PoolLike(address(uint160(uint256(keccak256(abi.encodePacked( + hex'ff', + UNIV3_FACTORY, + keccak256(abi.encode(gem0, gem1, fee)), + bytes32(0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54) // POOL_INIT_CODE_HASH + )))))); + } + + function _getLiquidity(address gem0, address gem1, uint24 fee, int24 tickLower, int24 tickUpper) + internal + view + returns (uint128 liquidity) + { + return (_getPool(gem0, gem1, fee). + positions(keccak256(abi.encodePacked(address(depositor), tickLower, tickUpper)))).liquidity; + + } + + function testDeposit() public { + assertEq(_getLiquidity(DAI, USDC, 100, REF_TICK-100, REF_TICK+100), 0); + uint256 prevUSDC = GemLike(USDC).balanceOf(address(buffer)); + uint256 prevDAI = GemLike(DAI).balanceOf(address(buffer)); + uint32 initialTime = uint32(block.timestamp); + + DepositorUniV3.LiquidityParams memory dp = DepositorUniV3.LiquidityParams({ + gem0: DAI, + gem1: USDC, + fee: uint24(100), + tickLower: REF_TICK-100, + tickUpper: REF_TICK+100, + liquidity: 0, + amt0Desired: 5_000 * WAD, + amt1Desired: 5_000 * 10**6, + amt0Min: 4_900 * WAD, + amt1Min: 4_900 * 10**6 + }); + + uint256 snapshot = vm.snapshot(); + (uint128 liq, uint256 amt0, uint256 amt1) = depositor.deposit(dp); + vm.revertTo(snapshot); + + vm.expectEmit(true, true, true, true); + emit Deposit(FACILITATOR, DAI, USDC, liq, amt0, amt1); + vm.prank(FACILITATOR); depositor.deposit(dp); + + assertLt(GemLike(DAI).balanceOf(address(buffer)), prevDAI); + assertLt(GemLike(USDC).balanceOf(address(buffer)), prevUSDC); + assertEq(GemLike(DAI).balanceOf(address(depositor)), 0); + assertEq(GemLike(USDC).balanceOf(address(depositor)), 0); + uint128 liquidityAfterDeposit = _getLiquidity(DAI, USDC, 100, REF_TICK-100, REF_TICK+100); + assertGt(liquidityAfterDeposit, 0); + (,,, uint96 due0, uint96 due1, uint32 end) = depositor.limits(DAI, USDC, 100); + assertEq(end, initialTime + 3600); + assertEq(due0, 10_000 * WAD - amt0); + assertEq(due1, 10_000 * 10**6 - amt1); + + prevUSDC = GemLike(USDC).balanceOf(address(buffer)); + prevDAI = GemLike(DAI).balanceOf(address(buffer)); + + dp.amt0Desired = 2_000 * WAD; + dp.amt1Desired = 2_000 * 10**6; + dp.amt0Min = 1_960 * WAD; + dp.amt1Min = 1_960 * 10**6; + + vm.warp(initialTime + 1800); + vm.prank(FACILITATOR); depositor.deposit(dp); + + (,,, due0, due1, end) = depositor.limits(DAI, USDC, 100); + assertEq(end, initialTime + 3600); + assertLt(GemLike(DAI).balanceOf(address(buffer)), prevDAI); + assertLt(GemLike(USDC).balanceOf(address(buffer)), prevUSDC); + assertEq(GemLike(DAI).balanceOf(address(depositor)), 0); + assertEq(GemLike(USDC).balanceOf(address(depositor)), 0); + assertGt(_getLiquidity(DAI, USDC, 100, REF_TICK-100, REF_TICK+100), liquidityAfterDeposit); + assertLt(due0, 10_000 * WAD - amt0); + assertLt(due1, 10_000 * 10**6 - amt1); + + dp.amt0Desired = 8_000 * WAD; + dp.amt1Desired = 8_000 * 10**6; + dp.amt0Min = 7_840 * WAD; + dp.amt1Min = 7_840 * 10**6; + + vm.expectRevert("DepositorUniV3/exceeds-due-amt"); + vm.prank(FACILITATOR); depositor.deposit(dp); + + vm.warp(initialTime + 3600); + vm.prank(FACILITATOR); (, amt0, amt1) = depositor.deposit(dp); + + (,,, due0, due1, end) = depositor.limits(DAI, USDC, 100); + assertEq(end, initialTime + 7200); + assertEq(due0, 10_000 * WAD - amt0); + assertEq(due1, 10_000 * 10**6 - amt1); + } + + function testGetPosition() public { + // initially the position doesn't exist + ( + uint128 liquidity, + uint256 feeGrowthInside0LastX128, + uint256 feeGrowthInside1LastX128, + uint128 tokensOwed0, + uint128 tokensOwed1 + ) = depositor.getPosition(DAI, USDC, 100, REF_TICK-100, REF_TICK+100); + assertEq(liquidity, 0); + assertEq(feeGrowthInside0LastX128, 0); + assertEq(feeGrowthInside1LastX128, 0); + assertEq(tokensOwed0, 0); + assertEq(tokensOwed1, 0); + + // deposit + DepositorUniV3.LiquidityParams memory dp = DepositorUniV3.LiquidityParams({ + gem0: DAI, + gem1: USDC, + fee: uint24(100), + tickLower: REF_TICK-100, + tickUpper: REF_TICK+100, + liquidity: 99777667447878834, + amt0Desired: 0, + amt1Desired: 0, + amt0Min: 0, + amt1Min: 0 + }); + vm.prank(FACILITATOR); depositor.deposit(dp); + + ( + liquidity, + feeGrowthInside0LastX128, + feeGrowthInside1LastX128, + tokensOwed0, + tokensOwed1 + ) = depositor.getPosition(DAI, USDC, 100, REF_TICK-100, REF_TICK+100); + assertEq(liquidity, 99777667447878834); + assertGt(feeGrowthInside0LastX128, 0); // initial value now that the position is created + assertGt(feeGrowthInside1LastX128, 0); // initial value now that the position is created + assertEq(tokensOwed0, 0); + assertEq(tokensOwed1, 0); + + // execute a trade to generate fees for the LP position + deal(DAI, address(this), 1_000_000 * WAD, true); + GemLike(DAI).approve(UNIV3_ROUTER, 1_000_000 * WAD); + SwapRouterLike.ExactInputParams memory params = SwapRouterLike.ExactInputParams({ + path: DAI_USDC_PATH, + recipient: address(this), + deadline: block.timestamp, + amountIn: 1_000_000 * WAD, + amountOutMinimum: 990_000 * 10**6 + }); + SwapRouterLike(UNIV3_ROUTER).exactInput(params); + + // withdraw without collecting fees + vm.warp(block.timestamp + 3600); + vm.prank(FACILITATOR); depositor.withdraw(dp, false); + + uint256 updatedfeeGrowthInside0LastX128; + uint256 updatedfeeGrowthInside1LastX128; + ( + liquidity, + updatedfeeGrowthInside0LastX128, + updatedfeeGrowthInside1LastX128, + tokensOwed0, + tokensOwed1 + ) = depositor.getPosition(DAI, USDC, 100, REF_TICK-100, REF_TICK+100); + assertEq(liquidity, 0); + assertTrue(updatedfeeGrowthInside0LastX128 > feeGrowthInside0LastX128 || updatedfeeGrowthInside1LastX128 > feeGrowthInside1LastX128); + assertTrue(tokensOwed0 > 0 || tokensOwed1 > 0); + } + + function testCollect() public { + DepositorUniV3.LiquidityParams memory dp = DepositorUniV3.LiquidityParams({ + gem0: DAI, + gem1: USDC, + fee: uint24(100), + tickLower: REF_TICK-100, + tickUpper: REF_TICK+100, + liquidity: 0, + amt0Desired: 500 * WAD, + amt1Desired: 500 * 10**6, + amt0Min: 490 * WAD, + amt1Min: 490 * 10**6 + }); + vm.prank(FACILITATOR); depositor.deposit(dp); + uint256 prevUSDC = GemLike(USDC).balanceOf(address(buffer)); + uint256 prevDAI = GemLike(DAI).balanceOf(address(buffer)); + + // execute a trade to generate fees for the LP position + deal(DAI, address(this), 1_000_000 * WAD, true); + GemLike(DAI).approve(UNIV3_ROUTER, 1_000_000 * WAD); + SwapRouterLike.ExactInputParams memory params = SwapRouterLike.ExactInputParams({ + path: DAI_USDC_PATH, + recipient: address(this), + deadline: block.timestamp, + amountIn: 1_000_000 * WAD, + amountOutMinimum: 990_000 * 10**6 + }); + SwapRouterLike(UNIV3_ROUTER).exactInput(params); + + DepositorUniV3.CollectParams memory cp = DepositorUniV3.CollectParams({ + gem0: DAI, + gem1: USDC, + fee: uint24(100), + tickLower: REF_TICK-100, + tickUpper: REF_TICK+100 + }); + + uint256 snapshot = vm.snapshot(); + (uint256 expectedFees0, uint256 expectedFees1) = depositor.collect(cp); + vm.revertTo(snapshot); + + vm.expectEmit(true, true, true, true); + emit Collect(FACILITATOR, DAI, USDC, expectedFees0, expectedFees1); + vm.prank(FACILITATOR); (uint256 fees0, uint256 fees1) = depositor.collect(cp); + + assertTrue(fees0 > 0 || fees1 > 0); + assertEq(GemLike(DAI).balanceOf(address(buffer)), prevDAI + fees0); + assertEq(GemLike(USDC).balanceOf(address(buffer)), prevUSDC + fees1); + assertEq(GemLike(DAI).balanceOf(address(depositor)), 0); + assertEq(GemLike(USDC).balanceOf(address(depositor)), 0); + } + + function testWithdrawWithNoFeeCollection() public { + uint256 initialUSDC = GemLike(USDC).balanceOf(address(buffer)); + uint256 initialDAI = GemLike(DAI).balanceOf(address(buffer)); + uint256 initialTime = uint32(block.timestamp); + + DepositorUniV3.LiquidityParams memory dp = DepositorUniV3.LiquidityParams({ + gem0: DAI, + gem1: USDC, + fee: uint24(100), + tickLower: REF_TICK-100, + tickUpper: REF_TICK+100, + liquidity: 0, + amt0Desired: 500 * WAD, + amt1Desired: 500 * 10**6, + amt0Min: 490 * WAD, + amt1Min: 490 * 10**6 + }); + vm.prank(FACILITATOR); (uint128 liq, uint256 deposited0, uint256 deposited1) = depositor.deposit(dp); + assertGt(_getLiquidity(DAI, USDC, 100, REF_TICK-100, REF_TICK+100), 0); + + dp.liquidity = liq; + + uint256 snapshot = vm.snapshot(); + (uint128 liquidity, uint256 withdrawn0, uint256 withdrawn1, uint256 fees0, uint256 fees1) = depositor.withdraw(dp, false); + vm.revertTo(snapshot); + + vm.expectEmit(true, true, true, true); + emit Withdraw(FACILITATOR, DAI, USDC, liquidity, withdrawn0, withdrawn1, fees0, fees1); + vm.prank(FACILITATOR); depositor.withdraw(dp, false); + + assertGe(withdrawn0 + 1, deposited0); + assertGe(withdrawn1 + 1, deposited1); + assertGe(GemLike(DAI).balanceOf(address(buffer)) + 1, initialDAI); + assertGe(GemLike(USDC).balanceOf(address(buffer)) + 1, initialUSDC); + assertEq(GemLike(DAI).balanceOf(address(depositor)), 0); + assertEq(GemLike(USDC).balanceOf(address(depositor)), 0); + assertEq(_getLiquidity(DAI, USDC, 100, REF_TICK-100, REF_TICK+100), 0); + assertEq(fees0, 0); + assertEq(fees1, 0); + assertEq(liquidity, liq); + (,,, uint96 due0, uint96 due1, uint32 end) = depositor.limits(DAI, USDC, 100); + assertEq(end, initialTime + 3600); + assertEq(due0, 10_000 * WAD - deposited0 - withdrawn0); + assertEq(due1, 10_000 * 10**6 - deposited1 - withdrawn1); + + dp.liquidity = 0; + dp.amt0Desired = 8_000 * WAD; + dp.amt1Desired = 8_000 * 10**6; + dp.amt0Min = 7_840 * WAD; + dp.amt1Min = 7_840 * 10**6; + + vm.warp(initialTime + 1800); + vm.prank(FACILITATOR); (liq,,) = depositor.deposit(dp); + + (,,, due0, due1, end) = depositor.limits(DAI, USDC, 100); + assertEq(end, initialTime + 3600); + assertLt(due0, 10_000 * WAD - deposited0 - withdrawn0); + assertLt(due1, 10_000 * 10**6 - deposited1 - withdrawn1); + + dp.liquidity = liq; + + vm.expectRevert("DepositorUniV3/exceeds-due-amt"); + vm.prank(FACILITATOR); depositor.withdraw(dp, false); + + vm.warp(initialTime + 3600); + vm.prank(FACILITATOR); (, withdrawn0, withdrawn1,,) = depositor.withdraw(dp, false); + + (,,, due0, due1, end) = depositor.limits(DAI, USDC, 100); + assertEq(end, initialTime + 7200); + assertEq(due0, 10_000 * WAD - withdrawn0); + assertEq(due1, 10_000 * 10**6 - withdrawn1); + } + + function testWithdrawWithFeeCollection() public { + DepositorUniV3.LiquidityParams memory dp = DepositorUniV3.LiquidityParams({ + gem0: DAI, + gem1: USDC, + fee: uint24(100), + tickLower: REF_TICK-100, + tickUpper: REF_TICK+100, + liquidity: 0, + amt0Desired: 500 * WAD, + amt1Desired: 500 * 10**6, + amt0Min: 490 * WAD, + amt1Min: 490 * 10**6 + }); + vm.prank(FACILITATOR); (uint128 liq,,) = depositor.deposit(dp); + assertGt(_getLiquidity(DAI, USDC, 100, REF_TICK-100, REF_TICK+100), 0); + uint256 prevUSDC = GemLike(USDC).balanceOf(address(buffer)); + uint256 prevDAI = GemLike(DAI).balanceOf(address(buffer)); + + // execute a trade to generate fees for the LP position + deal(DAI, address(this), 1_000_000 * WAD, true); + GemLike(DAI).approve(UNIV3_ROUTER, 1_000_000 * WAD); + SwapRouterLike.ExactInputParams memory params = SwapRouterLike.ExactInputParams({ + path: DAI_USDC_PATH, + recipient: address(this), + deadline: block.timestamp, + amountIn: 1_000_000 * WAD, + amountOutMinimum: 990_000 * 10**6 + }); + SwapRouterLike(UNIV3_ROUTER).exactInput(params); + + dp.liquidity = liq; + vm.warp(block.timestamp + 3600); + + uint256 snapshot = vm.snapshot(); + vm.prank(FACILITATOR); (uint128 liquidity, uint256 withdrawn0, uint256 withdrawn1, uint256 fees0, uint256 fees1) = depositor.withdraw(dp, true); + vm.revertTo(snapshot); + + vm.expectEmit(true, true, true, true); + emit Withdraw(FACILITATOR, DAI, USDC, liquidity, withdrawn0, withdrawn1, fees0, fees1); + vm.prank(FACILITATOR); depositor.withdraw(dp, true); + + assertTrue(fees0 > 0 || fees1 > 0); + assertTrue(withdrawn0 > 0 || withdrawn1 > 0); + assertEq(GemLike(DAI).balanceOf(address(buffer)), prevDAI + withdrawn0 + fees0); + assertEq(GemLike(USDC).balanceOf(address(buffer)), prevUSDC + withdrawn1 + fees1); + assertEq(GemLike(DAI).balanceOf(address(depositor)), 0); + assertEq(GemLike(USDC).balanceOf(address(depositor)), 0); + assertEq(_getLiquidity(DAI, USDC, 100, REF_TICK-100, REF_TICK+100), 0); + assertEq(liquidity, liq); + } + + function testWithdrawZeroWithFeeCollection() public { + DepositorUniV3.LiquidityParams memory dp = DepositorUniV3.LiquidityParams({ + gem0: DAI, + gem1: USDC, + fee: uint24(100), + tickLower: REF_TICK-100, + tickUpper: REF_TICK+100, + liquidity: 0, + amt0Desired: 500 * WAD, + amt1Desired: 500 * 10**6, + amt0Min: 490 * WAD, + amt1Min: 490 * 10**6 + }); + vm.prank(FACILITATOR); (uint128 liq,,) = depositor.deposit(dp); + assertGt(_getLiquidity(DAI, USDC, 100, REF_TICK-100, REF_TICK+100), 0); + uint256 prevUSDC = GemLike(USDC).balanceOf(address(buffer)); + uint256 prevDAI = GemLike(DAI).balanceOf(address(buffer)); + + // execute a trade to generate fees for the LP position + deal(DAI, address(this), 1_000_000 * WAD, true); + GemLike(DAI).approve(UNIV3_ROUTER, 1_000_000 * WAD); + SwapRouterLike.ExactInputParams memory params = SwapRouterLike.ExactInputParams({ + path: DAI_USDC_PATH, + recipient: address(this), + deadline: block.timestamp, + amountIn: 1_000_000 * WAD, + amountOutMinimum: 990_000 * 10**6 + }); + SwapRouterLike(UNIV3_ROUTER).exactInput(params); + + dp.amt0Desired = 0; + dp.amt1Desired = 0; + dp.amt0Min = 0; + dp.amt1Min = 0; + vm.warp(block.timestamp + 3600); + + uint256 snapshot = vm.snapshot(); + vm.prank(FACILITATOR); (uint128 liquidity, uint256 withdrawn0, uint256 withdrawn1, uint256 fees0, uint256 fees1) = depositor.withdraw(dp, true); + vm.revertTo(snapshot); + + vm.expectEmit(true, true, true, true); + emit Withdraw(FACILITATOR, DAI, USDC, liquidity, withdrawn0, withdrawn1, fees0, fees1); + vm.prank(FACILITATOR); depositor.withdraw(dp, true); + + assertEq(liquidity, 0); + assertEq(withdrawn0, 0); + assertEq(withdrawn1, 0); + assertTrue(fees0 > 0 || fees1 > 0); + assertEq(GemLike(DAI).balanceOf(address(buffer)), prevDAI + fees0); + assertEq(GemLike(USDC).balanceOf(address(buffer)), prevUSDC + fees1); + assertEq(GemLike(DAI).balanceOf(address(depositor)), 0); + assertEq(GemLike(USDC).balanceOf(address(depositor)), 0); + assertEq(_getLiquidity(DAI, USDC, 100, REF_TICK-100, REF_TICK+100), liq); + } + + function testWithdrawAmounts() public { + DepositorUniV3.LiquidityParams memory dp = DepositorUniV3.LiquidityParams({ + gem0: DAI, + gem1: USDC, + fee: uint24(100), + tickLower: REF_TICK-100, + tickUpper: REF_TICK+100, + liquidity: 0, + amt0Desired: 500 * WAD, + amt1Desired: 500 * 10**6, + amt0Min: 490 * WAD, + amt1Min: 490 * 10**6 + }); + vm.prank(FACILITATOR); (, uint256 deposited0, uint256 deposited1) = depositor.deposit(dp); + assertGt(_getLiquidity(DAI, USDC, 100, REF_TICK-100, REF_TICK+100), 0); + + dp.liquidity = 0; + dp.amt0Desired = deposited0; + dp.amt1Desired = deposited1; + + uint256 liquidityBeforeWithdraw = _getLiquidity(DAI, USDC, 100, REF_TICK-100, REF_TICK+100); + + vm.warp(block.timestamp + 3600); + + uint256 snapshot = vm.snapshot(); + vm.prank(FACILITATOR); (uint128 liquidity, uint256 withdrawn0, uint256 withdrawn1, uint256 fees0, uint256 fees1) = depositor.withdraw(dp, true); + vm.revertTo(snapshot); + + vm.expectEmit(true, true, true, true); + emit Withdraw(FACILITATOR, DAI, USDC, liquidity, withdrawn0, withdrawn1, fees0, fees1); + vm.prank(FACILITATOR); depositor.withdraw(dp, false); + + // due to liquidity from amounts calculation there is rounding dust + assertGe(withdrawn0 * 100001 / 100000, deposited0); + assertGe(withdrawn1 * 100001 / 100000, deposited1); + assertEq(GemLike(DAI).balanceOf(address(depositor)), 0); + assertEq(GemLike(USDC).balanceOf(address(depositor)), 0); + assertLt(_getLiquidity(DAI, USDC, 100, REF_TICK-100, REF_TICK+100), liquidityBeforeWithdraw); + assertEq(fees0, 0); + assertEq(fees1, 0); + assertGt(liquidity, 0); + } + + function testDepositWrongGemOrder() public { + DepositorUniV3.LiquidityParams memory dp = DepositorUniV3.LiquidityParams({ + gem0: USDC, + gem1: DAI, + fee: uint24(100), + tickLower: REF_TICK-100, + tickUpper: REF_TICK+100, + liquidity: 0, + amt0Desired: 0, + amt1Desired: 0, + amt0Min: 0, + amt1Min: 0 + }); + vm.expectRevert("DepositorUniV3/wrong-gem-order"); + vm.prank(FACILITATOR); depositor.deposit(dp); + } + + function testDepositExceedingAmt() public { + DepositorUniV3.LiquidityParams memory dp = DepositorUniV3.LiquidityParams({ + gem0: DAI, + gem1: USDC, + fee: uint24(100), + tickLower: REF_TICK-100, + tickUpper: REF_TICK+100, + liquidity: 0, + amt0Desired: 2 * uint128(1 * WAD), + amt1Desired: 2 * uint128(1 * 10**6), + amt0Min: 0, + amt1Min: 0 + }); + depositor.setLimits(DAI, USDC, 100, uint96(1 * WAD), type(uint96).max, 3600); + + vm.expectRevert("DepositorUniV3/exceeds-due-amt"); + vm.prank(FACILITATOR); depositor.deposit(dp); + + depositor.setLimits(DAI, USDC, 100, type(uint96).max, 1 * 10**6, 3600); + + vm.expectRevert("DepositorUniV3/exceeds-due-amt"); + vm.prank(FACILITATOR); depositor.deposit(dp); + + depositor.setLimits(DAI, USDC, 100, type(uint96).max, type(uint96).max, 3600); + + vm.prank(FACILITATOR); depositor.deposit(dp); + } + + function testDepositExceedingSlippage() public { + DepositorUniV3.LiquidityParams memory dp = DepositorUniV3.LiquidityParams({ + gem0: DAI, + gem1: USDC, + fee: uint24(100), + tickLower: REF_TICK-100, + tickUpper: REF_TICK+100, + liquidity: 0, + amt0Desired: 500 * WAD, + amt1Desired: 500 * 10**6, + amt0Min: 3 * 500 * WAD, + amt1Min: 0 + }); + + vm.expectRevert("DepositorUniV3/exceeds-slippage"); + vm.prank(FACILITATOR); depositor.deposit(dp); + + dp.amt0Min = 0; + dp.amt1Min = 3 * 500 * 10**6; + + vm.expectRevert("DepositorUniV3/exceeds-slippage"); + vm.prank(FACILITATOR); depositor.deposit(dp); + } + + function testWithdrawWrongGemOrder() public { + DepositorUniV3.LiquidityParams memory dp = DepositorUniV3.LiquidityParams({ + gem0: USDC, + gem1: DAI, + fee: uint24(100), + tickLower: REF_TICK-100, + tickUpper: REF_TICK+100, + liquidity: 0, + amt0Desired: 0, + amt1Desired: 0, + amt0Min: 0, + amt1Min: 0 + }); + + vm.expectRevert("DepositorUniV3/wrong-gem-order"); + vm.prank(FACILITATOR); depositor.withdraw(dp, false); + } + + function testWithdrawNoPosition() public { + DepositorUniV3.LiquidityParams memory dp = DepositorUniV3.LiquidityParams({ + gem0: DAI, + gem1: USDC, + fee: uint24(100), + tickLower: REF_TICK-100, + tickUpper: REF_TICK+100, + liquidity: 1, + amt0Desired: 0, + amt1Desired: 0, + amt0Min: 0, + amt1Min: 0 + }); + + // "Liquidity Sub" error - https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/contracts/libraries/LiquidityMath.sol#L12 + vm.expectRevert(bytes("LS")); + vm.prank(FACILITATOR); depositor.withdraw(dp, false); + } + + function testWithdrawExceedingAmt() public { + DepositorUniV3.LiquidityParams memory dp = DepositorUniV3.LiquidityParams({ + gem0: DAI, + gem1: USDC, + fee: uint24(100), + tickLower: REF_TICK-100, + tickUpper: REF_TICK+100, + liquidity: 0, + amt0Desired: 2 * WAD, + amt1Desired: 2 * 10**6, + amt0Min: 0, + amt1Min: 0 + }); + vm.prank(FACILITATOR); (uint128 liq,,) = depositor.deposit(dp); + dp.liquidity = liq; + vm.warp(block.timestamp + 3600); + + depositor.setLimits(DAI, USDC, 100, type(uint96).max, 1 * 10**6, 3600); + + vm.expectRevert("DepositorUniV3/exceeds-due-amt"); + vm.prank(FACILITATOR); depositor.withdraw(dp, false); + + depositor.setLimits(DAI, USDC, 100, uint96(1 * WAD), type(uint96).max, 3600); + + vm.expectRevert("DepositorUniV3/exceeds-due-amt"); + vm.prank(FACILITATOR); depositor.withdraw(dp, false); + + depositor.setLimits(DAI, USDC, 100, type(uint96).max, type(uint96).max, 3600); + + vm.prank(FACILITATOR); depositor.withdraw(dp, false); + } + + function testWithdrawExceedingSlippage() public { + DepositorUniV3.LiquidityParams memory dp = DepositorUniV3.LiquidityParams({ + gem0: DAI, + gem1: USDC, + fee: uint24(100), + tickLower: REF_TICK-100, + tickUpper: REF_TICK+100, + liquidity: 0, + amt0Desired: 500 * WAD, + amt1Desired: 500 * 10**6, + amt0Min: 0, + amt1Min: 0 + }); + vm.prank(FACILITATOR); (uint128 liq,,) = depositor.deposit(dp); + dp.liquidity = liq; + vm.warp(block.timestamp + 3600); + dp.amt0Min = 3 * 500 * WAD; + + vm.expectRevert("DepositorUniV3/exceeds-slippage"); + vm.prank(FACILITATOR); depositor.withdraw(dp, false); + + dp.amt0Min = 0; + dp.amt1Min = 3 * 500 * 10**6; + + vm.expectRevert("DepositorUniV3/exceeds-slippage"); + vm.prank(FACILITATOR); depositor.withdraw(dp, false); + } + + function testCollectWrongGemOrder() public { + DepositorUniV3.CollectParams memory cp = DepositorUniV3.CollectParams({ + gem0: USDC, + gem1: DAI, + fee: uint24(100), + tickLower: REF_TICK-100, + tickUpper: REF_TICK+100 + }); + + vm.expectRevert("DepositorUniV3/wrong-gem-order"); + vm.prank(FACILITATOR); depositor.collect(cp); + } + + function testCollectNoPosition() public { + DepositorUniV3.CollectParams memory cp = DepositorUniV3.CollectParams({ + gem0: DAI, + gem1: USDC, + fee: uint24(100), + tickLower: REF_TICK-100, + tickUpper: REF_TICK+100 + }); + + // 0 liquidity position - https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/contracts/libraries/Position.sol#L54 + vm.expectRevert(bytes("NP")); + vm.prank(FACILITATOR); depositor.collect(cp); + } + + function testMintCallback() public { + uint256 initialDAI = GemLike(DAI).balanceOf(address(buffer)); + uint256 initialPoolDAI = GemLike(DAI).balanceOf(DAI_USDC_POOL); + uint256 initialUSDC = GemLike(USDC).balanceOf(address(buffer)); + uint256 initialPoolUSDC = GemLike(USDC).balanceOf(DAI_USDC_POOL); + + vm.prank(DAI_USDC_POOL); + depositor.uniswapV3MintCallback({ + amt0Owed: 1, + amt1Owed: 2, + data: abi.encode(DepositorUniV3.MintCallbackData({gem0: DAI, gem1: USDC, fee: 100})) + }); + + assertEq(GemLike(DAI).balanceOf(address(buffer)), initialDAI - 1); + assertEq(GemLike(USDC).balanceOf(address(buffer)), initialUSDC - 2); + assertEq(GemLike(DAI).balanceOf(DAI_USDC_POOL), initialPoolDAI + 1); + assertEq(GemLike(USDC).balanceOf(DAI_USDC_POOL), initialPoolUSDC + 2); + } + + function testMintCallbackNotFromPool() public { + vm.expectRevert("DepositorUniV3/sender-not-a-pool"); + depositor.uniswapV3MintCallback({ + amt0Owed: 1, + amt1Owed: 2, + data: abi.encode(DepositorUniV3.MintCallbackData({gem0: DAI, gem1: USDC, fee: 100})) + }); + } +} diff --git a/test/funnels/Swapper.t.sol b/test/funnels/Swapper.t.sol new file mode 100644 index 00000000..976048e5 --- /dev/null +++ b/test/funnels/Swapper.t.sol @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.8.16; + +import "dss-test/DssTest.sol"; +import { Swapper } from "src/funnels/Swapper.sol"; +import { SwapperCalleeUniV3 } from "src/funnels/callees/SwapperCalleeUniV3.sol"; +import { AllocatorRoles } from "src/AllocatorRoles.sol"; +import { AllocatorBuffer } from "src/AllocatorBuffer.sol"; + +interface GemLike { + function balanceOf(address) external view returns (uint256); + function transfer(address, uint256) external; +} + +contract CalleeMock is DssTest { + function swap(address src, address dst, uint256 amt, uint256, address to, bytes calldata) external { + GemLike(src).transfer(address(0xDEAD), amt); + deal(dst, address(this), amt, true); + GemLike(dst).transfer(to, amt); + } +} + +contract SwapperTest is DssTest { + event SetLimits(address indexed src, address indexed dst, uint96 cap, uint32 era); + event Swap(address indexed sender, address indexed src, address indexed dst, uint256 amt, uint256 out); + + AllocatorRoles public roles; + AllocatorBuffer public buffer; + Swapper public swapper; + SwapperCalleeUniV3 public uniV3Callee; + + bytes32 constant ilk = "aaa"; + bytes constant USDC_DAI_PATH = abi.encodePacked(USDC, uint24(100), DAI); + bytes constant DAI_USDC_PATH = abi.encodePacked(DAI, uint24(100), USDC); + + address constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F; + address constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + address constant UNIV3_ROUTER = 0xE592427A0AEce92De3Edee1F18E0157C05861564; + + address constant FACILITATOR = address(0x1337); + address constant KEEPER = address(0xb0b); + + uint8 constant SWAPPER_ROLE = uint8(1); + + function setUp() public { + vm.createSelectFork(vm.envString("ETH_RPC_URL")); + + buffer = new AllocatorBuffer(); + roles = new AllocatorRoles(); + swapper = new Swapper(address(roles), ilk, address(buffer)); + uniV3Callee = new SwapperCalleeUniV3(UNIV3_ROUTER); + + roles.setIlkAdmin(ilk, address(this)); + roles.setRoleAction(ilk, SWAPPER_ROLE, address(swapper), swapper.swap.selector, true); + roles.setUserRole(ilk, FACILITATOR, SWAPPER_ROLE, true); + + swapper.setLimits(DAI, USDC, uint96(10_000 * WAD), 3600 seconds); + swapper.setLimits(USDC, DAI, uint96(10_000 * 10**6), 3600 seconds); + + deal(DAI, address(buffer), 1_000_000 * WAD, true); + deal(USDC, address(buffer), 1_000_000 * 10**6, true); + buffer.approve(USDC, address(swapper), type(uint256).max); + buffer.approve(DAI, address(swapper), type(uint256).max); + } + + function testConstructor() public { + Swapper s = new Swapper(address(0xBEEF), "SubDAO 1", address(0xAAA)); + assertEq(address(s.roles()), address(0xBEEF)); + assertEq(s.ilk(), "SubDAO 1"); + assertEq(s.buffer(), address(0xAAA)); + assertEq(s.wards(address(this)), 1); + } + + function testAuth() public { + checkAuth(address(swapper), "Swapper"); + } + + function testModifiers() public { + bytes4[] memory authedMethods = new bytes4[](2); + authedMethods[0] = swapper.setLimits.selector; + authedMethods[1] = swapper.swap.selector; + + vm.startPrank(address(0xBEEF)); + checkModifier(address(swapper), "Swapper/not-authorized", authedMethods); + vm.stopPrank(); + } + + function testSetLimits() public { + // swap to make sure due and end are set + vm.prank(FACILITATOR); swapper.swap(USDC, DAI, 1_000 * 10**6, 990 * WAD, address(uniV3Callee), USDC_DAI_PATH); + (,, uint96 dueBefore, uint32 endBefore) = swapper.limits(USDC, DAI); + assertGt(endBefore, 0); + assertGt(dueBefore, 0); + + vm.warp(block.timestamp + 1 hours); + + vm.expectEmit(true, true, true, true); + emit SetLimits(USDC, DAI, 4, 3); + vm.prank(address(this)); swapper.setLimits(USDC, DAI, 4, 3); + (uint96 cap, uint32 era, uint96 due, uint32 end) = swapper.limits(USDC, DAI); + assertEq(cap, 4); + assertEq(era, 3); + assertEq(due, 0); + assertEq(end, 0); + } + + function testRoles() public { + vm.expectRevert("Swapper/not-authorized"); + vm.prank(address(0xBEEF)); swapper.setLimits(address(0), address(0), 0, 0); + roles.setRoleAction(ilk, uint8(0xF1), address(swapper), swapper.setLimits.selector, true); + roles.setUserRole(ilk, address(0xBEEF), uint8(0xF1), true); + vm.prank(address(0xBEEF)); swapper.setLimits(address(0), address(0), 0, 0); + } + + function testSwap() public { + uint256 prevSrc = GemLike(USDC).balanceOf(address(buffer)); + uint256 prevDst = GemLike(DAI).balanceOf(address(buffer)); + + uint32 initialTime = uint32(block.timestamp); + + uint256 snapshot = vm.snapshot(); + vm.prank(FACILITATOR); uint256 expectedOut = swapper.swap(USDC, DAI, 1_000 * 10**6, 990 * WAD, address(uniV3Callee), USDC_DAI_PATH); + vm.revertTo(snapshot); + + vm.expectEmit(true, true, true, true); + emit Swap(FACILITATOR, USDC, DAI, 1_000 * 10**6, expectedOut); + vm.prank(FACILITATOR); uint256 out = swapper.swap(USDC, DAI, 1_000 * 10**6, 990 * WAD, address(uniV3Callee), USDC_DAI_PATH); + + assertGe(out, 990 * WAD); + assertEq(GemLike(USDC).balanceOf(address(buffer)), prevSrc - 1_000 * 10**6); + assertEq(GemLike(DAI).balanceOf(address(buffer)), prevDst + out); + assertEq(GemLike(DAI).balanceOf(address(swapper)), 0); + assertEq(GemLike(USDC).balanceOf(address(swapper)), 0); + assertEq(GemLike(DAI).balanceOf(address(uniV3Callee)), 0); + assertEq(GemLike(USDC).balanceOf(address(uniV3Callee)), 0); + (,, uint96 due, uint32 end) = swapper.limits(USDC, DAI); + assertEq(due, 9_000 * 10**6); + assertEq(end, initialTime + 3600); + + vm.warp(initialTime + 1800); + vm.prank(FACILITATOR); swapper.swap(USDC, DAI, 5_000 * 10**6, 4_950 * WAD, address(uniV3Callee), USDC_DAI_PATH); + (,, due, end) = swapper.limits(USDC, DAI); + assertEq(due, 4_000 * 10**6); + assertEq(end, initialTime + 3600); + + vm.expectRevert("Swapper/exceeds-due-amt"); + vm.prank(FACILITATOR); swapper.swap(USDC, DAI, 8_000 * 10**6, 7_920 * WAD, address(uniV3Callee), USDC_DAI_PATH); + + vm.warp(initialTime + 3600); + vm.prank(FACILITATOR); swapper.swap(USDC, DAI, 8_000 * 10**6, 7_920 * WAD, address(uniV3Callee), USDC_DAI_PATH); + (,, due, end) = swapper.limits(USDC, DAI); + assertEq(due, 2_000 * 10**6); + assertEq(end, initialTime + 7200); + + prevSrc = GemLike(DAI).balanceOf(address(buffer)); + prevDst = GemLike(USDC).balanceOf(address(buffer)); + + vm.expectEmit(true, true, true, false); + emit Swap(FACILITATOR, DAI, USDC, 1_000 * WAD, 0); + vm.prank(FACILITATOR); out = swapper.swap(DAI, USDC, 1_000 * WAD, 990 * 10**6, address(uniV3Callee), DAI_USDC_PATH); + + assertGe(out, 990 * 10**6); + assertEq(GemLike(DAI).balanceOf(address(buffer)), prevSrc - 1_000 * WAD); + assertEq(GemLike(USDC).balanceOf(address(buffer)), prevDst + out); + assertEq(GemLike(DAI).balanceOf(address(swapper)), 0); + assertEq(GemLike(USDC).balanceOf(address(swapper)), 0); + assertEq(GemLike(DAI).balanceOf(address(uniV3Callee)), 0); + assertEq(GemLike(USDC).balanceOf(address(uniV3Callee)), 0); + (,, due, end) = swapper.limits(DAI, USDC); + assertEq(due, 9_000 * WAD); + assertEq(end, initialTime + 7200); + } + + function testSwapAllAferEra() public { + vm.prank(FACILITATOR); swapper.swap(USDC, DAI, 10_000 * 10**6, 9900 * WAD, address(uniV3Callee), USDC_DAI_PATH); + (, uint64 era,,) = swapper.limits(USDC, DAI); + vm.warp(block.timestamp + era); + + vm.expectEmit(true, true, true, false); + emit Swap(FACILITATOR, USDC, DAI, 10_000 * 10**6, 0); + vm.prank(FACILITATOR); swapper.swap(USDC, DAI, 10_000 * 10**6, 9900 * WAD, address(uniV3Callee), USDC_DAI_PATH); + } + + function testSwapExceedingMax() public { + (uint128 cap,,,) = swapper.limits(USDC, DAI); + uint256 amt = cap + 1; + vm.expectRevert("Swapper/exceeds-due-amt"); + vm.prank(FACILITATOR); swapper.swap(USDC, DAI, amt, 0, address(uniV3Callee), USDC_DAI_PATH); + } + + function testSwapReceivingTooLittle() public { + CalleeMock callee = new CalleeMock(); + vm.expectRevert("Swapper/too-few-dst-received"); + vm.prank(FACILITATOR); swapper.swap(USDC, DAI, 100 * 10**6, 200 * WAD, address(callee), USDC_DAI_PATH); + } +} diff --git a/test/funnels/automation/ConduitMover.t.sol b/test/funnels/automation/ConduitMover.t.sol new file mode 100644 index 00000000..9f5f2bcb --- /dev/null +++ b/test/funnels/automation/ConduitMover.t.sol @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.8.16; + +import "dss-test/DssTest.sol"; +import { ConduitMover } from "src/funnels/automation/ConduitMover.sol"; +import { AllocatorRegistry } from "src/AllocatorRegistry.sol"; +import { AllocatorRoles } from "src/AllocatorRoles.sol"; +import { AllocatorBuffer } from "src/AllocatorBuffer.sol"; +import { AllocatorConduitMock } from "test/mocks/AllocatorConduitMock.sol"; + +interface GemLike { + function balanceOf(address) external view returns (uint256); +} + +contract ConduitMoverTest is DssTest { + event Kiss(address indexed usr); + event Diss(address indexed usr); + event SetConfig(address indexed from, address indexed to, address indexed gem, uint64 num, uint32 hop, uint128 lot); + event Move(address indexed from, address indexed to, address indexed gem, uint128 lot); + + address public buffer; + address public conduit1; + address public conduit2; + ConduitMover public mover; + + bytes32 constant ILK = "aaa"; + address constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + address constant FACILITATOR = address(0x1337); + address constant KEEPER = address(0xb0b); + uint8 constant MOVER_ROLE = uint8(1); + + function setUp() public { + vm.createSelectFork(vm.envString("ETH_RPC_URL")); + + buffer = address(new AllocatorBuffer()); + AllocatorRoles roles = new AllocatorRoles(); + AllocatorRegistry registry = new AllocatorRegistry(); + registry.file(ILK, "buffer", buffer); + + conduit1 = address(new AllocatorConduitMock(address(roles), address(registry))); + conduit2 = address(new AllocatorConduitMock(address(roles), address(registry))); + mover = new ConduitMover(ILK, buffer); + + // Allow mover to perform ILK operations on the conduits + roles.setIlkAdmin(ILK, address(this)); + roles.setRoleAction(ILK, MOVER_ROLE, conduit1, AllocatorConduitMock.deposit.selector, true); + roles.setRoleAction(ILK, MOVER_ROLE, conduit1, AllocatorConduitMock.withdraw.selector, true); + roles.setRoleAction(ILK, MOVER_ROLE, conduit2, AllocatorConduitMock.deposit.selector, true); + roles.setUserRole(ILK, address(mover), MOVER_ROLE, true); + + // Allow conduits to transfer out funds out of the buffer + AllocatorBuffer(buffer).approve(USDC, conduit1, type(uint256).max); + AllocatorBuffer(buffer).approve(USDC, conduit2, type(uint256).max); + + // Give conduit1 some funds + deal(USDC, buffer, 3_000 * 10**6, true); + vm.prank(address(mover)); AllocatorConduitMock(conduit1).deposit(ILK, USDC, 3_000 * 10**6); + + // Set up keeper to move from conduit1 to conduit2 + mover.rely(FACILITATOR); + vm.startPrank(FACILITATOR); + mover.kiss(KEEPER); + mover.setConfig(conduit1, conduit2, USDC, 10, 1 hours, uint128(1_000 * 10**6)); + vm.stopPrank(); + + // Confirm initial parameters and amounts + (uint64 num, uint32 hop, uint32 zzz, uint128 lot) = mover.configs(conduit1, conduit2, USDC); + assertEq(num, 10); + assertEq(hop, 1 hours); + assertEq(zzz, 0); + assertEq(lot, 1_000 * 10**6); + assertEq(GemLike(USDC).balanceOf(buffer), 0); + assertEq(GemLike(USDC).balanceOf(conduit1), 3_000 * 10**6); + assertEq(GemLike(USDC).balanceOf(conduit2), 0); + } + + function testConstructor() public { + ConduitMover m = new ConduitMover("xyz", address(0xABC)); + assertEq(m.ilk(), "xyz"); + assertEq(m.buffer(), address(0xABC)); + assertEq(m.wards(address(this)), 1); + } + + function testAuth() public { + checkAuth(address(mover), "ConduitMover"); + } + + function testModifiers() public { + bytes4[] memory authedMethods = new bytes4[](3); + authedMethods[0] = ConduitMover.kiss.selector; + authedMethods[1] = ConduitMover.diss.selector; + authedMethods[2] = ConduitMover.setConfig.selector; + + vm.startPrank(address(0xBEEF)); + checkModifier(address(mover), "ConduitMover/not-authorized", authedMethods); + vm.stopPrank(); + } + + function testKissDiss() public { + address testAddress = address(0x123); + assertEq(mover.buds(testAddress), 0); + + vm.expectEmit(true, true, true, true); + emit Kiss(testAddress); + mover.kiss(testAddress); + assertEq(mover.buds(testAddress), 1); + + vm.expectEmit(true, true, true, true); + emit Diss(testAddress); + mover.diss(testAddress); + assertEq(mover.buds(testAddress), 0); + } + + function testSetConfig() public { + vm.expectEmit(true, true, true, true); + emit SetConfig(address(0x123), address(0x456), address(0x789), uint64(23), uint32(360 seconds), uint96(314)); + mover.setConfig(address(0x123), address(0x456), address(0x789), uint64(23), uint32(360 seconds), uint96(314)); + + (uint64 num, uint32 hop, uint32 zzz, uint128 lot) = mover.configs(address(0x123), address(0x456), address(0x789)); + assertEq(num, 23); + assertEq(hop, 360); + assertEq(zzz, 0); + assertEq(lot, 314); + } + + function testMoveByKeeper() public { + vm.expectEmit(true, true, true, true); + emit Move(conduit1, conduit2, USDC, 1_000 * 10**6); + vm.prank(KEEPER); mover.move(conduit1, conduit2, USDC); + + assertEq(GemLike(USDC).balanceOf(conduit1), 2_000 * 10**6); + assertEq(GemLike(USDC).balanceOf(conduit2), 1_000 * 10**6); + assertEq(GemLike(USDC).balanceOf(buffer), 0); + (uint64 num, uint32 hop, uint32 zzz, uint128 lot) = mover.configs(conduit1, conduit2, USDC); + assertEq(num, 9); + assertEq(hop, 1 hours); + assertEq(zzz, block.timestamp); + assertEq(lot, 1_000 * 10**6); + + vm.warp(block.timestamp + 1 hours - 1); + vm.expectRevert("ConduitMover/too-soon"); + vm.prank(KEEPER); mover.move(conduit1, conduit2, USDC); + + vm.warp(block.timestamp + 1); + vm.prank(KEEPER); mover.move(conduit1, conduit2, USDC); + + assertEq(GemLike(USDC).balanceOf(conduit1), 1_000 * 10**6); + assertEq(GemLike(USDC).balanceOf(conduit2), 2_000 * 10**6); + assertEq(GemLike(USDC).balanceOf(buffer), 0); + (num, hop, zzz, lot) = mover.configs(conduit1, conduit2, USDC); + assertEq(num, 8); + assertEq(hop, 1 hours); + assertEq(zzz, block.timestamp); + assertEq(lot, 1_000 * 10**6); + } + + function testMoveNonKeeper() public { + assertEq(mover.buds(address(this)), 0); + vm.expectRevert("ConduitMover/non-keeper"); + mover.move(conduit1, conduit2, USDC); + } + + function testMoveExceedingNum() public { + vm.expectRevert("ConduitMover/exceeds-num"); + vm.prank(KEEPER); mover.move(conduit1, conduit2, address(0x123)); + } +} diff --git a/test/funnels/automation/StableDepositorUniV3.t.sol b/test/funnels/automation/StableDepositorUniV3.t.sol new file mode 100644 index 00000000..6eea77a5 --- /dev/null +++ b/test/funnels/automation/StableDepositorUniV3.t.sol @@ -0,0 +1,274 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.8.16; + +import "dss-test/DssTest.sol"; +import { DepositorUniV3 } from "src/funnels/DepositorUniV3.sol"; +import { StableDepositorUniV3 } from "src/funnels/automation/StableDepositorUniV3.sol"; +import { AllocatorRoles } from "src/AllocatorRoles.sol"; +import { AllocatorBuffer } from "src/AllocatorBuffer.sol"; + +interface GemLike { + function balanceOf(address) external view returns (uint256); + function transfer(address, uint256) external; + function approve(address, uint256) external; +} + +interface SwapRouterLike { + function exactInput(ExactInputParams calldata params) external returns (uint256 amountOut); + + struct ExactInputParams { + bytes path; + address recipient; + uint256 deadline; + uint256 amountIn; + uint256 amountOutMinimum; + } +} + +contract StableDepositorUniV3Test is DssTest { + event Kiss(address indexed usr); + event Diss(address indexed usr); + event SetConfig(address indexed gem0, address indexed gem1, uint24 indexed fee, int24 tickLower, int24 tickUpper, int32 num, uint32 hop, uint96 amt0, uint96 amt1, uint96 req0, uint96 req1); + + AllocatorBuffer public buffer; + DepositorUniV3 public depositor; + StableDepositorUniV3 public stableDepositor; + + bytes32 constant ilk = "aaa"; + bytes constant DAI_USDC_PATH = abi.encodePacked(DAI, uint24(100), USDC); + + address constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F; + address constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + address constant UNIV3_ROUTER = 0xE592427A0AEce92De3Edee1F18E0157C05861564; + address constant UNIV3_FACTORY = 0x1F98431c8aD98523631AE4a59f267346ea31F984; + + address constant FACILITATOR = address(0x1337); + address constant KEEPER = address(0xb0b); + + uint8 constant DEPOSITOR_ROLE = uint8(1); + + int24 constant REF_TICK = -276324; // tick corresponding to 1 DAI = 1 USDC calculated as ~= math.log(10**(-12))/math.log(1.0001) + + function setUp() public { + vm.createSelectFork(vm.envString("ETH_RPC_URL")); + + buffer = new AllocatorBuffer(); + AllocatorRoles roles = new AllocatorRoles(); + depositor = new DepositorUniV3(address(roles), ilk, UNIV3_FACTORY, address(buffer)); + stableDepositor = new StableDepositorUniV3(address(depositor)); + + roles.setIlkAdmin(ilk, address(this)); + roles.setRoleAction(ilk, DEPOSITOR_ROLE, address(depositor), depositor.deposit.selector, true); + roles.setRoleAction(ilk, DEPOSITOR_ROLE, address(depositor), depositor.withdraw.selector, true); + roles.setRoleAction(ilk, DEPOSITOR_ROLE, address(depositor), depositor.collect.selector, true); + roles.setUserRole(ilk, FACILITATOR, DEPOSITOR_ROLE, true); + roles.setUserRole(ilk, address(stableDepositor), DEPOSITOR_ROLE, true); + + depositor.setLimits(DAI, USDC, 100, uint96(10_000 * WAD), uint96(10_000 * 10**6), 3600 seconds); + + deal(DAI, address(buffer), 1_000_000 * WAD, true); + deal(USDC, address(buffer), 1_000_000 * 10**6, true); + buffer.approve(USDC, address(depositor), type(uint256).max); + buffer.approve(DAI, address(depositor), type(uint256).max); + + stableDepositor.rely(FACILITATOR); + vm.startPrank(FACILITATOR); + stableDepositor.setConfig(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, 10, 360, uint96(500 * WAD), uint96(500 * 10**6), uint96(490 * WAD), uint96(490 * 10**6)); + + stableDepositor.kiss(KEEPER); + vm.stopPrank(); + } + + function testConstructor() public { + StableDepositorUniV3 s = new StableDepositorUniV3(address(0xABC)); + assertEq(address(s.depositor()), address(0xABC)); + assertEq(s.wards(address(this)), 1); + } + + function testAuth() public { + checkAuth(address(stableDepositor), "StableDepositorUniV3"); + } + + function testModifiers() public { + bytes4[] memory authedMethods = new bytes4[](3); + authedMethods[0] = stableDepositor.kiss.selector; + authedMethods[1] = stableDepositor.diss.selector; + authedMethods[2] = stableDepositor.setConfig.selector; + + vm.startPrank(address(0xBEEF)); + checkModifier(address(stableDepositor), "StableDepositorUniV3/not-authorized", authedMethods); + vm.stopPrank(); + } + + function testKissDiss() public { + address testAddress = address(0x123); + + assertEq(stableDepositor.buds(testAddress), 0); + vm.expectEmit(true, true, true, true); + emit Kiss(testAddress); + stableDepositor.kiss(testAddress); + assertEq(stableDepositor.buds(testAddress), 1); + vm.expectEmit(true, true, true, true); + emit Diss(testAddress); + stableDepositor.diss(testAddress); + assertEq(stableDepositor.buds(testAddress), 0); + } + + function testSetConfig() public { + vm.expectRevert("StableDepositorUniV3/wrong-gem-order"); + stableDepositor.setConfig(address(0x456), address(0x123), uint24(314), 5, 6, 23, 3600, uint96(7), uint96(8), uint96(9), uint96(10)); + + vm.expectEmit(true, true, true, true); + emit SetConfig(address(0x123), address(0x456), uint24(314), 5, 6, 23, 3600, uint96(7), uint96(8), uint96(9), uint96(10)); + stableDepositor.setConfig(address(0x123), address(0x456), uint24(314), 5, 6, 23, 3600, uint96(7), uint96(8), uint96(9), uint96(10)); + + ( + int32 num, + uint32 zzz, + uint96 amt0, + uint96 amt1, + uint96 req0, + uint96 req1, + uint32 hop + ) = stableDepositor.configs(address(0x123), address(0x456), uint24(314), 5, 6); + assertEq(num, 23); + assertEq(zzz, 0); + assertEq(amt0, uint96(7)); + assertEq(amt1, uint96(8)); + assertEq(req0, uint96(9)); + assertEq(req1, uint96(10)); + assertEq(hop, 3600); + } + + function testDepositWithdrawByKeeper() public { + uint256 prevDai = GemLike(DAI).balanceOf(address(buffer)); + uint256 prevUsdc = GemLike(USDC).balanceOf(address(buffer)); + (int32 initNum,,,,,,) = stableDepositor.configs(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100); + assertEq(initNum, 10); + uint32 initialTime = uint32(block.timestamp); + + vm.prank(KEEPER); stableDepositor.deposit(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, uint128(491 * WAD), uint128(491 * 10**6)); + + uint256 afterDepositDai = GemLike(DAI).balanceOf(address(buffer)); + uint256 afterDepositUsdc = GemLike(USDC).balanceOf(address(buffer)); + (int32 num, uint32 zzz,,,,,) = stableDepositor.configs(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100); + assertLt(afterDepositDai, prevDai); + assertLt(afterDepositUsdc, prevUsdc); + assertEq(num, initNum - 1); + assertEq(zzz, initialTime); + + vm.warp(initialTime + 180); + vm.expectRevert("StableDepositorUniV3/too-soon"); + vm.prank(KEEPER); stableDepositor.deposit(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, uint128(491 * WAD), uint128(491 * 10**6)); + + vm.warp(initialTime + 360); + vm.prank(KEEPER); stableDepositor.deposit(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, uint128(491 * WAD), uint128(491 * 10**6)); + (num, zzz,,,,,) = stableDepositor.configs(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100); + + assertEq(num, initNum - 2); + assertEq(zzz, initialTime + 360); + + stableDepositor.setConfig(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, -10, 360, uint96(500 * WAD), uint96(500 * 10**6), uint96(490 * WAD), uint96(490 * 10**6)); + (initNum,,,,,,) = stableDepositor.configs(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100); + assertEq(initNum, -10); + + vm.prank(KEEPER); stableDepositor.withdraw(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, uint128(491 * WAD), uint128(491 * 10**6)); + (num, zzz,,,,,) = stableDepositor.configs(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100); + assertEq(num, initNum + 1); + assertEq(zzz, initialTime + 360); + + vm.warp(initialTime + 540); + vm.expectRevert("StableDepositorUniV3/too-soon"); + vm.prank(KEEPER); stableDepositor.withdraw(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, uint128(491 * WAD), uint128(491 * 10**6)); + + vm.warp(initialTime + 720); + vm.prank(KEEPER); stableDepositor.withdraw(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, uint128(491 * WAD), uint128(491 * 10**6)); + (num, zzz,,,,,) = stableDepositor.configs(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100); + + assertGt(GemLike(DAI).balanceOf(address(buffer)), afterDepositDai); + assertGt(GemLike(USDC).balanceOf(address(buffer)), afterDepositUsdc); + assertEq(num, initNum + 2); + assertEq(zzz, initialTime + 720); + } + + function testDepositWithdrawMinZero() public { + uint256 prevDai = GemLike(DAI).balanceOf(address(buffer)); + uint256 prevUsdc = GemLike(USDC).balanceOf(address(buffer)); + + vm.prank(KEEPER); stableDepositor.deposit(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, 0, 0); + + uint256 afterDepositDai = GemLike(DAI).balanceOf(address(buffer)); + uint256 afterDepositUsdc = GemLike(USDC).balanceOf(address(buffer)); + assertLt(afterDepositDai, prevDai); + assertLt(afterDepositUsdc, prevUsdc); + + stableDepositor.setConfig(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, -10, 360, uint96(500 * WAD), uint96(500 * 10**6), uint96(490 * WAD), uint96(490 * 10**6)); + vm.prank(KEEPER); stableDepositor.withdraw(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, 0, 0); + + assertGt(GemLike(DAI).balanceOf(address(buffer)), afterDepositDai); + assertGt(GemLike(USDC).balanceOf(address(buffer)), afterDepositUsdc); + } + + function testDepositWithdrawExceedingNum() public { + stableDepositor.setConfig(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, -10, 360, uint96(500 * WAD), uint96(500 * 10**6), uint96(490 * WAD), uint96(490 * 10**6)); + vm.expectRevert("StableDepositorUniV3/exceeds-num"); + vm.prank(KEEPER); stableDepositor.deposit(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, uint128(491 * 10**6), uint128(491 * WAD)); + + stableDepositor.setConfig(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, 10, 360, uint96(500 * WAD), uint96(500 * 10**6), uint96(490 * WAD), uint96(490 * 10**6)); + vm.expectRevert("StableDepositorUniV3/exceeds-num"); + vm.prank(KEEPER); stableDepositor.withdraw(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, uint128(491 * 10**6), uint128(491 * WAD)); + } + + function testDepositWithMin0TooSmall() public { + (,,,,, uint96 req0,) = stableDepositor.configs(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100); + + vm.expectRevert("StableDepositorUniV3/min-amt0-too-small"); + vm.prank(KEEPER); stableDepositor.deposit(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, req0 - 1, uint128(491 * 10**6)); + } + + function testDepositWithMin1TooSmall() public { + (,,,,,, uint96 req1) = stableDepositor.configs(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100); + + vm.expectRevert("StableDepositorUniV3/min-amt1-too-small"); + vm.prank(KEEPER); stableDepositor.deposit(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, uint128(491 * WAD), req1 - 1); + } + + function testCollectByKeeper() public { + vm.prank(KEEPER); stableDepositor.deposit(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, uint128(491 * WAD), uint128(491 * 10**6)); + + uint256 prevDai = GemLike(DAI).balanceOf(address(buffer)); + uint256 prevUsdc = GemLike(USDC).balanceOf(address(buffer)); + + // execute a trade to generate fees for the LP position + deal(DAI, address(this), 1_000_000 * WAD, true); + GemLike(DAI).approve(UNIV3_ROUTER, 1_000_000 * WAD); + SwapRouterLike.ExactInputParams memory params = SwapRouterLike.ExactInputParams({ + path: DAI_USDC_PATH, + recipient: address(this), + deadline: block.timestamp, + amountIn: 1_000_000 * WAD, + amountOutMinimum: 990_000 * 10**6 + }); + SwapRouterLike(UNIV3_ROUTER).exactInput(params); + + vm.prank(KEEPER); (uint256 fees0, uint256 fees1) = stableDepositor.collect(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100); + + assertTrue(fees0 > 0 || fees1 > 0); + assertEq(GemLike(DAI).balanceOf(address(buffer)), prevDai + fees0); + assertEq(GemLike(USDC).balanceOf(address(buffer)), prevUsdc + fees1); + } + + function testOperationsNonKeeper() public { + assertEq(stableDepositor.buds(address(this)), 0); + + vm.expectRevert("StableDepositorUniV3/non-keeper"); + stableDepositor.deposit(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, uint128(491 * WAD), uint128(491 * 10**6)); + + vm.expectRevert("StableDepositorUniV3/non-keeper"); + stableDepositor.withdraw(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, uint128(491 * WAD), uint128(491 * 10**6)); + + vm.expectRevert("StableDepositorUniV3/non-keeper"); + vm.prank(address(0x123)); stableDepositor.collect(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100); + } +} diff --git a/test/funnels/automation/StableSwapper.t.sol b/test/funnels/automation/StableSwapper.t.sol new file mode 100644 index 00000000..6c6dd4ec --- /dev/null +++ b/test/funnels/automation/StableSwapper.t.sol @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.8.16; + +import "dss-test/DssTest.sol"; +import { Swapper, GemLike } from "src/funnels/Swapper.sol"; +import { StableSwapper } from "src/funnels/automation/StableSwapper.sol"; +import { SwapperCalleeUniV3 } from "src/funnels/callees/SwapperCalleeUniV3.sol"; +import { AllocatorRoles } from "src/AllocatorRoles.sol"; +import { AllocatorBuffer } from "src/AllocatorBuffer.sol"; + +contract StableSwapperTest is DssTest { + event Kiss(address indexed usr); + event Diss(address indexed usr); + event SetConfig(address indexed src, address indexed dst, uint128 num, uint32 hop, uint96 lot, uint96 req); + event Swap(address indexed sender, address indexed src, address indexed dst, uint256 amt, uint256 out); + + AllocatorBuffer public buffer; + Swapper public swapper; + StableSwapper public stableSwapper; + SwapperCalleeUniV3 public uniV3Callee; + + bytes32 constant ilk = "aaa"; + bytes constant USDC_DAI_PATH = abi.encodePacked(USDC, uint24(100), DAI); + bytes constant DAI_USDC_PATH = abi.encodePacked(DAI, uint24(100), USDC); + + address constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F; + address constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + address constant UNIV3_ROUTER = 0xE592427A0AEce92De3Edee1F18E0157C05861564; + + address constant FACILITATOR = address(0x1337); + address constant KEEPER = address(0xb0b); + + uint8 constant SWAPPER_ROLE = uint8(1); + + function setUp() public { + vm.createSelectFork(vm.envString("ETH_RPC_URL")); + + buffer = new AllocatorBuffer(); + AllocatorRoles roles = new AllocatorRoles(); + swapper = new Swapper(address(roles), ilk, address(buffer)); + uniV3Callee = new SwapperCalleeUniV3(UNIV3_ROUTER); + stableSwapper = new StableSwapper(address(swapper)); + + roles.setIlkAdmin(ilk, address(this)); + roles.setRoleAction(ilk, SWAPPER_ROLE, address(swapper), swapper.swap.selector, true); + roles.setUserRole(ilk, FACILITATOR, SWAPPER_ROLE, true); + roles.setUserRole(ilk, address(stableSwapper), SWAPPER_ROLE, true); + + swapper.setLimits(DAI, USDC, uint96(10_000 * WAD), 3600 seconds); + swapper.setLimits(USDC, DAI, uint96(10_000 * 10**6), 3600 seconds); + + deal(DAI, address(buffer), 1_000_000 * WAD, true); + deal(USDC, address(buffer), 1_000_000 * 10**6, true); + buffer.approve(USDC, address(swapper), type(uint256).max); + buffer.approve(DAI, address(swapper), type(uint256).max); + + stableSwapper.rely(FACILITATOR); + vm.startPrank(FACILITATOR); + stableSwapper.setConfig(DAI, USDC, 10, 360 seconds, uint96(1_000 * WAD), uint96(990 * 10**6)); + stableSwapper.setConfig(USDC, DAI, 10, 360 seconds, uint96(1_000 * 10**6), uint96(990 * WAD)); + stableSwapper.kiss(KEEPER); + vm.stopPrank(); + } + + function testConstructor() public { + StableSwapper s = new StableSwapper(address(0xABC)); + assertEq(address(s.swapper()), address(0xABC)); + assertEq(s.wards(address(this)), 1); + } + + function testAuth() public { + checkAuth(address(stableSwapper), "StableSwapper"); + } + + function testModifiers() public { + bytes4[] memory authedMethods = new bytes4[](3); + authedMethods[0] = stableSwapper.kiss.selector; + authedMethods[1] = stableSwapper.diss.selector; + authedMethods[2] = stableSwapper.setConfig.selector; + + vm.startPrank(address(0xBEEF)); + checkModifier(address(stableSwapper), "StableSwapper/not-authorized", authedMethods); + vm.stopPrank(); + } + + function testKissDiss() public { + address testAddress = address(0x123); + + assertEq(stableSwapper.buds(testAddress), 0); + vm.expectEmit(true, true, true, true); + emit Kiss(testAddress); + stableSwapper.kiss(testAddress); + assertEq(stableSwapper.buds(testAddress), 1); + vm.expectEmit(true, true, true, true); + emit Diss(testAddress); + stableSwapper.diss(testAddress); + assertEq(stableSwapper.buds(testAddress), 0); + } + + function testSetConfig() public { + vm.expectEmit(true, true, true, true); + emit SetConfig(address(0x123), address(0x456), uint128(23), uint32(360 seconds), uint96(314), uint96(42)); + stableSwapper.setConfig(address(0x123), address(0x456), uint128(23), uint32(360 seconds), uint96(314), uint96(42)); + + (uint128 num, uint32 hop, uint32 zzz, uint96 lot, uint96 req) = stableSwapper.configs(address(0x123), address(0x456)); + assertEq(num, 23); + assertEq(hop, 360); + assertEq(zzz, 0); + assertEq(lot, 314); + assertEq(req, 42); + } + + function testSwapByKeeper() public { + uint256 prevSrc = GemLike(USDC).balanceOf(address(buffer)); + uint256 prevDst = GemLike(DAI).balanceOf(address(buffer)); + (uint128 initUsdcDaiNum,,,,) = stableSwapper.configs(USDC, DAI); + (uint128 initDaiUsdcNum,,,,) = stableSwapper.configs(DAI, USDC); + uint32 initialTime = uint32(block.timestamp); + + vm.expectEmit(true, true, true, false); + emit Swap(address(stableSwapper), USDC, DAI, 0, 0); + vm.prank(KEEPER); uint256 out = stableSwapper.swap(USDC, DAI, 990 * WAD, address(uniV3Callee), USDC_DAI_PATH); + + assertGe(out, 990 * WAD); + assertEq(GemLike(USDC).balanceOf(address(buffer)), prevSrc - 1_000 * 10**6); + assertEq(GemLike(DAI).balanceOf(address(buffer)), prevDst + out); + assertEq(GemLike(DAI).balanceOf(address(stableSwapper)), 0); + assertEq(GemLike(USDC).balanceOf(address(stableSwapper)), 0); + assertEq(GemLike(DAI).balanceOf(address(swapper)), 0); + assertEq(GemLike(USDC).balanceOf(address(swapper)), 0); + assertEq(GemLike(DAI).balanceOf(address(uniV3Callee)), 0); + assertEq(GemLike(USDC).balanceOf(address(uniV3Callee)), 0); + (uint128 usdcDaiNum,, uint32 usdcDaiZzz,,) = stableSwapper.configs(USDC, DAI); + assertEq(usdcDaiNum, initUsdcDaiNum - 1); + assertEq(usdcDaiZzz, initialTime); + + vm.warp(initialTime + 180); + vm.expectRevert("StableSwapper/too-soon"); + vm.prank(KEEPER); stableSwapper.swap(USDC, DAI, 990 * WAD, address(uniV3Callee), USDC_DAI_PATH); + + vm.warp(initialTime + 360); + vm.prank(KEEPER); stableSwapper.swap(USDC, DAI, 990 * WAD, address(uniV3Callee), USDC_DAI_PATH); + + (usdcDaiNum,, usdcDaiZzz,,) = stableSwapper.configs(USDC, DAI); + assertEq(usdcDaiNum, initUsdcDaiNum - 2); + assertEq(usdcDaiZzz, initialTime + 360); + + prevSrc = GemLike(DAI).balanceOf(address(buffer)); + prevDst = GemLike(USDC).balanceOf(address(buffer)); + + vm.expectEmit(true, true, true, false); + emit Swap(address(stableSwapper), DAI, USDC, 0, 0); + vm.prank(KEEPER); out = stableSwapper.swap(DAI, USDC, 990 * 10**6, address(uniV3Callee), DAI_USDC_PATH); + + assertGe(out, 990 * 10**6); + assertEq(GemLike(DAI).balanceOf(address(buffer)), prevSrc - 1_000 * WAD); + assertEq(GemLike(USDC).balanceOf(address(buffer)), prevDst + out); + assertEq(GemLike(DAI).balanceOf(address(stableSwapper)), 0); + assertEq(GemLike(USDC).balanceOf(address(stableSwapper)), 0); + assertEq(GemLike(DAI).balanceOf(address(swapper)), 0); + assertEq(GemLike(USDC).balanceOf(address(swapper)), 0); + assertEq(GemLike(DAI).balanceOf(address(uniV3Callee)), 0); + assertEq(GemLike(USDC).balanceOf(address(uniV3Callee)), 0); + (uint128 daiUsdcNum,, uint32 daiUsdcZzz,,) = stableSwapper.configs(DAI, USDC); + assertEq(daiUsdcNum, initDaiUsdcNum - 1); + assertEq(daiUsdcZzz, initialTime + 360); + } + + function testSwapMinZero() public { + vm.expectEmit(true, true, true, false); + emit Swap(address(stableSwapper), USDC, DAI, 0, 0); + vm.prank(KEEPER); stableSwapper.swap(USDC, DAI, 0, address(uniV3Callee), USDC_DAI_PATH); + } + + function testSwapNonKeeper() public { + assertEq(stableSwapper.buds(address(this)), 0); + vm.expectRevert("StableSwapper/non-keeper"); + stableSwapper.swap(USDC, DAI, 9900 * WAD, address(uniV3Callee), USDC_DAI_PATH); + } + + function testSwapExceedingNum() public { + vm.expectRevert("StableSwapper/exceeds-num"); + vm.prank(KEEPER); stableSwapper.swap(USDC, USDC, 0, address(uniV3Callee), USDC_DAI_PATH); + } + + function testSwapWithMinTooSmall() public { + (,,,, uint96 req) = stableSwapper.configs(USDC, DAI); + vm.expectRevert("StableSwapper/min-too-small"); + vm.prank(KEEPER); stableSwapper.swap(USDC, DAI, req - 1, address(uniV3Callee), USDC_DAI_PATH); + } +} diff --git a/test/funnels/callees/SwapperCalleeUniV3.t.sol b/test/funnels/callees/SwapperCalleeUniV3.t.sol new file mode 100644 index 00000000..6cdef72d --- /dev/null +++ b/test/funnels/callees/SwapperCalleeUniV3.t.sol @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +pragma solidity ^0.8.16; + +import "dss-test/DssTest.sol"; +import { SwapperCalleeUniV3 } from "src/funnels/callees/SwapperCalleeUniV3.sol"; + +interface GemLike { + function balanceOf(address) external view returns (uint256); + function transfer(address, uint256) external; + function decimals() external view returns (uint8); +} + +contract SwapperCalleeUniV3Test is DssTest { + + SwapperCalleeUniV3 public callee; + + address constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F; + address constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + address constant USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7; + address constant UNIV3_ROUTER = 0xE592427A0AEce92De3Edee1F18E0157C05861564; + + function setUp() public { + vm.createSelectFork(vm.envString("ETH_RPC_URL")); + + callee = new SwapperCalleeUniV3(UNIV3_ROUTER); + + deal(DAI, address(this), 1_000_000 * WAD, true); + deal(USDC, address(this), 1_000_000 * 10**6, true); + } + + function testConstructor() public { + SwapperCalleeUniV3 c = new SwapperCalleeUniV3(address(0xBEEF)); + assertEq(address(c.uniV3Router()), address(0xBEEF)); + } + + function checkStableSwap(address from, address to, bytes memory path) public { + uint256 prevFrom = GemLike(from).balanceOf(address(this)); + uint256 prevTo = GemLike(to).balanceOf(address(this)); + uint8 fromDecimals = GemLike(from).decimals(); + uint8 toDecimals = GemLike(to).decimals(); + + GemLike(from).transfer(address(callee), 10_000 * 10**fromDecimals); + callee.swap(from, to, 10_000 * 10**fromDecimals, 9000 * 10**toDecimals, address(this), path); + + assertEq(GemLike(from).balanceOf(address(this)), prevFrom - 10_000 * 10**fromDecimals); + assertGe(GemLike(to).balanceOf(address(this)), prevTo + 9000 * 10**toDecimals); + assertEq(GemLike(from).balanceOf(address(callee)), 0); + assertEq(GemLike(to).balanceOf(address(callee)), 0); + } + + function testSwapShortPath() public { + bytes memory DAI_USDC_PATH = abi.encodePacked(DAI, uint24(100), USDC); + checkStableSwap(DAI, USDC, DAI_USDC_PATH); + } + + function testSwapLongPath() public { + bytes memory USDC_USDT_DAI_PATH = abi.encodePacked(USDC, uint24(100), USDT, uint24(100), DAI); + checkStableSwap(USDC, DAI, USDC_USDT_DAI_PATH); + } + + function testSwapInvalidPath() public { + bytes memory USDC_USDT_DAI_PATH = abi.encodePacked(USDC, uint24(100), USDT, uint24(100), DAI); + + vm.expectRevert("SwapperCalleeUniV3/invalid-path"); + this.checkStableSwap(DAI, USDC, USDC_USDT_DAI_PATH); + } +} diff --git a/src/AllocatorConduitExample.sol b/test/mocks/AllocatorConduitMock.sol similarity index 84% rename from src/AllocatorConduitExample.sol rename to test/mocks/AllocatorConduitMock.sol index 48dd0f21..f127b50d 100644 --- a/src/AllocatorConduitExample.sol +++ b/test/mocks/AllocatorConduitMock.sol @@ -26,16 +26,12 @@ interface RegistryLike { function buffers(bytes32) external view returns (address); } -interface BufferLike { - function approve(address, address, uint256) external; -} - interface TokenLike { function transfer(address, uint256) external; function transferFrom(address, address, uint256) external; } -contract AllocatorConduitExample is IAllocatorConduit { +contract AllocatorConduitMock is IAllocatorConduit { // --- storage variables --- mapping(address => uint256) public wards; @@ -55,12 +51,12 @@ contract AllocatorConduitExample is IAllocatorConduit { // --- modifiers --- modifier auth() { - require(wards[msg.sender] == 1, "AllocatorBuffer/not-authorized"); + require(wards[msg.sender] == 1, "AllocatorConduitMock/not-authorized"); _; } modifier ilkAuth(bytes32 ilk) { - require(roles.canCall(ilk, msg.sender, address(this), msg.sig), "AllocatorConduitExample/ilk-not-authorized"); + require(roles.canCall(ilk, msg.sender, address(this), msg.sig), "AllocatorConduitMock/ilk-not-authorized"); _; } @@ -98,9 +94,7 @@ contract AllocatorConduitExample is IAllocatorConduit { function deposit(bytes32 ilk, address asset, uint256 amount) external ilkAuth(ilk) { address buffer = registry.buffers(ilk); - address manager; // Implement destination logic - BufferLike(buffer).approve(asset, address(this), amount); - TokenLike(asset).transferFrom(buffer, manager, amount); + TokenLike(asset).transferFrom(buffer, address(this), amount); positions[ilk][asset] += amount; emit Deposit(ilk, asset, buffer, amount); } @@ -110,8 +104,7 @@ contract AllocatorConduitExample is IAllocatorConduit { amount = balance < maxAmount ? balance : maxAmount; positions[ilk][asset] = balance - amount; address buffer = registry.buffers(ilk); - address manager; // Implement source logic - TokenLike(asset).transferFrom(manager, buffer, amount); + TokenLike(asset).transfer(buffer, amount); emit Withdraw(ilk, asset, buffer, amount); } } From c730ed9dacaf61abca78e27d3179d6fa28da3f76 Mon Sep 17 00:00:00 2001 From: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> Date: Tue, 1 Aug 2023 09:28:12 -0300 Subject: [PATCH 27/74] TokenLike => GemLike (#34) --- src/AllocatorBuffer.sol | 4 ++-- src/AllocatorVault.sol | 10 +++++----- test/mocks/AllocatorConduitMock.sol | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/AllocatorBuffer.sol b/src/AllocatorBuffer.sol index 3be37f58..1273f10c 100644 --- a/src/AllocatorBuffer.sol +++ b/src/AllocatorBuffer.sol @@ -16,7 +16,7 @@ pragma solidity ^0.8.16; -interface TokenLike { +interface GemLike { function balanceOf(address) external view returns (uint256); function approve(address, uint256) external; function transfer(address, uint256) external; @@ -63,7 +63,7 @@ contract AllocatorBuffer { // --- functions --- function approve(address asset, address spender, uint256 amount) external auth { - TokenLike(asset).approve(spender, amount); + GemLike(asset).approve(spender, amount); emit Approve(asset, spender, amount); } } diff --git a/src/AllocatorVault.sol b/src/AllocatorVault.sol index 20f2b476..71f4a4a4 100644 --- a/src/AllocatorVault.sol +++ b/src/AllocatorVault.sol @@ -33,21 +33,21 @@ interface JugLike { function drip(bytes32) external returns (uint256); } -interface TokenLike { +interface GemLike { function totalSupply() external view returns (uint256); function approve(address, uint256) external; function transferFrom(address, address, uint256) external; } interface GemJoinLike { - function gem() external view returns (TokenLike); + function gem() external view returns (GemLike); function ilk() external view returns (bytes32); function vat() external view returns (address); function join(address, uint256) external; } interface NstJoinLike { - function nst() external view returns (TokenLike); + function nst() external view returns (GemLike); function vat() external view returns (address); function exit(address, uint256) external; function join(address, uint256) external; @@ -73,7 +73,7 @@ contract AllocatorVault { bytes32 immutable public ilk; GemJoinLike immutable public gemJoin; NstJoinLike immutable public nstJoin; - TokenLike immutable public nst; + GemLike immutable public nst; // --- events --- @@ -147,7 +147,7 @@ contract AllocatorVault { // --- administration --- function init() external auth { - TokenLike gem = gemJoin.gem(); + GemLike gem = gemJoin.gem(); uint256 supply = gem.totalSupply(); require(supply == 10**6 * WAD, "AllocatorVault/supply-not-one-million-wad"); diff --git a/test/mocks/AllocatorConduitMock.sol b/test/mocks/AllocatorConduitMock.sol index f127b50d..04195b09 100644 --- a/test/mocks/AllocatorConduitMock.sol +++ b/test/mocks/AllocatorConduitMock.sol @@ -26,7 +26,7 @@ interface RegistryLike { function buffers(bytes32) external view returns (address); } -interface TokenLike { +interface GemLike { function transfer(address, uint256) external; function transferFrom(address, address, uint256) external; } @@ -94,7 +94,7 @@ contract AllocatorConduitMock is IAllocatorConduit { function deposit(bytes32 ilk, address asset, uint256 amount) external ilkAuth(ilk) { address buffer = registry.buffers(ilk); - TokenLike(asset).transferFrom(buffer, address(this), amount); + GemLike(asset).transferFrom(buffer, address(this), amount); positions[ilk][asset] += amount; emit Deposit(ilk, asset, buffer, amount); } @@ -104,7 +104,7 @@ contract AllocatorConduitMock is IAllocatorConduit { amount = balance < maxAmount ? balance : maxAmount; positions[ilk][asset] = balance - amount; address buffer = registry.buffers(ilk); - TokenLike(asset).transfer(buffer, amount); + GemLike(asset).transfer(buffer, amount); emit Withdraw(ilk, asset, buffer, amount); } } From 92a05a3c7e8286fab15ecbb9ed2e5c7a89c74d15 Mon Sep 17 00:00:00 2001 From: oldchili <130549691+oldchili@users.noreply.github.com> Date: Wed, 2 Aug 2023 19:50:17 +0300 Subject: [PATCH 28/74] Move IAllocatorConduit to src dir (#35) --- src/{interfaces => }/IAllocatorConduit.sol | 0 test/mocks/AllocatorConduitMock.sol | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename src/{interfaces => }/IAllocatorConduit.sol (100%) diff --git a/src/interfaces/IAllocatorConduit.sol b/src/IAllocatorConduit.sol similarity index 100% rename from src/interfaces/IAllocatorConduit.sol rename to src/IAllocatorConduit.sol diff --git a/test/mocks/AllocatorConduitMock.sol b/test/mocks/AllocatorConduitMock.sol index 04195b09..5f158024 100644 --- a/test/mocks/AllocatorConduitMock.sol +++ b/test/mocks/AllocatorConduitMock.sol @@ -16,7 +16,7 @@ pragma solidity ^0.8.16; -import "src/interfaces/IAllocatorConduit.sol"; +import "src/IAllocatorConduit.sol"; interface RolesLike { function canCall(bytes32, address, address, bytes4) external view returns (bool); From 7923bcc2254566886da50c2e2a29a7251c44e2e0 Mon Sep 17 00:00:00 2001 From: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> Date: Fri, 4 Aug 2023 09:33:04 -0300 Subject: [PATCH 29/74] Add unchecked to a couple of places (#39) --- src/funnels/automation/StableDepositorUniV3.sol | 4 ++-- src/funnels/automation/StableSwapper.sol | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/funnels/automation/StableDepositorUniV3.sol b/src/funnels/automation/StableDepositorUniV3.sol index 787e9b35..1b569c7c 100644 --- a/src/funnels/automation/StableDepositorUniV3.sol +++ b/src/funnels/automation/StableDepositorUniV3.sol @@ -144,7 +144,7 @@ contract StableDepositorUniV3 { require(cfg.num > 0, "StableDepositorUniV3/exceeds-num"); require(block.timestamp >= cfg.zzz + cfg.hop, "StableDepositorUniV3/too-soon"); - configs[gem0][gem1][fee][tickLower][tickUpper].num = cfg.num - 1; + unchecked { configs[gem0][gem1][fee][tickLower][tickUpper].num = cfg.num - 1; } configs[gem0][gem1][fee][tickLower][tickUpper].zzz = uint32(block.timestamp); if (amt0Min == 0) amt0Min = cfg.req0; @@ -178,7 +178,7 @@ contract StableDepositorUniV3 { require(cfg.num < 0, "StableDepositorUniV3/exceeds-num"); require(block.timestamp >= cfg.zzz + cfg.hop, "StableDepositorUniV3/too-soon"); - configs[gem0][gem1][fee][tickLower][tickUpper].num = cfg.num + 1; + unchecked { configs[gem0][gem1][fee][tickLower][tickUpper].num = cfg.num + 1; } configs[gem0][gem1][fee][tickLower][tickUpper].zzz = uint32(block.timestamp); if (amt0Min == 0) amt0Min = cfg.req0; diff --git a/src/funnels/automation/StableSwapper.sol b/src/funnels/automation/StableSwapper.sol index 9340c8e6..af225031 100644 --- a/src/funnels/automation/StableSwapper.sol +++ b/src/funnels/automation/StableSwapper.sol @@ -98,7 +98,7 @@ contract StableSwapper { require(cfg.num > 0, "StableSwapper/exceeds-num"); require(block.timestamp >= cfg.zzz + cfg.hop, "StableSwapper/too-soon"); - configs[src][dst].num = cfg.num - 1; + unchecked { configs[src][dst].num = cfg.num - 1; } configs[src][dst].zzz = uint32(block.timestamp); if (minOut == 0) minOut = cfg.req; From c76d7b4210191668cc5663d434ccfc57b58db30e Mon Sep 17 00:00:00 2001 From: sunbreak Date: Mon, 7 Aug 2023 13:39:53 -0300 Subject: [PATCH 30/74] Remove TODO that is not necessary --- src/AllocatorVault.sol | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/AllocatorVault.sol b/src/AllocatorVault.sol index 71f4a4a4..11499de7 100644 --- a/src/AllocatorVault.sol +++ b/src/AllocatorVault.sol @@ -203,6 +203,4 @@ contract AllocatorVault { function wipe(uint256 wad) external { wipe(buffer, wad); } - - // TODO: evaluate if quit function is necessary and how it should be } From 1517a5a0a920566c6be80ed44f5fdd39faa91c35 Mon Sep 17 00:00:00 2001 From: oldchili <130549691+oldchili@users.noreply.github.com> Date: Mon, 7 Aug 2023 21:52:17 +0300 Subject: [PATCH 31/74] Remove unusesd WAD definition --- src/funnels/automation/StableSwapper.sol | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/funnels/automation/StableSwapper.sol b/src/funnels/automation/StableSwapper.sol index af225031..b10c5d80 100644 --- a/src/funnels/automation/StableSwapper.sol +++ b/src/funnels/automation/StableSwapper.sol @@ -35,8 +35,6 @@ contract StableSwapper { uint96 req; // The minimum required output amount to insist on in the swap form src to dst } - uint256 internal constant WAD = 10 ** 18; - event Rely(address indexed usr); event Deny(address indexed usr); event Kiss(address indexed usr); From 6d8c592da8095541638566712f4dd1c166ec4a68 Mon Sep 17 00:00:00 2001 From: telome <130504305+telome@users.noreply.github.com> Date: Wed, 9 Aug 2023 15:34:59 +0100 Subject: [PATCH 32/74] Add support for conduit <--> buffer moves (#43) * Add support for conduit <--> buffer moves * Add missing unchecked --------- Co-authored-by: telome <> --- src/funnels/automation/ConduitMover.sol | 6 ++-- test/funnels/automation/ConduitMover.t.sol | 32 ++++++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/funnels/automation/ConduitMover.sol b/src/funnels/automation/ConduitMover.sol index e2b67dc3..eb2e6b6f 100644 --- a/src/funnels/automation/ConduitMover.sol +++ b/src/funnels/automation/ConduitMover.sol @@ -96,11 +96,11 @@ contract ConduitMover { require(cfg.num > 0, "ConduitMover/exceeds-num"); require(block.timestamp >= cfg.zzz + cfg.hop, "ConduitMover/too-soon"); - configs[from][to][gem].num = cfg.num - 1; + unchecked { configs[from][to][gem].num = cfg.num - 1; } configs[from][to][gem].zzz = uint32(block.timestamp); - ConduitLike(from).withdraw(ilk, gem, cfg.lot); - ConduitLike(to).deposit(ilk, gem, cfg.lot); + if (from != buffer) ConduitLike(from).withdraw(ilk, gem, cfg.lot); + if (to != buffer) ConduitLike(to).deposit(ilk, gem, cfg.lot); emit Move(from, to, gem, cfg.lot); } diff --git a/test/funnels/automation/ConduitMover.t.sol b/test/funnels/automation/ConduitMover.t.sol index 9f5f2bcb..b95707a2 100644 --- a/test/funnels/automation/ConduitMover.t.sol +++ b/test/funnels/automation/ConduitMover.t.sol @@ -155,6 +155,38 @@ contract ConduitMoverTest is DssTest { assertEq(lot, 1_000 * 10**6); } + function testMoveByKeeperToAndFromBuffer() public { + // Set up keeper to move USDC between conduit1 and buffer + vm.prank(FACILITATOR); mover.setConfig(conduit1, buffer, USDC, 10, 1 hours, uint128(1_000 * 10**6)); + vm.prank(FACILITATOR); mover.setConfig(buffer, conduit1, USDC, 10, 1 hours, uint128(1_000 * 10**6)); + assertEq(GemLike(USDC).balanceOf(conduit1), 3_000 * 10**6); + assertEq(GemLike(USDC).balanceOf(buffer), 0); + + vm.expectEmit(true, true, true, true); + emit Move(conduit1, buffer, USDC, 1_000 * 10**6); + vm.prank(KEEPER); mover.move(conduit1, buffer, USDC); + + assertEq(GemLike(USDC).balanceOf(conduit1), 2_000 * 10**6); + assertEq(GemLike(USDC).balanceOf(buffer), 1_000 * 10**6); + (uint64 num, uint32 hop, uint32 zzz, uint128 lot) = mover.configs(conduit1, buffer, USDC); + assertEq(num, 9); + assertEq(hop, 1 hours); + assertEq(zzz, block.timestamp); + assertEq(lot, 1_000 * 10**6); + + vm.expectEmit(true, true, true, true); + emit Move(buffer, conduit1, USDC, 1_000 * 10**6); + vm.prank(KEEPER); mover.move(buffer, conduit1, USDC); + + assertEq(GemLike(USDC).balanceOf(conduit1), 3_000 * 10**6); + assertEq(GemLike(USDC).balanceOf(buffer), 0); + (num, hop, zzz, lot) = mover.configs(buffer, conduit1, USDC); + assertEq(num, 9); + assertEq(hop, 1 hours); + assertEq(zzz, block.timestamp); + assertEq(lot, 1_000 * 10**6); + } + function testMoveNonKeeper() public { assertEq(mover.buds(address(this)), 0); vm.expectRevert("ConduitMover/non-keeper"); From 36e0830379b1c8b54630abb79c5077d4e9dad200 Mon Sep 17 00:00:00 2001 From: sunbreak Date: Wed, 9 Aug 2023 16:27:47 -0300 Subject: [PATCH 33/74] Nit: fix variable name --- src/AllocatorRoles.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/AllocatorRoles.sol b/src/AllocatorRoles.sol index 1f73c5fc..1623016f 100644 --- a/src/AllocatorRoles.sol +++ b/src/AllocatorRoles.sol @@ -77,9 +77,9 @@ contract AllocatorRoles emit Deny(usr); } - function setIlkAdmin(bytes32 ilk, address user) external auth { - ilkAdmins[ilk] = user; - emit SetIlkAdmin(ilk, user); + function setIlkAdmin(bytes32 ilk, address usr) external auth { + ilkAdmins[ilk] = usr; + emit SetIlkAdmin(ilk, usr); } // --- ilk administration --- From 651d06c357d65be1c0da8f9e235eaf2ac21dd204 Mon Sep 17 00:00:00 2001 From: oldchili <130549691+oldchili@users.noreply.github.com> Date: Mon, 14 Aug 2023 10:54:56 +0300 Subject: [PATCH 34/74] Remove AllocatorVault.s.sol --- script/AllocatorVault.s.sol | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 script/AllocatorVault.s.sol diff --git a/script/AllocatorVault.s.sol b/script/AllocatorVault.s.sol deleted file mode 100644 index 4f5e8655..00000000 --- a/script/AllocatorVault.s.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-or-later - -pragma solidity ^0.8.16; - -import "forge-std/Script.sol"; - -contract AllocatorVaultScript is Script { - function setUp() public {} - - function run() public { - vm.broadcast(); - } -} From 74d5721ce7bd9743999d3e64c76beb5aac621f17 Mon Sep 17 00:00:00 2001 From: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> Date: Mon, 14 Aug 2023 10:27:39 -0300 Subject: [PATCH 35/74] Vault: Only allow to draw and wipe to the Buffer (#45) --- src/AllocatorVault.sol | 24 ++++++++---------------- test/AllocatorVault.t.sol | 35 +++++++++-------------------------- 2 files changed, 17 insertions(+), 42 deletions(-) diff --git a/src/AllocatorVault.sol b/src/AllocatorVault.sol index 11499de7..07dc85bc 100644 --- a/src/AllocatorVault.sol +++ b/src/AllocatorVault.sol @@ -81,8 +81,8 @@ contract AllocatorVault { event Deny(address indexed usr); event File(bytes32 indexed what, address data); event Init(uint256 supply); - event Draw(address indexed sender, address indexed to, uint256 wad); - event Wipe(address indexed sender, address indexed from, uint256 wad); + event Draw(address indexed sender, uint256 wad); + event Wipe(address indexed sender, uint256 wad); // --- modifiers --- @@ -177,30 +177,22 @@ contract AllocatorVault { // --- funnels execution --- - function draw(address to, uint256 wad) public auth { + function draw(uint256 wad) public auth { uint256 rate = jug.drip(ilk); uint256 dart = _divup(wad * RAY, rate); require(dart <= uint256(type(int256).max), "AllocatorVault/overflow"); vat.frob(ilk, address(this), address(0), address(this), 0, int256(dart)); - nstJoin.exit(to, wad); - emit Draw(msg.sender, to, wad); + nstJoin.exit(buffer, wad); + emit Draw(msg.sender, wad); } - function draw(uint256 wad) external { - draw(buffer, wad); - } - - function wipe(address from, uint256 wad) public auth { - nst.transferFrom(from, address(this), wad); + function wipe(uint256 wad) public auth { + nst.transferFrom(buffer, address(this), wad); nstJoin.join(address(this), wad); uint256 rate = jug.drip(ilk); uint256 dart = wad * RAY / rate; require(dart <= uint256(type(int256).max), "AllocatorVault/overflow"); vat.frob(ilk, address(this), address(this), address(this), 0, -int256(dart)); - emit Wipe(msg.sender, from, wad); - } - - function wipe(uint256 wad) external { - wipe(buffer, wad); + emit Wipe(msg.sender, wad); } } diff --git a/test/AllocatorVault.t.sol b/test/AllocatorVault.t.sol index a5df72d3..cd82fd57 100644 --- a/test/AllocatorVault.t.sol +++ b/test/AllocatorVault.t.sol @@ -27,8 +27,8 @@ contract AllocatorVaultTest is DssTest { bytes32 public ilk; event Init(uint256 supply); - event Draw(address indexed sender, address indexed to, uint256 wad); - event Wipe(address indexed sender, address indexed from, uint256 wad); + event Draw(address indexed sender, uint256 wad); + event Wipe(address indexed sender, uint256 wad); function _divup(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { @@ -59,12 +59,10 @@ contract AllocatorVaultTest is DssTest { } function testModifiers() public { - bytes4[] memory authedMethods = new bytes4[](5); + bytes4[] memory authedMethods = new bytes4[](3); authedMethods[0] = vault.init.selector; - authedMethods[1] = bytes4(keccak256("draw(address,uint256)")); - authedMethods[2] = bytes4(keccak256("draw(uint256)")); - authedMethods[3] = bytes4(keccak256("wipe(address,uint256)")); - authedMethods[4] = bytes4(keccak256("wipe(uint256)")); + authedMethods[1] = bytes4(keccak256("draw(uint256)")); + authedMethods[2] = bytes4(keccak256("wipe(uint256)")); vm.startPrank(address(0xBEEF)); checkModifier(address(vault), "AllocatorVault/not-authorized", authedMethods); @@ -112,7 +110,7 @@ contract AllocatorVaultTest is DssTest { (, uint256 art) = vat.urns(ilk, address(buffer)); assertEq(art, 0); vm.expectEmit(true, true, true, true); - emit Draw(address(this), address(buffer), 50 * 10**18); + emit Draw(address(this), 50 * 10**18); vault.draw(50 * 10**18); (, art) = vat.urns(ilk, address(vault)); assertEq(art, 50 * 10**18); @@ -122,7 +120,7 @@ contract AllocatorVaultTest is DssTest { assertEq(nst.balanceOf(address(buffer)), 50 * 10**18); vm.warp(block.timestamp + 1); vm.expectEmit(true, true, true, true); - emit Draw(address(this), address(buffer), 50 * 10**18); + emit Draw(address(this), 50 * 10**18); vault.draw(50 * 10**18); (, art) = vat.urns(ilk, address(vault)); uint256 expectedArt = 50 * 10**18 + _divup(50 * 10**18 * 1000, div); @@ -140,33 +138,18 @@ contract AllocatorVaultTest is DssTest { vm.expectRevert(); vault.wipe(100.06 * 10**18); // It will try to wipe more art than existing, then reverts vm.expectEmit(true, true, true, true); - emit Wipe(address(this), address(buffer), 100.05 * 10**18); + emit Wipe(address(this), 100.05 * 10**18); vault.wipe(100.05 * 10**18); assertEq(nst.balanceOf(address(buffer)), 0.01 * 10**18); (, art) = vat.urns(ilk, address(vault)); assertEq(art, 1); // Dust which is impossible to wipe } - function testDrawAndWipeOtherAddress() public { - vault.init(); - vault.file("jug", address(jug)); - vm.expectEmit(true, true, true, true); - emit Draw(address(this), address(0xBEEF), 50 * 10**18); - vault.draw(address(0xBEEF), 50 * 10**18); - assertEq(nst.balanceOf(address(0xBEEF)), 50 * 10**18); - vm.prank(address(0xBEEF)); - nst.approve(address(vault), 50 * 10**18); - vm.expectEmit(true, true, true, true); - emit Wipe(address(this), address(0xBEEF), 50 * 10**18); - vault.wipe(address(0xBEEF), 50 * 10**18); - assertEq(nst.balanceOf(address(0xBEEF)), 0); - } - function testDebtOverLine() public { vault.init(); vault.file("jug", address(jug)); vm.expectEmit(true, true, true, true); - emit Draw(address(this), address(buffer), vault.line()); + emit Draw(address(this), vault.line()); vault.draw(vault.line()); vm.warp(block.timestamp + 1); jug.drip(ilk); From a3d2095a484f74b17b0edd6ebc0afd6ffc7862a7 Mon Sep 17 00:00:00 2001 From: oldchili <130549691+oldchili@users.noreply.github.com> Date: Mon, 14 Aug 2023 20:42:24 +0300 Subject: [PATCH 36/74] Add README content (#44) * Add README content * Apply suggestions from code review Co-authored-by: telome <130504305+telome@users.noreply.github.com> * READMD - Allocation => Allocator * READMD - Dao => DAO * README - v3 => V3 * Minor * debt ceiling => max debt ceiling * Add Security Model and Technical Assumptions * Apply suggestions from code review Co-authored-by: telome <130504305+telome@users.noreply.github.com> * Minors * Improve wording for 2106 limitation * Apply suggestions from code review Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> * Ilk => ilk * Emphasize ilk is a code term * Update drawing to include registry and separate proxy * Add link to dss-conduits * Add explanation of why we need the ConduitMover * Add the keeper assumption about updating minimal amounts * Apply suggestions from code review Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> --------- Co-authored-by: telome <130504305+telome@users.noreply.github.com> Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> --- README | 2 - README.md | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+), 2 deletions(-) delete mode 100644 README create mode 100644 README.md diff --git a/README b/README deleted file mode 100644 index 3dc5f4e8..00000000 --- a/README +++ /dev/null @@ -1,2 +0,0 @@ -Part of this code was inspired by https://github.com/makerdao/rwa-toolkit/blob/master/src/urns/RwaUrn.sol mainly authored by livnev and https://github.com/dapphub/ds-roles/blob/master/src/roles.sol authored by DappHub. -Since it should belong to the MakerDAO community the Copyright from our additions has been transferred to Dai Foundation. diff --git a/README.md b/README.md new file mode 100644 index 00000000..778b9d01 --- /dev/null +++ b/README.md @@ -0,0 +1,148 @@ +# `dss-allocator` + +Part of this code was inspired by https://github.com/makerdao/rwa-toolkit/blob/master/src/urns/RwaUrn.sol mainly authored by livnev and https://github.com/dapphub/ds-roles/blob/master/src/roles.sol authored by DappHub. +Since it should belong to the MakerDAO community the Copyright from our additions has been transferred to Dai Foundation. + +## Overview +Implementation of the allocation system, based on the [technical specification forum post](https://forum.makerdao.com/t/preliminary-technical-specification-of-the-allocation-system/20921). +The conduits are implemented separately. See for example [dss-conduits](https://github.com/makerdao/dss-conduits). + +![Untitled-2023-08-07-1511](https://github.com/makerdao/dss-allocator/assets/130549691/af24bcb8-5e5a-4394-8eee-a1f7d6f44341) + +## Layers +The system is comprised of several layers: + +- Core Allocation System (*green above*): + - Smart contracts that can be considered a part of the Maker Core Protocol, and are immutable and present in all Allocators. + - Their main role is to mint NST (New Stable Token) and hold it (possibly with other tokens) in the `AllocatorBuffer`. +- Deployment Funnels (*blue above*): + - Contracts that pull funds from the `AllocatorBuffer`. + - The funds can be swapped and/or deployed into AMM pools or specific conduits. + - A typical setting for a funnel includes a base rate-limited contract (such as Swapper) and an automation contract on top of it (such as StableSwapper). +- Conduits (*orange above*): + - Yield investment singletons that support deposits and withdrawals. + +## Actors +The allocation system includes several actor types: + +- Pause Proxy: + - Performs actions through spells with governance delay. + - In charge of setting up the core components and the NST minting instant access modules (DC-IAMs). + - Ward of the singleton contracts (e.g RWA conduits, Coinbase Custody, `AllocatorRoles`). +- AllocatorDAO Proxy: + - Performs actions through a sub-spell with governance delay. + - Ward of its `AllocatorVault`, `AllocatorBuffer` and funnel contracts. + - In charge of adding new contracts to the funnel network (e.g Swapper, DepositorUniV3). + - Can add operators to its funnel network through the `AllocatorRoles` contract. + - In charge of setting rate-limiting safety parameters for operators. +- Operator: + - Performs actions without a spell and without governance delay. + - An optional actor which is whitelisted through the `AllocatorRoles` contract to perform specified actions on the `AllocatorVault`, funnels and conduits. + - Will typically be a facilitator multisig or an automation contract controlled by one (e.g `StableSwapper`, `StableDepositorUniV3`). +- Keeper: + - An optional actor which can be set up to trigger the automation contracts in case repetitive actions are needed (such as swapping NST to USDC every time interval). + +![Untitled (1)](https://github.com/makerdao/dss-allocator/assets/130549691/c677928b-32f4-4000-b6ed-e3798caa9c5c) + +## Contracts and Configuration +### VAT Configuration + +Each AllocatorDAO has a unique `ilk` (collateral type) with one VAT vault set up for it. + +- Each `ilk` supports a 1 trillion NST max debt ceiling. +- Each `ilk` has a special collateral token that is minted and locked in the system. +- The collateral amount of each vault is 1 million WAD (i.e. 10^6 * 10^18 units of collateral token). +- All the `ilk`s have a shared simple [oracle](https://github.com/makerdao/dss-allocator/blob/dev/src/AllocatorOracle.sol) that just returns a fixed price of 1 Million (which multiplied by the collateral amount makes sure the max debt ceiling can indeed be reached). + +### AllocatorVault + +Single contract per `ilk`, which operators can use to: + +- Mint (`draw`) NST from the vault to the AllocatorBuffer. +- Repay (`wipe`) NST from the AllocatorBuffer. + +### AllocatorBuffer + +A simple contract for the AllocatorDAO to hold funds in. + +- Supports approving contracts to `transferFrom` it. +- Note that although the `AllocatorVault` pushes and pulls NST to/from the `AllocatorBuffer`, it can manage other tokens as well. + +### AllocatorRoles + +A global permissions registry, inspired by [ds-roles](https://github.com/dapphub/ds-roles). + +- Allows AllocatorDAOs to list operators to manage `AllocatorVault`s, funnels and conduits in a per-action resolution. +- Warded by the Pause Proxy, which needs to add a new AllocatorDAO once one is onboarded. + +### AllocatorRegistry + +A registry where each AllocatorDAO’s `AllocatorBuffer` address is listed. + +### Swapper + +A module that pulls tokens from the `AllocatorBuffer` and sends them to be swapped at a callee contract. The resulting funds are sent back to the `AllocatorBuffer`. + +It enforces that: + +- The swap rate is not faster than a pre-configured rate. +- The amount to swap each time is not larger than a pre-configured amount. +- The received funds are not less than a minimal amount specified on the swap call. + +### Swapper Callees + +Contracts that perform the actual swap and send the resulting funds to the Swapper (to be forwarded to the AllocatoBuffer). + +- They can be implemented on top of any DEX / swap vehicle. +- An example is `SwapperCalleeUniV3`, where swaps in Uniswap V3 can be triggered. + +### DepositorUniV3 + +A primitive for depositing liquidity to Uniswap V3 in a fixed range. + +As the Swapper, it includes rate limit protection and is designed so facilitators and automation contracts can use it. + +### StableSwapper + +An automation contract, which can be used by the AllocatorDAOs to set up recurring swaps of stable tokens (e.g NST to USDC). + +- In order to use it, the AllocatorDAO should list it as an operator of its `Swapper` primitive in the `AllocatorRoles` contract. +- The `Swapper` primitive will rate-limit the automation contract. + +### StableDepositorUniV3 + +An automation contract sample, which can be used by the AllocatorDAOs to set up recurring deposits or withdraws. + +- In order to use it, the AllocatorDAO should list it as an operator of its `DepositorUniV3` primitive in the `AllocatorRoles` contract. +- The `Depositor` primitive will rate-limit the automation contract. + +### ConduitMover + +An automation contract sample, which can be used by the AllocatorDAOs to move funds between their `AllocatorBuffer` and the conduits in an automated manner. +- Although there is no built-in rate limit in the transfer of funds from/to the `AllocatorBuffer` to/form the conduits, +this can be useful for optimizing yield by moving funds to the destination conduit just in time for them to get processed +(in case the destination conduit has an agreed upon rate limiting). +- It can also be useful for automating movement of funds from the buffer in the same rate as they are swapped or withdrawn into it. + +### IAllocatorConduit + +An interface which each Conduit should implement. + +## Security Model: +- AllocatorDAOs can not incur a loss of more than the debt ceiling (`line`) of their respective `ilk`. +- A funnel operator (whether a facilitator or an automated contract) can not incur a loss of more than `cap` amount of funds per `era` interval for a specific configuration. This includes not being able to move funds directly to any unknown address that the AllocatorDAO Proxy did not approve. +- A keeper can not incur a loss of more than the funnel opeator can, and any loss it can incur is also constrained by `req` or `req0` and `req1` for a specific configuration. + +## Technical Assumptions: +- A `uint32` is suitable for storing timestamps or time intervals in the funnels, as the current version of the Allocation System is expected to be deprecated long before 2106. +- A `uint96` is suitable for storing token amounts in the funnels, as amounts in the scale of 70B are not expected to be used. This implies that the Allocation System does not support tokens with extremely low prices. +- As with most MakerDAO contracts, non standard token implementations are assumed to not be supported. As examples, this includes tokens that: + * Do not have a decimals field or have more than 18 decimals. + * Do not revert and instead rely on a return value. + * Implement fee on transfer. + * Include rebasing logic. + * Implement callbacks/hooks. +- In the Swapper, in case `limit.era` is zero the full cap amount can be swapped for multiple times in the same transaction because `limit.due` will be reset upon re-entry. However, this is consistent with the intended behavior, as in that case zero cooldown is explicitly defined. +- In StableSwapper the keeper's minimal out value is assumed to be updated whenever `configs[src][dst]` is changed. Failing to do so may result in the swap call reverting or in taking on more slippage than intended (up to a limit controlled by `configs[src][dst].min`). +- In StableDepositorUniV3 the keeper's minimal amt values are assumed to be updated whenever `configs[gem0][gem1][fee][tickLower][tickUpper]` is changed. Failing to do so may result in the deposit/withdraw call reverting or in taking on more slippage than intended (up to a limit controlled by `configs[gem0][gem1][fee][tickLower][tickUpper].req0/1`). +- The Allocation System assumes that the ESM threshold is set large enough prior to its deployment, so Emergency Shutdown can never be called. From a24fc1387e8ce24d0f695f6714f67cb3e9bc29c2 Mon Sep 17 00:00:00 2001 From: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> Date: Tue, 15 Aug 2023 10:17:01 -0300 Subject: [PATCH 37/74] Roles: Add hasActionRole getter + minor change to hasUserRole (#47) --- src/AllocatorRoles.sol | 8 ++++++-- test/AllocatorRoles.t.sol | 8 ++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/AllocatorRoles.sol b/src/AllocatorRoles.sol index 1623016f..6dc749e3 100644 --- a/src/AllocatorRoles.sol +++ b/src/AllocatorRoles.sol @@ -55,8 +55,12 @@ contract AllocatorRoles // --- getters --- - function hasUserRole(bytes32 ilk, address who, uint8 role) external view returns (bool) { - return bytes32(0) != userRoles[ilk][who] & bytes32(2 ** uint256(role)); + function hasUserRole(bytes32 ilk, address who, uint8 role) external view returns (bool has) { + has = userRoles[ilk][who] & bytes32(2 ** uint256(role)) != bytes32(0); + } + + function hasActionRole(bytes32 ilk, address target, bytes4 sig, uint8 role) external view returns (bool has) { + has = actionsRoles[ilk][target][sig] & bytes32(2 ** uint256(role)) != bytes32(0); } // --- internals --- diff --git a/test/AllocatorRoles.t.sol b/test/AllocatorRoles.t.sol index 5af1a0d9..0aea0380 100644 --- a/test/AllocatorRoles.t.sol +++ b/test/AllocatorRoles.t.sol @@ -66,9 +66,17 @@ contract AllocatorRolesTest is DssTest { vm.expectRevert("AuthedMock/not-authorized"); authed.exec(); + assertTrue(!roles.hasActionRole(ilk, address(authed), bytes4(keccak256("exec()")), admin_role)); + assertTrue(!roles.hasActionRole(ilk, address(authed), bytes4(keccak256("exec()")), mod_role)); + assertTrue(!roles.hasActionRole(ilk, address(authed), bytes4(keccak256("exec()")), user_role)); + assertTrue(!roles.hasActionRole(ilk, address(authed), bytes4(keccak256("exec()")), max_role)); vm.expectEmit(true, true, true, true); emit SetRoleAction(ilk, admin_role, address(authed), bytes4(keccak256("exec()")), true); roles.setRoleAction(ilk, admin_role, address(authed), bytes4(keccak256("exec()")), true); + assertTrue( roles.hasActionRole(ilk, address(authed), bytes4(keccak256("exec()")), admin_role)); + assertTrue(!roles.hasActionRole(ilk, address(authed), bytes4(keccak256("exec()")), mod_role)); + assertTrue(!roles.hasActionRole(ilk, address(authed), bytes4(keccak256("exec()")), user_role)); + assertTrue(!roles.hasActionRole(ilk, address(authed), bytes4(keccak256("exec()")), max_role)); assertTrue(roles.canCall(ilk, address(this), address(authed), bytes4(keccak256("exec()")))); authed.exec(); From ecba0650cff920f8d68234d8ca68b2e8826144e9 Mon Sep 17 00:00:00 2001 From: sunbreak Date: Tue, 15 Aug 2023 11:07:13 -0300 Subject: [PATCH 38/74] Fix README --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 778b9d01..a9fd0e18 100644 --- a/README.md +++ b/README.md @@ -50,8 +50,7 @@ The allocation system includes several actor types: Each AllocatorDAO has a unique `ilk` (collateral type) with one VAT vault set up for it. - Each `ilk` supports a 1 trillion NST max debt ceiling. -- Each `ilk` has a special collateral token that is minted and locked in the system. -- The collateral amount of each vault is 1 million WAD (i.e. 10^6 * 10^18 units of collateral token). +- The collateral amount of each vault is 1 million WAD (10^6 * 10^18 indivisible units of collateral). - All the `ilk`s have a shared simple [oracle](https://github.com/makerdao/dss-allocator/blob/dev/src/AllocatorOracle.sol) that just returns a fixed price of 1 Million (which multiplied by the collateral amount makes sure the max debt ceiling can indeed be reached). ### AllocatorVault From 204d18c871021e453cbd05a11a22c5f32adc87ac Mon Sep 17 00:00:00 2001 From: sunbreak Date: Tue, 15 Aug 2023 11:19:11 -0300 Subject: [PATCH 39/74] Revert "Fix README" This reverts commit ecba0650cff920f8d68234d8ca68b2e8826144e9. --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a9fd0e18..778b9d01 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,8 @@ The allocation system includes several actor types: Each AllocatorDAO has a unique `ilk` (collateral type) with one VAT vault set up for it. - Each `ilk` supports a 1 trillion NST max debt ceiling. -- The collateral amount of each vault is 1 million WAD (10^6 * 10^18 indivisible units of collateral). +- Each `ilk` has a special collateral token that is minted and locked in the system. +- The collateral amount of each vault is 1 million WAD (i.e. 10^6 * 10^18 units of collateral token). - All the `ilk`s have a shared simple [oracle](https://github.com/makerdao/dss-allocator/blob/dev/src/AllocatorOracle.sol) that just returns a fixed price of 1 Million (which multiplied by the collateral amount makes sure the max debt ceiling can indeed be reached). ### AllocatorVault From 7a145fdba8aaf34b2a191b6846ed00036de48d77 Mon Sep 17 00:00:00 2001 From: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> Date: Tue, 15 Aug 2023 14:06:34 -0300 Subject: [PATCH 40/74] Vault: Remove usage of Gem and GemJoin (#48) * Remove usage of Gem and GemJoin * Fix README --- README.md | 3 +-- src/AllocatorVault.sol | 22 ++++++---------------- test/AllocatorVault.t.sol | 34 +++++++++++++--------------------- test/mocks/GemJoinMock.sol | 23 ----------------------- 4 files changed, 20 insertions(+), 62 deletions(-) delete mode 100644 test/mocks/GemJoinMock.sol diff --git a/README.md b/README.md index 778b9d01..a9fd0e18 100644 --- a/README.md +++ b/README.md @@ -50,8 +50,7 @@ The allocation system includes several actor types: Each AllocatorDAO has a unique `ilk` (collateral type) with one VAT vault set up for it. - Each `ilk` supports a 1 trillion NST max debt ceiling. -- Each `ilk` has a special collateral token that is minted and locked in the system. -- The collateral amount of each vault is 1 million WAD (i.e. 10^6 * 10^18 units of collateral token). +- The collateral amount of each vault is 1 million WAD (10^6 * 10^18 indivisible units of collateral). - All the `ilk`s have a shared simple [oracle](https://github.com/makerdao/dss-allocator/blob/dev/src/AllocatorOracle.sol) that just returns a fixed price of 1 Million (which multiplied by the collateral amount makes sure the max debt ceiling can indeed be reached). ### AllocatorVault diff --git a/src/AllocatorVault.sol b/src/AllocatorVault.sol index 07dc85bc..6022cb77 100644 --- a/src/AllocatorVault.sol +++ b/src/AllocatorVault.sol @@ -71,7 +71,6 @@ contract AllocatorVault { address immutable public buffer; VatLike immutable public vat; bytes32 immutable public ilk; - GemJoinLike immutable public gemJoin; NstJoinLike immutable public nstJoin; GemLike immutable public nst; @@ -80,7 +79,7 @@ contract AllocatorVault { event Rely(address indexed usr); event Deny(address indexed usr); event File(bytes32 indexed what, address data); - event Init(uint256 supply); + event Init(); event Draw(address indexed sender, uint256 wad); event Wipe(address indexed sender, uint256 wad); @@ -94,18 +93,16 @@ contract AllocatorVault { // --- constructor --- - constructor(address roles_, address buffer_, address vat_, address gemJoin_, address nstJoin_) { + constructor(address roles_, address buffer_, address vat_, bytes32 ilk_, address nstJoin_) { roles = RolesLike(roles_); buffer = buffer_; vat = VatLike(vat_); - - gemJoin = GemJoinLike(gemJoin_); + ilk = ilk_; nstJoin = NstJoinLike(nstJoin_); - require(vat_ == gemJoin.vat() && vat_ == nstJoin.vat(), "AllocatorVault/vat-not-match"); + require(vat_ == nstJoin.vat(), "AllocatorVault/vat-not-match"); - ilk = GemJoinLike(gemJoin_).ilk(); nst = NstJoinLike(nstJoin_).nst(); VatLike(vat_).hope(nstJoin_); @@ -147,15 +144,8 @@ contract AllocatorVault { // --- administration --- function init() external auth { - GemLike gem = gemJoin.gem(); - uint256 supply = gem.totalSupply(); - require(supply == 10**6 * WAD, "AllocatorVault/supply-not-one-million-wad"); - - gem.approve(address(gemJoin), supply); - gemJoin.join(address(this), supply); - vat.frob(ilk, address(this), address(this), address(0), int256(supply), 0); - - emit Init(supply); + vat.frob(ilk, address(this), address(this), address(0), int256(10**6 * WAD), 0); + emit Init(); } function rely(address usr) external auth { diff --git a/test/AllocatorVault.t.sol b/test/AllocatorVault.t.sol index cd82fd57..5b006a54 100644 --- a/test/AllocatorVault.t.sol +++ b/test/AllocatorVault.t.sol @@ -9,7 +9,6 @@ import { RolesMock } from "test/mocks/RolesMock.sol"; import { VatMock } from "test/mocks/VatMock.sol"; import { JugMock } from "test/mocks/JugMock.sol"; import { GemMock } from "test/mocks/GemMock.sol"; -import { GemJoinMock } from "test/mocks/GemJoinMock.sol"; import { NstJoinMock } from "test/mocks/NstJoinMock.sol"; contract AllocatorVaultTest is DssTest { @@ -17,8 +16,6 @@ contract AllocatorVaultTest is DssTest { VatMock public vat; JugMock public jug; - GemMock public gem; - GemJoinMock public gemJoin; GemMock public nst; NstJoinMock public nstJoin; AllocatorBuffer public buffer; @@ -26,7 +23,7 @@ contract AllocatorVaultTest is DssTest { AllocatorVault public vault; bytes32 public ilk; - event Init(uint256 supply); + event Init(); event Draw(address indexed sender, uint256 wad); event Wipe(address indexed sender, uint256 wad); @@ -40,18 +37,17 @@ contract AllocatorVaultTest is DssTest { ilk = "TEST-ILK"; vat = new VatMock(); jug = new JugMock(vat); - gem = new GemMock(1_000_000 * 10**18); - gemJoin = new GemJoinMock(vat, ilk, gem); nst = new GemMock(0); nstJoin = new NstJoinMock(vat, nst); buffer = new AllocatorBuffer(); roles = new RolesMock(); - vault = new AllocatorVault(address(roles), address(buffer), address(vat), address(gemJoin), address(nstJoin)); + vault = new AllocatorVault(address(roles), address(buffer), address(vat), ilk, address(nstJoin)); buffer.approve(address(nst), address(vault), type(uint256).max); - gem.transfer(address(vault), 1_000_000 * 10**18); + + vat.slip(ilk, address(vault), int256(1_000_000 * WAD)); // Add some existing DAI assigned to nstJoin to avoid a particular error - stdstore.target(address(vat)).sig("dai(address)").with_key(address(nstJoin)).depth(0).checked_write(100_000 * 10**45); + stdstore.target(address(vat)).sig("dai(address)").with_key(address(nstJoin)).depth(0).checked_write(100_000 * RAD); } function testAuth() public { @@ -82,28 +78,24 @@ contract AllocatorVaultTest is DssTest { } function testInit() public { - assertEq(gem.balanceOf(address(vault)), gem.totalSupply()); - assertEq(gem.balanceOf(address(gemJoin)), 0); + assertEq(vat.gem(ilk, address(vault)), 10**6 * WAD); (uint256 ink, ) = vat.urns(ilk, address(vault)); assertEq(ink, 0); vault.init(); - assertEq(gem.balanceOf(address(vault)), 0); - assertEq(gem.balanceOf(address(gemJoin)), gem.totalSupply()); + assertEq(vat.gem(ilk, address(vault)), 0); (ink, ) = vat.urns(ilk, address(vault)); - assertEq(ink, gem.totalSupply()); + assertEq(ink, 10**6 * WAD); } - function testInitNotTotalSupply() public { - deal(address(gem), address(vault), gem.balanceOf(address(vault)) - 1); - vm.expectRevert("Gem/insufficient-balance"); + function testInitNotEnoughBalance() public { + vat.slip(ilk, address(vault), -1); + vm.expectRevert(); vault.init(); } - uint256 div = 1001; // Hack to solve a compiling issue - function testDrawWipe() public { vm.expectEmit(true, true, true, true); - emit Init(gem.totalSupply()); + emit Init(); vault.init(); vault.file("jug", address(jug)); assertEq(vault.line(), 20_000_000 * 10**18); @@ -123,7 +115,7 @@ contract AllocatorVaultTest is DssTest { emit Draw(address(this), 50 * 10**18); vault.draw(50 * 10**18); (, art) = vat.urns(ilk, address(vault)); - uint256 expectedArt = 50 * 10**18 + _divup(50 * 10**18 * 1000, div); + uint256 expectedArt = 50 * 10**18 + _divup(50 * 10**18 * 1000, 1001); assertEq(art, expectedArt); assertEq(vat.rate(), 1001 * 10**27 / 1000); assertEq(vault.debt(), _divup(expectedArt * 1001, 1000)); diff --git a/test/mocks/GemJoinMock.sol b/test/mocks/GemJoinMock.sol deleted file mode 100644 index e07e306c..00000000 --- a/test/mocks/GemJoinMock.sol +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-or-later - -pragma solidity ^0.8.16; - -import { VatMock } from "test/mocks/VatMock.sol"; -import { GemMock } from "test/mocks/GemMock.sol"; - -contract GemJoinMock { - VatMock public vat; - bytes32 public ilk; - GemMock public gem; - - constructor(VatMock vat_, bytes32 ilk_, GemMock gem_) { - vat = vat_; - ilk = ilk_; - gem = gem_; - } - - function join(address usr, uint256 wad) external { - vat.slip(ilk, usr, int256(wad)); - gem.transferFrom(msg.sender, address(this), wad); - } -} From f6bc6a8fc9db03d0a91754c860b426b5ca6a1f84 Mon Sep 17 00:00:00 2001 From: oldchili <130549691+oldchili@users.noreply.github.com> Date: Wed, 16 Aug 2023 22:04:59 +0300 Subject: [PATCH 41/74] AllocatorVault - make draw and wipe external --- src/AllocatorVault.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AllocatorVault.sol b/src/AllocatorVault.sol index 6022cb77..b16e2619 100644 --- a/src/AllocatorVault.sol +++ b/src/AllocatorVault.sol @@ -167,7 +167,7 @@ contract AllocatorVault { // --- funnels execution --- - function draw(uint256 wad) public auth { + function draw(uint256 wad) external auth { uint256 rate = jug.drip(ilk); uint256 dart = _divup(wad * RAY, rate); require(dart <= uint256(type(int256).max), "AllocatorVault/overflow"); @@ -176,7 +176,7 @@ contract AllocatorVault { emit Draw(msg.sender, wad); } - function wipe(uint256 wad) public auth { + function wipe(uint256 wad) external auth { nst.transferFrom(buffer, address(this), wad); nstJoin.join(address(this), wad); uint256 rate = jug.drip(ilk); From 5af7242af3825009b7463c6842cbde5e075dcc16 Mon Sep 17 00:00:00 2001 From: sunbreak Date: Thu, 17 Aug 2023 11:42:32 -0300 Subject: [PATCH 42/74] Callee swap => swapCallback --- src/funnels/Swapper.sol | 4 ++-- src/funnels/callees/SwapperCalleeUniV3.sol | 2 +- test/funnels/Swapper.t.sol | 2 +- test/funnels/callees/SwapperCalleeUniV3.t.sol | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/funnels/Swapper.sol b/src/funnels/Swapper.sol index 97628df4..7de12fcb 100644 --- a/src/funnels/Swapper.sol +++ b/src/funnels/Swapper.sol @@ -27,7 +27,7 @@ interface GemLike { } interface CalleeLike { - function swap(address, address, uint256, uint256, address, bytes calldata) external; + function swapCallback(address, address, uint256, uint256, address, bytes calldata) external; } contract Swapper { @@ -102,7 +102,7 @@ contract Swapper { GemLike(src).transferFrom(buffer, callee, amt); // Avoid swapping directly to buffer to prevent piggybacking another operation to satisfy the balance check - CalleeLike(callee).swap(src, dst, amt, minOut, address(this), data); + CalleeLike(callee).swapCallback(src, dst, amt, minOut, address(this), data); out = GemLike(dst).balanceOf(address(this)); require(out >= minOut, "Swapper/too-few-dst-received"); diff --git a/src/funnels/callees/SwapperCalleeUniV3.sol b/src/funnels/callees/SwapperCalleeUniV3.sol index 1a6c6bd3..99aee0de 100644 --- a/src/funnels/callees/SwapperCalleeUniV3.sol +++ b/src/funnels/callees/SwapperCalleeUniV3.sol @@ -42,7 +42,7 @@ contract SwapperCalleeUniV3 { uniV3Router = _uniV3Router; } - function swap(address src, address dst, uint256 amt, uint256 minOut, address to, bytes calldata data) external { + function swapCallback(address src, address dst, uint256 amt, uint256 minOut, address to, bytes calldata data) external { bytes memory path = data; address firstToken; diff --git a/test/funnels/Swapper.t.sol b/test/funnels/Swapper.t.sol index 976048e5..20aac03c 100644 --- a/test/funnels/Swapper.t.sol +++ b/test/funnels/Swapper.t.sol @@ -14,7 +14,7 @@ interface GemLike { } contract CalleeMock is DssTest { - function swap(address src, address dst, uint256 amt, uint256, address to, bytes calldata) external { + function swapCallback(address src, address dst, uint256 amt, uint256, address to, bytes calldata) external { GemLike(src).transfer(address(0xDEAD), amt); deal(dst, address(this), amt, true); GemLike(dst).transfer(to, amt); diff --git a/test/funnels/callees/SwapperCalleeUniV3.t.sol b/test/funnels/callees/SwapperCalleeUniV3.t.sol index 6cdef72d..a454c3ed 100644 --- a/test/funnels/callees/SwapperCalleeUniV3.t.sol +++ b/test/funnels/callees/SwapperCalleeUniV3.t.sol @@ -40,7 +40,7 @@ contract SwapperCalleeUniV3Test is DssTest { uint8 toDecimals = GemLike(to).decimals(); GemLike(from).transfer(address(callee), 10_000 * 10**fromDecimals); - callee.swap(from, to, 10_000 * 10**fromDecimals, 9000 * 10**toDecimals, address(this), path); + callee.swapCallback(from, to, 10_000 * 10**fromDecimals, 9000 * 10**toDecimals, address(this), path); assertEq(GemLike(from).balanceOf(address(this)), prevFrom - 10_000 * 10**fromDecimals); assertGe(GemLike(to).balanceOf(address(this)), prevTo + 9000 * 10**toDecimals); From aea59a10983470793f315638be94cfc66f913b4d Mon Sep 17 00:00:00 2001 From: telome <130504305+telome@users.noreply.github.com> Date: Tue, 22 Aug 2023 17:13:35 +0100 Subject: [PATCH 43/74] Add automation keeper scripts (#31) * Add AllocatorRoles * First check roles * Fix for error messaging + add test for roles in the buffer + some renaming and order * Add tests + some renaming * More casting simplification * Add draft swapper * Separate facilitators from keepers * Account for ES * Fix nits * Move to subfolders * Move tests * Use storage weights * Remove pip * Add box authorisation sanity check * Update src/funnels/Swapper.sol Co-authored-by: oldchili <130549691+oldchili@users.noreply.github.com> * Address first batch of review comments * Rename vars * Use fixed lots * Add countdowns * Allow other gem decimals * Remove wipe call * Removing deposit call * Add README for latest design * Update README re whitelist * Update README to laster design iteration * Clarify README * Add updated Swapper * Add Router * Fix event * Clean ConduitMock * Update to approve+deposit architecture * Rename WhitelistedRouter.move * Move gem from buffer * Make Swapper generic * Add roles to Swapper * Add SwapperRunner * Update Swapper tests * Update router tests * Fix rebase * Use AllocatorBuffer instead of mock * Use fork * Rename swap role * Add Depositor * Fix rebase * Add Depositor rate limit * Add SwapDepositor * Fix cap check * Fix comment * Simplify usage of StableSwapper + fix tests * Add swap threshold * Remove this version of Router * Prepare structure for easier merge of dev * Rename GemLikes * Add _ prefix to internal functions * Move dust transfer to outer call * Allow for fee collection without liquidity removal * Using deposit cap per gem * Remove SwapDepositor * Add collect function to Depositor * Reorg directories * Rename maxSrcAmts -> caps + split Swapper tests * Add auth tests * Set StableSwapper config in one go * Apply suggestions from code review Co-authored-by: oldchili <130549691+oldchili@users.noreply.github.com> * Use immutable for buffer & swapper * Use reqOut instead of minPrice * Pre-calculate optimal deposit amounts * Add comments + fix events * Add fee collectFees flag + comment warning about minOut/reqOut mismatch * Add liquidity move test * Clean up StableSwapper access control * Split depositor tests * Add event tests * Remove buffer_ refs * Add revert tests * Add src checks * More tests for before and after hop operations * Remove redundant blank lines * More tests for StableSwapper * Remove redundant blank line in Depositor.t.sol * Remove unused TestUtils * Depositor interacts with pool directly * Add stable depositor * Align min/max/req var names * Add StableDepositor tests, missing collect * Now really add tests * Revert Depositor.t.sol changes * Apply suggestions from code review Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> * MintCallback revert message, tests * Actually add test, minor changes * Move automation's collect to keeper * Remove setApprovalForAll from buffer * Remove setApprovalForAll interface * Make facilitator warded, bots=>buds * Standarize short functions to multi-line, spaces * Remove more spaces in front of events * Reorder immutables according to ctr params * Fix spaces before immutable comments * Move PairConfig comments to the struct definition * Set swapper as SwapperLike directly * Add new lines at end of files * Fix some license identifiers * Pack hop,zzz,cap in swapper * Pack hop,zzz in depositor * Use buffer explicitly in MintCallbackData * Add UniV3 callee tests * Fix whitespaces * Increase slippage tolerance for testSwapLongPath * Use USDT instead of WETH in callee tests * Update test/funnels/callees/UniV3SwapperCallee.t.sol Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> * Use single struct for configuration * Minor fix * Use math libs from dss-kiln * Apply suggestions from code review Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> * Update test/funnels/Swapper.t.sol Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> * Update test/funnels/Swapper.t.sol Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> * Make sure zzz does not change in setLimits test * Align amt=>collect, test events with snapshot (except withdraw) * Test zzz also for Depositor's setLimits * Apply suggestions from code review Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> Co-authored-by: telome <130504305+telome@users.noreply.github.com> * Update src/funnels/Depositor.sol Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> * Move constant ot after immutable * Use named params in collect's burn call * Address Depositor.t.sol review comments * Apply suggestions from code review Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> * Return fees from Depositor.withdraw + misc (#22) * Return fees in Depositor * Fully check Depositor.Withdraw events * Withdraw to return fees0 and fees1, rename to those in collect * Test also withdraw events data * gem0, gem1 => src, dst in Swapper * Minor neats * Align vars and structs documentation, Capitalize comments * Clean up merge duplication * Remove spacing --------- Co-authored-by: telome <> Co-authored-by: oldchili <130549691+oldchili@users.noreply.github.com> Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> * Update test/funnels/automation/StableDepositor.t.sol Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> * Read position (#25) * Add getPosition * Return fees in Depositor * Fully check Depositor.Withdraw events * Withdraw to return fees0 and fees1, rename to those in collect * Test also withdraw events data * gem0, gem1 => src, dst in Swapper * Minor neats * Align vars and structs documentation, Capitalize comments * Clean up merge duplication --------- Co-authored-by: oldchili <130549691+oldchili@users.noreply.github.com> Co-authored-by: telome <> * Minor modifications to funnels tests + change default verbosity (#24) * Modify funnel test + change default verbosity * More changes to tests * Remove check that is semantically doesn't say much * Remove unused variables * Remove unused variables * Remove TestUtils (#27) * Smarter rate limiter using partial amounts (#26) * Swapper: Rate limit using partial amount * StableSwapper: add hop * Swapper reorder fields in limits structure * Partial amounts for Depositor and StableDepositor * Use same order * Change amts if greater than new cap in setLimits * amt => due * Add some missing variable documentation * Add missing zzz update * Fix name test contract * Improve storage packing + make deposit mapping keys more specific * Set due and zzz to 0 on SetLimits * Fix missing update of zzz * Add missing check + fix error message * Improve test coverage * Fix some comments * Set zzz to 0 in setConfig * Fix comments * Remove some unchecked blocks for better theoretical code correctness * Easier comparison to reason about * Fix for using just two slots in StableDepositor * Fix spacing * Fix comment * Minor change in test * nits * Minor * Minor * Avoid swapping directly to buffer (#28) * Avoid swapping directly to buffer * No need to get prev balance * Minor change in test * Revert "Minor change in test" This reverts commit 08e8cee1d14298fc5e43b071fda587b6eb601ead. --------- Co-authored-by: sunbreak * min => req * Minors Co-authored-by: oldchili <130549691+oldchili@users.noreply.github.com> * hop => era, zzz => end * More hop => era * Match order struct values Depositor with Swapper as it is also more logical packing * Fix aligment * StableDepositor: Make num signed int for separating deposit from withdraw (#29) * Changes in comments Co-authored-by: telome <130504305+telome@users.noreply.github.com> --------- Co-authored-by: oldchili <130549691+oldchili@users.noreply.github.com> Co-authored-by: telome <130504305+telome@users.noreply.github.com> * Rename Depositor to DepositorUniV3 + Callee renaming + Minor comment fix in Swapper (#30) * Rename Depositor to DepositorUniV3 + Minor comment fix in Swapper * UniV3SwapperCallee => SwapperCalleeUniV3 * Swapper Depositor Neats (#32) * Remove TODO of cheaper SLOAD * LiquidityAmounts - standard header, remove unused functions * Change licenses * Conduits Automated Mover (#33) * Conduit mover - initial version * Reordering and neats * Turn AllocatorConduitExample to a mock * Update test/funnels/automation/ConduitMover.t.sol Co-authored-by: telome <130504305+telome@users.noreply.github.com> --------- Co-authored-by: telome <130504305+telome@users.noreply.github.com> * Add automation keeper scripts * Minor simplification * Move addresses and chainId to arguments * Estimate gas prior to sending tx * Make scripts bash3-compatible * Add ConduitMover keeper script * Update script/funnels/automation/run_stable_depositor.sh Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> --------- Co-authored-by: sunbreak Co-authored-by: telome <> Co-authored-by: oldchili <130549691+oldchili@users.noreply.github.com> Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> --- .../funnels/automation/run_conduit_mover.sh | 40 +++++++++++++ .../automation/run_stable_depositor.sh | 56 +++++++++++++++++++ .../funnels/automation/run_stable_swapper.sh | 41 ++++++++++++++ 3 files changed, 137 insertions(+) create mode 100755 script/funnels/automation/run_conduit_mover.sh create mode 100755 script/funnels/automation/run_stable_depositor.sh create mode 100755 script/funnels/automation/run_stable_swapper.sh diff --git a/script/funnels/automation/run_conduit_mover.sh b/script/funnels/automation/run_conduit_mover.sh new file mode 100755 index 00000000..6372f0b3 --- /dev/null +++ b/script/funnels/automation/run_conduit_mover.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash + +# Usage: ./run_conduit_mover.sh $CHAINID $CONDUIT_MOVER_ADDR $FROM_BLOCK +# Example goerli usage: ./run_conduit_mover.sh 5 0x04e02dEa98410758e52cd0c47F07d9cc0fb15566 9440653 + +set -e + +CHAINID=$1 +CONDUIT_MOVER=$2 +FROM_BLOCK=${3:-"earliest"} + +[[ "$ETH_RPC_URL" && "$(cast chain-id)" == "$CHAINID" ]] || { echo -e "Please set a ETH_RPC_URL pointing to chainId $CHAINID"; exit 1; } + +SET_CONFIG_LOG="SetConfig(address indexed from, address indexed to, address indexed gem, uint64 num, uint32 hop, uint128 lot)" +MOVE_SIG="move(address from, address to, address gem)" + +JSON=$(cast logs --from-block $FROM_BLOCK --to-block latest --address $CONDUIT_MOVER "$SET_CONFIG_LOG" --json) +echo $JSON | jq -c '.[]' | while read i; do + from=$(cast abi-decode --input "x(address)" $(echo $i | jq -r ".topics[1]")) + to=$( cast abi-decode --input "x(address)" $(echo $i | jq -r ".topics[2]")) + gem=$( cast abi-decode --input "x(address)" $(echo $i | jq -r ".topics[3]")) + + params="$from $to $gem" + var="handled_${params// /_}" + if [ -z "${!var}" ]; then + declare handled_${params// /_}=1 + else + continue + fi + + cfg=$(cast call $CONDUIT_MOVER "configs(address,address,address)(uint64,uint32,uint32,uint128)" $params) + num=$(echo $cfg | cut -d" " -f1) + + if (( num > 0 )); then + echo "Num=$num. Moving $gem from conduit $from to conduit $to..." + gas=$(cast estimate $CONDUIT_MOVER "$MOVE_SIG" $params || true) + [[ -z "$gas" ]] && { continue; } + cast send --gas-limit $gas $CONDUIT_MOVER "$MOVE_SIG" $params + fi +done diff --git a/script/funnels/automation/run_stable_depositor.sh b/script/funnels/automation/run_stable_depositor.sh new file mode 100755 index 00000000..ac5173d6 --- /dev/null +++ b/script/funnels/automation/run_stable_depositor.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash + +# Usage: ./run_stable_depositor.sh $CHAINID $STABLE_DEPOSITOR_ADDR $FROM_BLOCK +# Example goerli usage: ./run_stable_depositor.sh 5 0x61928e1813c8883D14a75f31F3daeE53929A45DE 9422770 + +set -e + +CHAINID=$1 +STABLE_DEPOSITOR=$2 +FROM_BLOCK=${3:-"earliest"} + +[[ "$ETH_RPC_URL" && "$(cast chain-id)" == "$CHAINID" ]] || { echo -e "Please set a ETH_RPC_URL pointing to chainId $CHAINID"; exit 1; } + +SET_CONFIG_LOG="SetConfig(address indexed gem0, address indexed gem1, uint24 indexed fee, int24 tickLower, int24 tickUpper, int32 num, uint32 hop, uint96 amt0, uint96 amt1, uint96 req0, uint96 req1)" +DEPOSIT_SIG="deposit(address gem0, address gem1, uint24 fee, int24 tickLower, int24 tickUpper, uint128 amt0Min, uint128 amt1Min)" +WITHDRAW_SIG="withdraw(address gem0, address gem1, uint24 fee, int24 tickLower, int24 tickUpper, uint128 amt0Min, uint128 amt1Min)" + +JSON=$(cast logs --from-block $FROM_BLOCK --to-block latest --address $STABLE_DEPOSITOR "$SET_CONFIG_LOG" --json) +echo $JSON | jq -c '.[]' | while read i; do + gem0=$(cast abi-decode --input "x(address)" $(echo $i | jq -r ".topics[1]")) + gem1=$(cast abi-decode --input "x(address)" $(echo $i | jq -r ".topics[2]")) + fee=$(cast abi-decode --input "x(uint24)" $(echo $i | jq -r ".topics[3]")) + data=$(cast abi-decode --input "x(int24,int24)" $(echo $i | jq -r ".data")) + tickLower=$(echo $data | cut -d" " -f1) + tickUpper=$(echo $data | cut -d" " -f2) + + params="$gem0 $gem1 $fee $tickLower $tickUpper" + var="handled_${params//[- ]/_}" + if [ -z "${!var}" ]; then + declare handled_${params//[- ]/_}=1 + else + continue + fi + + cfg_calldata=$(cast calldata "configs(address,address,uint24,int24,int24)" $params) + # Note that we run `cast call` using the raw calldata to avoid issues with negative arguments + cfg=$(cast call $STABLE_DEPOSITOR $cfg_calldata) + decoded_cfg=$(cast abi-decode --input "x(int32,uint32,uint96,uint96,uint96,uint96,uint32)" $cfg) + num=$(echo $decoded_cfg | cut -d" " -f1) + + if (( num > 0 )); then + echo "Num=$num. Depositing into ($gem0, $gem1, $fee) pool..." + sig=$DEPOSIT_SIG + elif (( num < 0 )); then + echo "Num=$num. Withdrawing from ($gem0, $gem1, $fee) pool..." + sig=$WITHDRAW_SIG + fi + + if (( num )); then + calldata=$(cast calldata "$sig" $params 0 0) + # Note that we run `cast estimate` and `cast send` using the raw calldata to avoid issues with negative arguments + gas=$(cast estimate $STABLE_DEPOSITOR $calldata || true) + [[ -z "$gas" ]] && { continue; } + cast send --gas-limit $gas $STABLE_DEPOSITOR $calldata + fi +done diff --git a/script/funnels/automation/run_stable_swapper.sh b/script/funnels/automation/run_stable_swapper.sh new file mode 100755 index 00000000..79209996 --- /dev/null +++ b/script/funnels/automation/run_stable_swapper.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash + +# Usage: ./run_stable_swapper.sh $CHAINID $STABLE_SWAPPER_ADDR $CALLEE_ADDR $POOL_FEE $FROM_BLOCK +# Example goerli usage: ./run_stable_swapper.sh 5 0x4b4271cA5980a436972BEc4ad9870f773e2b3e11 0x8963f53392D35a6c9939804a924058aB981363e4 500 9416503 + +set -e + +CHAINID=$1 +STABLE_SWAPPER=$2 +CALLEE=$3 +POOL_FEE=$4 +FROM_BLOCK=${5:-"earliest"} + +[[ "$ETH_RPC_URL" && "$(cast chain-id)" == "$CHAINID" ]] || { echo -e "Please set a ETH_RPC_URL pointing to chainId $CHAINID"; exit 1; } + +SET_CONFIG_LOG="SetConfig(address indexed src, address indexed dst, uint128 num, uint32 hop, uint96 lot, uint96 req)" +SWAP_SIG="swap(address src, address dst, uint256 minOut, address callee, bytes calldata data)" + +JSON=$(cast logs --from-block $FROM_BLOCK --to-block latest --address $STABLE_SWAPPER "$SET_CONFIG_LOG" --json) +echo $JSON | jq -c '.[]' | while read i; do + src=$(cast abi-decode --input "x(address)" $(echo $i | jq -r ".topics[1]")) + dst=$(cast abi-decode --input "x(address)" $(echo $i | jq -r ".topics[2]")) + + var="handled_${src}_${dst}" + if [ -z "${!var}" ]; then + declare handled_${src}_${dst}=1 + else + continue + fi + + cfg=$(cast call $STABLE_SWAPPER "configs(address,address)(uint128,uint32,uint32,uint96,uint96)" $src $dst) + num=$(echo $cfg | cut -d" " -f1) + + if (( num > 0 )); then + echo "Num=$num. Swapping from $src to $dst..." + data="$(cast concat-hex $src $(printf "%06X" $(cast to-hex $POOL_FEE)) $dst)" + gas=$(cast estimate $STABLE_SWAPPER "$SWAP_SIG" $src $dst 0 $CALLEE $data || true) + [[ -z "$gas" ]] && { continue; } + cast send --gas-limit $gas $STABLE_SWAPPER "$SWAP_SIG" $src $dst 0 $CALLEE $data + fi +done From 40005875d2eb3f6dd67b6267e6091d75e0eed565 Mon Sep 17 00:00:00 2001 From: telome <130504305+telome@users.noreply.github.com> Date: Wed, 23 Aug 2023 18:09:49 +0100 Subject: [PATCH 44/74] Fix typo in uniswapV3MintCallback (#50) * Fix typo in uniswapV3MintCallback * Test uniswapV3MintCallback when both amt{i}Owed > 0 --------- Co-authored-by: telome <> --- src/funnels/DepositorUniV3.sol | 2 +- test/funnels/DepositorUniV3.t.sol | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/funnels/DepositorUniV3.sol b/src/funnels/DepositorUniV3.sol index 884641b1..491bc7cc 100644 --- a/src/funnels/DepositorUniV3.sol +++ b/src/funnels/DepositorUniV3.sol @@ -197,7 +197,7 @@ contract DepositorUniV3 { require(msg.sender == pool, "DepositorUniV3/sender-not-a-pool"); if (amt0Owed > 0) GemLike(decoded.gem0).transferFrom(buffer, msg.sender, amt0Owed); - if (amt0Owed > 0) GemLike(decoded.gem1).transferFrom(buffer, msg.sender, amt1Owed); + if (amt1Owed > 0) GemLike(decoded.gem1).transferFrom(buffer, msg.sender, amt1Owed); } struct LiquidityParams { diff --git a/test/funnels/DepositorUniV3.t.sol b/test/funnels/DepositorUniV3.t.sol index 1bc12fda..c89dad53 100644 --- a/test/funnels/DepositorUniV3.t.sol +++ b/test/funnels/DepositorUniV3.t.sol @@ -795,6 +795,18 @@ contract DepositorUniV3Test is DssTest { vm.prank(DAI_USDC_POOL); depositor.uniswapV3MintCallback({ amt0Owed: 1, + amt1Owed: 0, + data: abi.encode(DepositorUniV3.MintCallbackData({gem0: DAI, gem1: USDC, fee: 100})) + }); + + assertEq(GemLike(DAI).balanceOf(address(buffer)), initialDAI - 1); + assertEq(GemLike(USDC).balanceOf(address(buffer)), initialUSDC); + assertEq(GemLike(DAI).balanceOf(DAI_USDC_POOL), initialPoolDAI + 1); + assertEq(GemLike(USDC).balanceOf(DAI_USDC_POOL), initialPoolUSDC); + + vm.prank(DAI_USDC_POOL); + depositor.uniswapV3MintCallback({ + amt0Owed: 0, amt1Owed: 2, data: abi.encode(DepositorUniV3.MintCallbackData({gem0: DAI, gem1: USDC, fee: 100})) }); @@ -803,6 +815,18 @@ contract DepositorUniV3Test is DssTest { assertEq(GemLike(USDC).balanceOf(address(buffer)), initialUSDC - 2); assertEq(GemLike(DAI).balanceOf(DAI_USDC_POOL), initialPoolDAI + 1); assertEq(GemLike(USDC).balanceOf(DAI_USDC_POOL), initialPoolUSDC + 2); + + vm.prank(DAI_USDC_POOL); + depositor.uniswapV3MintCallback({ + amt0Owed: 10, + amt1Owed: 20, + data: abi.encode(DepositorUniV3.MintCallbackData({gem0: DAI, gem1: USDC, fee: 100})) + }); + + assertEq(GemLike(DAI).balanceOf(address(buffer)), initialDAI - 11); + assertEq(GemLike(USDC).balanceOf(address(buffer)), initialUSDC - 22); + assertEq(GemLike(DAI).balanceOf(DAI_USDC_POOL), initialPoolDAI + 11); + assertEq(GemLike(USDC).balanceOf(DAI_USDC_POOL), initialPoolUSDC + 22); } function testMintCallbackNotFromPool() public { From e8275c8c435f5fdc012e8f0a52e8004b3c4c3b3a Mon Sep 17 00:00:00 2001 From: telome <130504305+telome@users.noreply.github.com> Date: Tue, 29 Aug 2023 12:34:20 +0100 Subject: [PATCH 45/74] Remove path validation from callee (#54) Co-authored-by: telome <> --- src/funnels/callees/SwapperCalleeUniV3.sol | 14 ++------------ test/funnels/callees/SwapperCalleeUniV3.t.sol | 7 ------- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/src/funnels/callees/SwapperCalleeUniV3.sol b/src/funnels/callees/SwapperCalleeUniV3.sol index 99aee0de..e05a3689 100644 --- a/src/funnels/callees/SwapperCalleeUniV3.sol +++ b/src/funnels/callees/SwapperCalleeUniV3.sol @@ -42,20 +42,10 @@ contract SwapperCalleeUniV3 { uniV3Router = _uniV3Router; } - function swapCallback(address src, address dst, uint256 amt, uint256 minOut, address to, bytes calldata data) external { - bytes memory path = data; - - address firstToken; - address lastToken; - assembly { - firstToken := div(mload(add(path, 0x20)), 0x1000000000000000000000000) - lastToken := div(mload(sub(add(add(path, 0x20), mload(path)), 0x14)), 0x1000000000000000000000000) - } - require(src == firstToken && dst == lastToken, "SwapperCalleeUniV3/invalid-path"); - + function swapCallback(address src, address /* dst */, uint256 amt, uint256 minOut, address to, bytes calldata data) external { ApproveLike(src).approve(uniV3Router, amt); SwapRouterLike.ExactInputParams memory params = SwapRouterLike.ExactInputParams({ - path: path, + path: data, recipient: to, deadline: block.timestamp, amountIn: amt, diff --git a/test/funnels/callees/SwapperCalleeUniV3.t.sol b/test/funnels/callees/SwapperCalleeUniV3.t.sol index a454c3ed..16a4891d 100644 --- a/test/funnels/callees/SwapperCalleeUniV3.t.sol +++ b/test/funnels/callees/SwapperCalleeUniV3.t.sol @@ -57,11 +57,4 @@ contract SwapperCalleeUniV3Test is DssTest { bytes memory USDC_USDT_DAI_PATH = abi.encodePacked(USDC, uint24(100), USDT, uint24(100), DAI); checkStableSwap(USDC, DAI, USDC_USDT_DAI_PATH); } - - function testSwapInvalidPath() public { - bytes memory USDC_USDT_DAI_PATH = abi.encodePacked(USDC, uint24(100), USDT, uint24(100), DAI); - - vm.expectRevert("SwapperCalleeUniV3/invalid-path"); - this.checkStableSwap(DAI, USDC, USDC_USDT_DAI_PATH); - } } From a8bdf0790e1fc040397e3f4d25e4284afd0afa2b Mon Sep 17 00:00:00 2001 From: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> Date: Tue, 29 Aug 2023 08:46:40 -0300 Subject: [PATCH 46/74] Remove init function and use grab in spell set up (#53) --- src/AllocatorVault.sol | 6 ------ test/AllocatorVault.t.sol | 28 ++++------------------------ test/mocks/VatMock.sol | 9 +++++++++ 3 files changed, 13 insertions(+), 30 deletions(-) diff --git a/src/AllocatorVault.sol b/src/AllocatorVault.sol index b16e2619..8e365a4f 100644 --- a/src/AllocatorVault.sol +++ b/src/AllocatorVault.sol @@ -79,7 +79,6 @@ contract AllocatorVault { event Rely(address indexed usr); event Deny(address indexed usr); event File(bytes32 indexed what, address data); - event Init(); event Draw(address indexed sender, uint256 wad); event Wipe(address indexed sender, uint256 wad); @@ -143,11 +142,6 @@ contract AllocatorVault { // --- administration --- - function init() external auth { - vat.frob(ilk, address(this), address(this), address(0), int256(10**6 * WAD), 0); - emit Init(); - } - function rely(address usr) external auth { wards[usr] = 1; emit Rely(usr); diff --git a/test/AllocatorVault.t.sol b/test/AllocatorVault.t.sol index 5b006a54..51d13ff7 100644 --- a/test/AllocatorVault.t.sol +++ b/test/AllocatorVault.t.sol @@ -45,6 +45,7 @@ contract AllocatorVaultTest is DssTest { buffer.approve(address(nst), address(vault), type(uint256).max); vat.slip(ilk, address(vault), int256(1_000_000 * WAD)); + vat.grab(ilk, address(vault), address(vault), address(0), int256(1_000_000 * WAD), 0); // Add some existing DAI assigned to nstJoin to avoid a particular error stdstore.target(address(vat)).sig("dai(address)").with_key(address(nstJoin)).depth(0).checked_write(100_000 * RAD); @@ -55,10 +56,9 @@ contract AllocatorVaultTest is DssTest { } function testModifiers() public { - bytes4[] memory authedMethods = new bytes4[](3); - authedMethods[0] = vault.init.selector; - authedMethods[1] = bytes4(keccak256("draw(uint256)")); - authedMethods[2] = bytes4(keccak256("wipe(uint256)")); + bytes4[] memory authedMethods = new bytes4[](2); + authedMethods[0] = vault.draw.selector; + authedMethods[1] = vault.wipe.selector; vm.startPrank(address(0xBEEF)); checkModifier(address(vault), "AllocatorVault/not-authorized", authedMethods); @@ -77,26 +77,7 @@ contract AllocatorVaultTest is DssTest { vault.file("jug", address(0)); } - function testInit() public { - assertEq(vat.gem(ilk, address(vault)), 10**6 * WAD); - (uint256 ink, ) = vat.urns(ilk, address(vault)); - assertEq(ink, 0); - vault.init(); - assertEq(vat.gem(ilk, address(vault)), 0); - (ink, ) = vat.urns(ilk, address(vault)); - assertEq(ink, 10**6 * WAD); - } - - function testInitNotEnoughBalance() public { - vat.slip(ilk, address(vault), -1); - vm.expectRevert(); - vault.init(); - } - function testDrawWipe() public { - vm.expectEmit(true, true, true, true); - emit Init(); - vault.init(); vault.file("jug", address(jug)); assertEq(vault.line(), 20_000_000 * 10**18); (, uint256 art) = vat.urns(ilk, address(buffer)); @@ -138,7 +119,6 @@ contract AllocatorVaultTest is DssTest { } function testDebtOverLine() public { - vault.init(); vault.file("jug", address(jug)); vm.expectEmit(true, true, true, true); emit Draw(address(this), vault.line()); diff --git a/test/mocks/VatMock.sol b/test/mocks/VatMock.sol index 1880ec21..4d25af28 100644 --- a/test/mocks/VatMock.sol +++ b/test/mocks/VatMock.sol @@ -44,6 +44,15 @@ contract VatMock { gem[ilk][usr] = wad >= 0 ? gem[ilk][usr] + uint256(wad) : gem[ilk][usr] - uint256(-wad); } + function grab(bytes32 i, address u, address v, address, int dink, int dart) external { + Urn storage urn = urns[i][u]; + + urn.ink = dink >= 0 ? urn.ink + uint256(dink) : urn.ink - uint256(-dink); + urn.art = dart >= 0 ? urn.art + uint256(dart) : urn.art - uint256(-dart); + Art = dart >= 0 ? Art + uint256(dart) : Art - uint256(-dart); + gem[i][v] = dink >= 0 ? gem[i][v] - uint256(dink) : gem[i][v] + uint256(-dink); + } + function fold(uint256 rate_) external { rate = rate + rate_; } From 0ff5f8d332a57cc77ddc2976406a74e514c80db9 Mon Sep 17 00:00:00 2001 From: telome <130504305+telome@users.noreply.github.com> Date: Tue, 29 Aug 2023 12:48:10 +0100 Subject: [PATCH 47/74] Minor gas optimisations (#55) Co-authored-by: telome <> --- src/AllocatorVault.sol | 2 +- src/funnels/DepositorUniV3.sol | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/AllocatorVault.sol b/src/AllocatorVault.sol index 8e365a4f..1387ed39 100644 --- a/src/AllocatorVault.sol +++ b/src/AllocatorVault.sol @@ -176,7 +176,7 @@ contract AllocatorVault { uint256 rate = jug.drip(ilk); uint256 dart = wad * RAY / rate; require(dart <= uint256(type(int256).max), "AllocatorVault/overflow"); - vat.frob(ilk, address(this), address(this), address(this), 0, -int256(dart)); + vat.frob(ilk, address(this), address(0), address(this), 0, -int256(dart)); emit Wipe(msg.sender, wad); } } diff --git a/src/funnels/DepositorUniV3.sol b/src/funnels/DepositorUniV3.sol index 491bc7cc..ae4cda90 100644 --- a/src/funnels/DepositorUniV3.sol +++ b/src/funnels/DepositorUniV3.sol @@ -229,8 +229,7 @@ contract DepositorUniV3 { // Reset batch limit.due0 = limits[p.gem0][p.gem1][p.fee].cap0; limit.due1 = limits[p.gem0][p.gem1][p.fee].cap1; - limit.era = limits[p.gem0][p.gem1][p.fee].era; - limit.end = uint32(block.timestamp) + limit.era; + limit.end = uint32(block.timestamp) + limits[p.gem0][p.gem1][p.fee].era; } UniV3PoolLike pool = _getPool(p.gem0, p.gem1, p.fee); @@ -271,8 +270,7 @@ contract DepositorUniV3 { // Reset batch limit.due0 = limits[p.gem0][p.gem1][p.fee].cap0; limit.due1 = limits[p.gem0][p.gem1][p.fee].cap1; - limit.era = limits[p.gem0][p.gem1][p.fee].era; - limit.end = uint32(block.timestamp) + limit.era; + limit.end = uint32(block.timestamp) + limits[p.gem0][p.gem1][p.fee].era; } UniV3PoolLike pool = _getPool(p.gem0, p.gem1, p.fee); From c0ba9ee98516df8e9a65236938cbaf58c83ffdc0 Mon Sep 17 00:00:00 2001 From: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> Date: Tue, 29 Aug 2023 14:05:19 -0300 Subject: [PATCH 48/74] Remove Vault getters + some old unused interfaces (#56) --- src/AllocatorVault.sol | 34 +--------------------------------- test/AllocatorVault.t.sol | 16 ---------------- 2 files changed, 1 insertion(+), 49 deletions(-) diff --git a/src/AllocatorVault.sol b/src/AllocatorVault.sol index 1387ed39..d8911ed3 100644 --- a/src/AllocatorVault.sol +++ b/src/AllocatorVault.sol @@ -22,9 +22,6 @@ interface RolesLike { } interface VatLike { - function ilks(bytes32) external view returns (uint256, uint256, uint256, uint256, uint256); - function live() external view returns (uint256); - function urns(bytes32, address) external view returns (uint256, uint256); function frob(bytes32, address, address, address, int256, int256) external; function hope(address) external; } @@ -34,18 +31,10 @@ interface JugLike { } interface GemLike { - function totalSupply() external view returns (uint256); function approve(address, uint256) external; function transferFrom(address, address, uint256) external; } -interface GemJoinLike { - function gem() external view returns (GemLike); - function ilk() external view returns (bytes32); - function vat() external view returns (address); - function join(address, uint256) external; -} - interface NstJoinLike { function nst() external view returns (GemLike); function vat() external view returns (address); @@ -102,7 +91,7 @@ contract AllocatorVault { require(vat_ == nstJoin.vat(), "AllocatorVault/vat-not-match"); - nst = NstJoinLike(nstJoin_).nst(); + nst = nstJoin.nst(); VatLike(vat_).hope(nstJoin_); nst.approve(nstJoin_, type(uint256).max); @@ -119,27 +108,6 @@ contract AllocatorVault { } } - // --- getters --- - // In theory, `ilk.Art` should be equal to `urn.art` for this type of collateral, as there should only be one position per `ilk`. - // However to stick with the correct usage, `ilk.Art` is used for calculating `slot()` and `urn.art` for the `debt()` of this position. - - function debt() external view returns (uint256) { - (, uint256 art) = vat.urns(ilk, address(this)); - (, uint256 rate,,,) = vat.ilks(ilk); - return _divup(art * rate, RAY); - } - - function line() external view returns (uint256) { - (,,, uint256 line_,) = vat.ilks(ilk); - return line_ / RAY; - } - - function slot() external view returns (uint256) { - (uint256 Art, uint256 rate,, uint256 line_,) = vat.ilks(ilk); - uint256 debt_ = Art * rate; - return line_ > debt_ ? (line_ - debt_) / RAY : 0; - } - // --- administration --- function rely(address usr) external auth { diff --git a/test/AllocatorVault.t.sol b/test/AllocatorVault.t.sol index 51d13ff7..a12ff469 100644 --- a/test/AllocatorVault.t.sol +++ b/test/AllocatorVault.t.sol @@ -79,7 +79,6 @@ contract AllocatorVaultTest is DssTest { function testDrawWipe() public { vault.file("jug", address(jug)); - assertEq(vault.line(), 20_000_000 * 10**18); (, uint256 art) = vat.urns(ilk, address(buffer)); assertEq(art, 0); vm.expectEmit(true, true, true, true); @@ -88,8 +87,6 @@ contract AllocatorVaultTest is DssTest { (, art) = vat.urns(ilk, address(vault)); assertEq(art, 50 * 10**18); assertEq(vat.rate(), 10**27); - assertEq(vault.debt(), 50 * 10**18); - assertEq(vault.slot(), vault.line() - 50 * 10**18); assertEq(nst.balanceOf(address(buffer)), 50 * 10**18); vm.warp(block.timestamp + 1); vm.expectEmit(true, true, true, true); @@ -99,8 +96,6 @@ contract AllocatorVaultTest is DssTest { uint256 expectedArt = 50 * 10**18 + _divup(50 * 10**18 * 1000, 1001); assertEq(art, expectedArt); assertEq(vat.rate(), 1001 * 10**27 / 1000); - assertEq(vault.debt(), _divup(expectedArt * 1001, 1000)); - assertEq(vault.slot(), vault.line() - _divup(expectedArt * 1001, 1000)); assertEq(nst.balanceOf(address(buffer)), 100 * 10**18); assertGt(art * vat.rate(), 100.05 * 10**45); assertLt(art * vat.rate(), 100.06 * 10**45); @@ -117,15 +112,4 @@ contract AllocatorVaultTest is DssTest { (, art) = vat.urns(ilk, address(vault)); assertEq(art, 1); // Dust which is impossible to wipe } - - function testDebtOverLine() public { - vault.file("jug", address(jug)); - vm.expectEmit(true, true, true, true); - emit Draw(address(this), vault.line()); - vault.draw(vault.line()); - vm.warp(block.timestamp + 1); - jug.drip(ilk); - assertGt(vault.debt(), vault.line()); - assertEq(vault.slot(), 0); - } } From a5469884813528b414ec1c2b985f52dd192455a1 Mon Sep 17 00:00:00 2001 From: oldchili <130549691+oldchili@users.noreply.github.com> Date: Tue, 29 Aug 2023 21:04:11 +0300 Subject: [PATCH 49/74] Add unchecked to the 2 functions in TickMath.sol (#51) --- src/funnels/uniV3/TickMath.sol | 404 +++++++++++++++++---------------- 1 file changed, 204 insertions(+), 200 deletions(-) diff --git a/src/funnels/uniV3/TickMath.sol b/src/funnels/uniV3/TickMath.sol index 17f75475..4949fc14 100644 --- a/src/funnels/uniV3/TickMath.sol +++ b/src/funnels/uniV3/TickMath.sol @@ -30,63 +30,65 @@ library TickMath { pure returns (uint160 sqrtPriceX96) { - uint256 absTick = - tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick)); + unchecked { + uint256 absTick = + tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick)); - // EDIT: 0.8 compatibility - require(absTick <= uint256(int256(MAX_TICK)), "T"); + // EDIT: 0.8 compatibility + require(absTick <= uint256(int256(MAX_TICK)), "T"); - uint256 ratio = - absTick & 0x1 != 0 - ? 0xfffcb933bd6fad37aa2d162d1a594001 - : 0x100000000000000000000000000000000; - if (absTick & 0x2 != 0) - ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128; - if (absTick & 0x4 != 0) - ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128; - if (absTick & 0x8 != 0) - ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128; - if (absTick & 0x10 != 0) - ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128; - if (absTick & 0x20 != 0) - ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128; - if (absTick & 0x40 != 0) - ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128; - if (absTick & 0x80 != 0) - ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128; - if (absTick & 0x100 != 0) - ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128; - if (absTick & 0x200 != 0) - ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128; - if (absTick & 0x400 != 0) - ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128; - if (absTick & 0x800 != 0) - ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128; - if (absTick & 0x1000 != 0) - ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128; - if (absTick & 0x2000 != 0) - ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128; - if (absTick & 0x4000 != 0) - ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128; - if (absTick & 0x8000 != 0) - ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128; - if (absTick & 0x10000 != 0) - ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128; - if (absTick & 0x20000 != 0) - ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128; - if (absTick & 0x40000 != 0) - ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128; - if (absTick & 0x80000 != 0) - ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128; + uint256 ratio = + absTick & 0x1 != 0 + ? 0xfffcb933bd6fad37aa2d162d1a594001 + : 0x100000000000000000000000000000000; + if (absTick & 0x2 != 0) + ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128; + if (absTick & 0x4 != 0) + ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128; + if (absTick & 0x8 != 0) + ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128; + if (absTick & 0x10 != 0) + ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128; + if (absTick & 0x20 != 0) + ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128; + if (absTick & 0x40 != 0) + ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128; + if (absTick & 0x80 != 0) + ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128; + if (absTick & 0x100 != 0) + ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128; + if (absTick & 0x200 != 0) + ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128; + if (absTick & 0x400 != 0) + ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128; + if (absTick & 0x800 != 0) + ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128; + if (absTick & 0x1000 != 0) + ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128; + if (absTick & 0x2000 != 0) + ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128; + if (absTick & 0x4000 != 0) + ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128; + if (absTick & 0x8000 != 0) + ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128; + if (absTick & 0x10000 != 0) + ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128; + if (absTick & 0x20000 != 0) + ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128; + if (absTick & 0x40000 != 0) + ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128; + if (absTick & 0x80000 != 0) + ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128; - if (tick > 0) ratio = type(uint256).max / ratio; + if (tick > 0) ratio = type(uint256).max / ratio; - // this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96. - // we then downcast because we know the result always fits within 160 bits due to our tick input constraint - // we round up in the division so getTickAtSqrtRatio of the output price is always consistent - sqrtPriceX96 = uint160( - (ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1) - ); + // this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96. + // we then downcast because we know the result always fits within 160 bits due to our tick input constraint + // we round up in the division so getTickAtSqrtRatio of the output price is always consistent + sqrtPriceX96 = uint160( + (ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1) + ); + } } /// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio @@ -99,160 +101,162 @@ library TickMath { pure returns (int24 tick) { - // second inequality must be < because the price can never reach the price at the max tick - require( - sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO, - "R" - ); - uint256 ratio = uint256(sqrtPriceX96) << 32; + unchecked { + // second inequality must be < because the price can never reach the price at the max tick + require( + sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO, + "R" + ); + uint256 ratio = uint256(sqrtPriceX96) << 32; - uint256 r = ratio; - uint256 msb = 0; + uint256 r = ratio; + uint256 msb = 0; - assembly { - let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) - msb := or(msb, f) - r := shr(f, r) - } - assembly { - let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF)) - msb := or(msb, f) - r := shr(f, r) - } - assembly { - let f := shl(5, gt(r, 0xFFFFFFFF)) - msb := or(msb, f) - r := shr(f, r) - } - assembly { - let f := shl(4, gt(r, 0xFFFF)) - msb := or(msb, f) - r := shr(f, r) - } - assembly { - let f := shl(3, gt(r, 0xFF)) - msb := or(msb, f) - r := shr(f, r) - } - assembly { - let f := shl(2, gt(r, 0xF)) - msb := or(msb, f) - r := shr(f, r) - } - assembly { - let f := shl(1, gt(r, 0x3)) - msb := or(msb, f) - r := shr(f, r) - } - assembly { - let f := gt(r, 0x1) - msb := or(msb, f) - } + assembly { + let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) + msb := or(msb, f) + r := shr(f, r) + } + assembly { + let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF)) + msb := or(msb, f) + r := shr(f, r) + } + assembly { + let f := shl(5, gt(r, 0xFFFFFFFF)) + msb := or(msb, f) + r := shr(f, r) + } + assembly { + let f := shl(4, gt(r, 0xFFFF)) + msb := or(msb, f) + r := shr(f, r) + } + assembly { + let f := shl(3, gt(r, 0xFF)) + msb := or(msb, f) + r := shr(f, r) + } + assembly { + let f := shl(2, gt(r, 0xF)) + msb := or(msb, f) + r := shr(f, r) + } + assembly { + let f := shl(1, gt(r, 0x3)) + msb := or(msb, f) + r := shr(f, r) + } + assembly { + let f := gt(r, 0x1) + msb := or(msb, f) + } - if (msb >= 128) r = ratio >> (msb - 127); - else r = ratio << (127 - msb); + if (msb >= 128) r = ratio >> (msb - 127); + else r = ratio << (127 - msb); - int256 log_2 = (int256(msb) - 128) << 64; + int256 log_2 = (int256(msb) - 128) << 64; - assembly { - r := shr(127, mul(r, r)) - let f := shr(128, r) - log_2 := or(log_2, shl(63, f)) - r := shr(f, r) - } - assembly { - r := shr(127, mul(r, r)) - let f := shr(128, r) - log_2 := or(log_2, shl(62, f)) - r := shr(f, r) - } - assembly { - r := shr(127, mul(r, r)) - let f := shr(128, r) - log_2 := or(log_2, shl(61, f)) - r := shr(f, r) - } - assembly { - r := shr(127, mul(r, r)) - let f := shr(128, r) - log_2 := or(log_2, shl(60, f)) - r := shr(f, r) - } - assembly { - r := shr(127, mul(r, r)) - let f := shr(128, r) - log_2 := or(log_2, shl(59, f)) - r := shr(f, r) - } - assembly { - r := shr(127, mul(r, r)) - let f := shr(128, r) - log_2 := or(log_2, shl(58, f)) - r := shr(f, r) - } - assembly { - r := shr(127, mul(r, r)) - let f := shr(128, r) - log_2 := or(log_2, shl(57, f)) - r := shr(f, r) - } - assembly { - r := shr(127, mul(r, r)) - let f := shr(128, r) - log_2 := or(log_2, shl(56, f)) - r := shr(f, r) - } - assembly { - r := shr(127, mul(r, r)) - let f := shr(128, r) - log_2 := or(log_2, shl(55, f)) - r := shr(f, r) - } - assembly { - r := shr(127, mul(r, r)) - let f := shr(128, r) - log_2 := or(log_2, shl(54, f)) - r := shr(f, r) - } - assembly { - r := shr(127, mul(r, r)) - let f := shr(128, r) - log_2 := or(log_2, shl(53, f)) - r := shr(f, r) - } - assembly { - r := shr(127, mul(r, r)) - let f := shr(128, r) - log_2 := or(log_2, shl(52, f)) - r := shr(f, r) - } - assembly { - r := shr(127, mul(r, r)) - let f := shr(128, r) - log_2 := or(log_2, shl(51, f)) - r := shr(f, r) - } - assembly { - r := shr(127, mul(r, r)) - let f := shr(128, r) - log_2 := or(log_2, shl(50, f)) - } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(63, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(62, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(61, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(60, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(59, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(58, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(57, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(56, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(55, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(54, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(53, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(52, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(51, f)) + r := shr(f, r) + } + assembly { + r := shr(127, mul(r, r)) + let f := shr(128, r) + log_2 := or(log_2, shl(50, f)) + } - int256 log_sqrt10001 = log_2 * 255738958999603826347141; // 128.128 number + int256 log_sqrt10001 = log_2 * 255738958999603826347141; // 128.128 number - int24 tickLow = - int24( - (log_sqrt10001 - 3402992956809132418596140100660247210) >> 128 - ); - int24 tickHi = - int24( - (log_sqrt10001 + 291339464771989622907027621153398088495) >> 128 - ); + int24 tickLow = + int24( + (log_sqrt10001 - 3402992956809132418596140100660247210) >> 128 + ); + int24 tickHi = + int24( + (log_sqrt10001 + 291339464771989622907027621153398088495) >> 128 + ); - tick = tickLow == tickHi - ? tickLow - : getSqrtRatioAtTick(tickHi) <= sqrtPriceX96 - ? tickHi - : tickLow; + tick = tickLow == tickHi + ? tickLow + : getSqrtRatioAtTick(tickHi) <= sqrtPriceX96 + ? tickHi + : tickLow; + } } } From c3e065cb72fb6e8667601e0e9d0cc52bec61be0d Mon Sep 17 00:00:00 2001 From: oldchili <130549691+oldchili@users.noreply.github.com> Date: Mon, 4 Sep 2023 17:02:43 +0300 Subject: [PATCH 50/74] Readme Additions (#57) * Readme Additions * Update README.md Co-authored-by: telome <130504305+telome@users.noreply.github.com> --------- Co-authored-by: telome <130504305+telome@users.noreply.github.com> --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index a9fd0e18..765a44c7 100644 --- a/README.md +++ b/README.md @@ -144,4 +144,7 @@ An interface which each Conduit should implement. - In the Swapper, in case `limit.era` is zero the full cap amount can be swapped for multiple times in the same transaction because `limit.due` will be reset upon re-entry. However, this is consistent with the intended behavior, as in that case zero cooldown is explicitly defined. - In StableSwapper the keeper's minimal out value is assumed to be updated whenever `configs[src][dst]` is changed. Failing to do so may result in the swap call reverting or in taking on more slippage than intended (up to a limit controlled by `configs[src][dst].min`). - In StableDepositorUniV3 the keeper's minimal amt values are assumed to be updated whenever `configs[gem0][gem1][fee][tickLower][tickUpper]` is changed. Failing to do so may result in the deposit/withdraw call reverting or in taking on more slippage than intended (up to a limit controlled by `configs[gem0][gem1][fee][tickLower][tickUpper].req0/1`). +- Deployment sanity checks are done as part of the init functions (see the `deploy` directory). +- DepositorUniV3 has limits for the maximum amount of a pair of tokens that can be added or removed from the pool per era. The rate is purposefully shared between the deposit and withdraw operations (so both actions share the same capacity). +- The AllocatorDAO Proxy configuring the different rate limits is assumed to know what it is doing and is allowed to set any configuration, even if one configuration collides or duplicates others. - The Allocation System assumes that the ESM threshold is set large enough prior to its deployment, so Emergency Shutdown can never be called. From bdda5facbfc9ff8fafe9e85789c071535dd921f5 Mon Sep 17 00:00:00 2001 From: oldchili <130549691+oldchili@users.noreply.github.com> Date: Tue, 5 Sep 2023 17:46:31 +0300 Subject: [PATCH 51/74] Add ChainSecurity and FPS audits (#58) --- ...ChainSecurity_Maker_DSS_Allocator_audit.pdf | Bin 0 -> 537709 bytes audit/FPS_dss-allocator_Assessment_FINAL.pdf | Bin 0 -> 129787 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 audit/ChainSecurity_Maker_DSS_Allocator_audit.pdf create mode 100644 audit/FPS_dss-allocator_Assessment_FINAL.pdf diff --git a/audit/ChainSecurity_Maker_DSS_Allocator_audit.pdf b/audit/ChainSecurity_Maker_DSS_Allocator_audit.pdf new file mode 100644 index 0000000000000000000000000000000000000000..eff50f81337935f55211ecfc6d7cda73bd4ab753 GIT binary patch literal 537709 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 z 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 QeH`S3-f}+sM<^7Q=x3LjwZ7V7Ff-3)h| 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 z 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 literal 0 HcmV?d00001 diff --git a/audit/FPS_dss-allocator_Assessment_FINAL.pdf b/audit/FPS_dss-allocator_Assessment_FINAL.pdf new file mode 100644 index 0000000000000000000000000000000000000000..4c6c98220443a782e23936572c25269aa867881e GIT binary patch literal 129787 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�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 literal 0 HcmV?d00001 From 9403ef259f5d321b87be67aaaaeb0cd8380a72ca Mon Sep 17 00:00:00 2001 From: oldchili <130549691+oldchili@users.noreply.github.com> Date: Tue, 12 Sep 2023 20:37:28 +0300 Subject: [PATCH 52/74] Deployment Scripts (#49) * Deployment scripts - wip * Minimize functions, init all from PP * Add ConduitMover, solve compilation issues * Add changelog values * Update src/deploy/AllocatorInit.sol Co-authored-by: telome <130504305+telome@users.noreply.github.com> * put in ilk registry, sanity checks * WIP * test cleaups * Move deploy out of src * Remove init function and use grab in spell set up * vat.grab in init script instead of vault's removed init() * Update alignment in deploy/AllocatorInit.sol Co-authored-by: telome <130504305+telome@users.noreply.github.com> * Gems => Tokens * Apply suggestions from code review Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> Co-authored-by: telome <130504305+telome@users.noreply.github.com> * deployNetwork => deployIlk * initAllocator => initIlk * More network => ilk renamings * Alignment after renaming * Add comment to verify nstJoin once in dss-test * Set duty * Switch to use class 5 in the registry * Use contracts as interfaces in Deployment.t.sol * Add missing check for collect * Support multiple facilitators and keepers * AllocatorConfig=>AllocatorIlkConfig * Pass ilk explicitly to initIlk * Creak the ilk's chainlog keys automaticaly * Use ilk string as ilk resitry name and symbol * Use bytes32ToStr to conserve dash in ilk registy names * Update deploy/AllocatorDeploy.sol Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> * Fix return values * Correct checking that PP is denied * Use ScriptTools.switchOwner in AllocatorInit.sol * better bytes32ToStr * Do not use bytes32ToStr in test * Add PIP chainlog entry per ilk * Remove Allocator from CL keys * Fetch vat from NstJoin (#59) * Fetch vat from nst join * nstJoin.vat() to return VatLike --------- Co-authored-by: telome <130504305+telome@users.noreply.github.com> Co-authored-by: sunbreak Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> --- deploy/AllocatorDeploy.sol | 94 +++++++ deploy/AllocatorInit.sol | 297 +++++++++++++++++++++ deploy/AllocatorInstances.sol | 34 +++ src/AllocatorVault.sol | 10 +- test/AllocatorVault.t.sol | 2 +- test/integration/Deployment.t.sol | 413 ++++++++++++++++++++++++++++++ 6 files changed, 843 insertions(+), 7 deletions(-) create mode 100644 deploy/AllocatorDeploy.sol create mode 100644 deploy/AllocatorInit.sol create mode 100644 deploy/AllocatorInstances.sol create mode 100644 test/integration/Deployment.t.sol diff --git a/deploy/AllocatorDeploy.sol b/deploy/AllocatorDeploy.sol new file mode 100644 index 00000000..5ea8de5a --- /dev/null +++ b/deploy/AllocatorDeploy.sol @@ -0,0 +1,94 @@ +// SPDX-FileCopyrightText: © 2023 Dai Foundation +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +pragma solidity ^0.8.16; + +import { ScriptTools } from "dss-test/ScriptTools.sol"; + +import { AllocatorOracle } from "src/AllocatorOracle.sol"; +import { AllocatorRoles } from "src/AllocatorRoles.sol"; +import { AllocatorRegistry } from "src/AllocatorRegistry.sol"; +import { AllocatorBuffer } from "src/AllocatorBuffer.sol"; +import { AllocatorVault } from "src/AllocatorVault.sol"; +import { Swapper } from "src/funnels/Swapper.sol"; +import { DepositorUniV3 } from "src/funnels/DepositorUniV3.sol"; +import { StableSwapper } from "src/funnels/automation/StableSwapper.sol"; +import { StableDepositorUniV3 } from "src/funnels/automation/StableDepositorUniV3.sol"; +import { ConduitMover } from "src/funnels/automation/ConduitMover.sol"; + +import { AllocatorSharedInstance, AllocatorIlkInstance } from "./AllocatorInstances.sol"; + + +library AllocatorDeploy { + + // Note: owner is assumed to be the pause proxy + function deployShared( + address deployer, + address owner + ) internal returns (AllocatorSharedInstance memory sharedInstance) { + address _oracle = address(new AllocatorOracle()); + + address _roles = address(new AllocatorRoles()); + ScriptTools.switchOwner(_roles, deployer, owner); + + address _registry = address(new AllocatorRegistry()); + ScriptTools.switchOwner(_registry, deployer, owner); + + sharedInstance.oracle = _oracle; + sharedInstance.roles = _roles; + sharedInstance.registry = _registry; + } + + // Note: owner is assumed to be the pause proxy, allocator proxy will receive ownerships on init + function deployIlk( + address deployer, + address owner, + address roles, + bytes32 ilk, + address nstJoin, + address uniV3Factory + ) internal returns (AllocatorIlkInstance memory ilkInstance) { + address _buffer = address(new AllocatorBuffer()); + ScriptTools.switchOwner(_buffer, deployer, owner); + ilkInstance.buffer = _buffer; + + address _vault = address(new AllocatorVault(roles, _buffer, ilk, nstJoin)); + ScriptTools.switchOwner(_vault, deployer, owner); + ilkInstance.vault = _vault; + + address _swapper = address(new Swapper(roles, ilk, _buffer)); + ScriptTools.switchOwner(_swapper, deployer, owner); + ilkInstance.swapper = _swapper; + + address _depositorUniV3 = address(new DepositorUniV3(roles, ilk, uniV3Factory, _buffer)); + ScriptTools.switchOwner(_depositorUniV3, deployer, owner); + ilkInstance.depositorUniV3 = _depositorUniV3; + + address _stableSwapper = address(new StableSwapper(_swapper)); + ScriptTools.switchOwner(_stableSwapper, deployer, owner); + ilkInstance.stableSwapper = _stableSwapper; + + address _stableDepositorUniV3 = address(new StableDepositorUniV3(_depositorUniV3)); + ScriptTools.switchOwner(_stableDepositorUniV3, deployer, owner); + ilkInstance.stableDepositorUniV3 = _stableDepositorUniV3; + + address _conduitMover = address(new ConduitMover(ilk, _buffer)); + ScriptTools.switchOwner(_conduitMover, deployer, owner); + ilkInstance.conduitMover = _conduitMover; + + ilkInstance.owner = owner; + } +} diff --git a/deploy/AllocatorInit.sol b/deploy/AllocatorInit.sol new file mode 100644 index 00000000..9de9e25b --- /dev/null +++ b/deploy/AllocatorInit.sol @@ -0,0 +1,297 @@ +// SPDX-FileCopyrightText: © 2023 Dai Foundation +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +pragma solidity >=0.8.0; + +import { ScriptTools } from "dss-test/ScriptTools.sol"; +import { DssInstance } from "dss-test/MCD.sol"; +import { AllocatorSharedInstance, AllocatorIlkInstance } from "./AllocatorInstances.sol"; + +interface WardsLike { + function rely(address) external; + function deny(address) external; +} + +interface IlkRegistryLike { + function put( + bytes32 _ilk, + address _join, + address _gem, + uint256 _dec, + uint256 _class, + address _pip, + address _xlip, + string calldata _name, + string calldata _symbol + ) external; +} + +interface RolesLike { + function setIlkAdmin(bytes32, address) external; + function setUserRole(bytes32, address, uint8, bool) external; + function setRoleAction(bytes32, uint8, address, bytes4, bool) external; +} + +interface RegistryLike { + function file(bytes32, bytes32, address) external; +} + +interface VaultLike { + function ilk() external view returns (bytes32); + function roles() external view returns (address); + function buffer() external view returns (address); + function vat() external view returns (address); + function nst() external view returns (address); + function file(bytes32, address) external; + function draw(uint256) external; + function wipe(uint256) external; +} + +interface BufferLike { + function approve(address, address, uint256) external; +} + +interface SwapperLike { + function roles() external view returns (address); + function ilk() external view returns (bytes32); + function buffer() external view returns (address); + function swap(address, address, uint256, uint256, address, bytes calldata) external returns (uint256); +} + +interface DepositorUniV3Like { + struct LiquidityParams { + address gem0; + address gem1; + uint24 fee; + int24 tickLower; + int24 tickUpper; + uint128 liquidity; + uint256 amt0Desired; + uint256 amt1Desired; + uint256 amt0Min; + uint256 amt1Min; + } + + struct CollectParams { + address gem0; + address gem1; + uint24 fee; + int24 tickLower; + int24 tickUpper; + } + + function roles() external view returns (address); + function ilk() external view returns (bytes32); + function buffer() external view returns (address); + function deposit(LiquidityParams memory) external returns (uint128, uint256, uint256); + function withdraw(LiquidityParams memory, bool) external returns (uint128, uint256, uint256, uint256, uint256); + function collect(CollectParams memory) external returns (uint256, uint256); +} + +interface StableSwapperLike { + function swapper() external view returns (address); +} + +interface StableDepositorUniV3Like { + function depositor() external view returns (address); +} + +interface ConduitMoverLike { + function ilk() external view returns (bytes32); + function buffer() external view returns (address); +} + +interface KissLike { + function kiss(address) external; +} + +struct AllocatorIlkConfig { + bytes32 ilk; + uint256 duty; + uint256 debtCeiling; + address allocatorProxy; + uint8 facilitatorRole; + uint8 automationRole; + address[] facilitators; + address[] stableSwapperKeepers; + address[] stableDepositorUniV3Keepers; + address[] conduitMoverKeepers; + address[] swapTokens; + address[] depositTokens; + address ilkRegistry; +} + +function bytes32ToStr(bytes32 _bytes32) pure returns (string memory) { + uint256 len; + while(len < 32 && _bytes32[len] != 0) len++; + bytes memory bytesArray = new bytes(len); + for (uint256 i; i < len; i++) { + bytesArray[i] = _bytes32[i]; + } + return string(bytesArray); +} + +library AllocatorInit { + uint256 constant WAD = 10 ** 18; + uint256 constant RAY = 10 ** 27; + uint256 constant RAD = 10 ** 45; + + uint256 constant RATES_ONE_HUNDRED_PCT = 1000000021979553151239153027; + + function initShared( + DssInstance memory dss, + AllocatorSharedInstance memory sharedInstance + ) internal { + dss.chainlog.setAddress("ALLOCATOR_ROLES", sharedInstance.roles); + dss.chainlog.setAddress("ALLOCATOR_REGISTRY", sharedInstance.registry); + } + + function initIlk( + DssInstance memory dss, + AllocatorSharedInstance memory sharedInstance, + AllocatorIlkInstance memory ilkInstance, + AllocatorIlkConfig memory cfg + ) internal { + bytes32 ilk = cfg.ilk; + + // Sanity checks + require(VaultLike(ilkInstance.vault).ilk() == ilk, "AllocatorInit/vault-ilk-mismatch"); + require(VaultLike(ilkInstance.vault).roles() == sharedInstance.roles, "AllocatorInit/vault-roles-mismatch"); + require(VaultLike(ilkInstance.vault).buffer() == ilkInstance.buffer, "AllocatorInit/vault-buffer-mismatch"); + require(VaultLike(ilkInstance.vault).vat() == address(dss.vat), "AllocatorInit/vault-vat-mismatch"); + // Once nstJoin is in the chainlog and adapted to dss-test should also check against it + + require(SwapperLike(ilkInstance.swapper).roles() == sharedInstance.roles, "AllocatorInit/swapper-roles-mismatch"); + require(SwapperLike(ilkInstance.swapper).ilk() == ilk, "AllocatorInit/swapper-ilk-mismatch"); + require(SwapperLike(ilkInstance.swapper).buffer() == ilkInstance.buffer, "AllocatorInit/swapper-buffer-mismatch"); + + require(DepositorUniV3Like(ilkInstance.depositorUniV3).roles() == sharedInstance.roles, "AllocatorInit/depositorUniV3-roles-mismatch"); + require(DepositorUniV3Like(ilkInstance.depositorUniV3).ilk() == ilk, "AllocatorInit/depositorUniV3-ilk-mismatch"); + require(DepositorUniV3Like(ilkInstance.depositorUniV3).buffer() == ilkInstance.buffer, "AllocatorInit/depositorUniV3-buffer-mismatch"); + + require(StableSwapperLike(ilkInstance.stableSwapper).swapper() == ilkInstance.swapper, "AllocatorInit/stableSwapper-swapper-mismatch"); + require(StableDepositorUniV3Like(ilkInstance.stableDepositorUniV3).depositor() == ilkInstance.depositorUniV3, "AllocatorInit/stableDepositorUniV3-depositorUniV3-mismatch"); + + require(ConduitMoverLike(ilkInstance.conduitMover).ilk() == ilk, "AllocatorInit/conduitMover-ilk-mismatch"); + require(ConduitMoverLike(ilkInstance.conduitMover).buffer() == ilkInstance.buffer, "AllocatorInit/conduitMover-buffer-mismatch"); + + // Onboard the ilk + dss.vat.init(ilk); + dss.jug.init(ilk); + + require((cfg.duty >= RAY) && (cfg.duty <= RATES_ONE_HUNDRED_PCT), "AllocatorInit/ilk-duty-out-of-bounds"); + dss.jug.file(ilk, "duty", cfg.duty); + + require(cfg.debtCeiling < WAD, "AllocatorInit/incorrect-ilk-line-precision"); + dss.vat.file(ilk, "line", cfg.debtCeiling * RAD); + dss.vat.file("Line", dss.vat.Line() + cfg.debtCeiling * RAD); + + dss.spotter.file(ilk, "pip", sharedInstance.oracle); + dss.spotter.file(ilk, "mat", RAY); + dss.spotter.poke(ilk); + + // Add buffer to registry + RegistryLike(sharedInstance.registry).file(ilk, "buffer", ilkInstance.buffer); + + // Initiate the allocator vault + dss.vat.slip(ilk, ilkInstance.vault, int256(1_000_000 * WAD)); + dss.vat.grab(ilk, ilkInstance.vault, ilkInstance.vault, address(0), int256(1_000_000 * WAD), 0); + + VaultLike(ilkInstance.vault).file("jug", address(dss.jug)); + + // Allow vault and funnels to pull funds from the buffer + BufferLike(ilkInstance.buffer).approve(VaultLike(ilkInstance.vault).nst(), ilkInstance.vault, type(uint256).max); + for(uint256 i = 0; i < cfg.swapTokens.length; i++) { + BufferLike(ilkInstance.buffer).approve(cfg.swapTokens[i], ilkInstance.swapper, type(uint256).max); + } + for(uint256 i = 0; i < cfg.depositTokens.length; i++) { + BufferLike(ilkInstance.buffer).approve(cfg.depositTokens[i], ilkInstance.depositorUniV3, type(uint256).max); + } + + // Set the pause proxy temporarily as ilk admin so we can set all the roles below + RolesLike(sharedInstance.roles).setIlkAdmin(ilk, ilkInstance.owner); + + // Allow the facilitators to operate on the vault and funnels directly + for(uint256 i = 0; i < cfg.facilitators.length; i++) { + RolesLike(sharedInstance.roles).setUserRole(ilk, cfg.facilitators[i], cfg.facilitatorRole, true); + } + + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.facilitatorRole, ilkInstance.vault, VaultLike.draw.selector, true); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.facilitatorRole, ilkInstance.vault, VaultLike.wipe.selector, true); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.facilitatorRole, ilkInstance.swapper, SwapperLike.swap.selector, true); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.facilitatorRole, ilkInstance.depositorUniV3, DepositorUniV3Like.deposit.selector, true); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.facilitatorRole, ilkInstance.depositorUniV3, DepositorUniV3Like.withdraw.selector, true); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.facilitatorRole, ilkInstance.depositorUniV3, DepositorUniV3Like.collect.selector, true); + + // Allow the automation contracts to operate on the funnels + RolesLike(sharedInstance.roles).setUserRole(ilk, ilkInstance.stableSwapper, cfg.automationRole, true); + RolesLike(sharedInstance.roles).setUserRole(ilk, ilkInstance.stableDepositorUniV3, cfg.automationRole, true); + + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkInstance.swapper, SwapperLike.swap.selector, true); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkInstance.depositorUniV3, DepositorUniV3Like.deposit.selector, true); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkInstance.depositorUniV3, DepositorUniV3Like.withdraw.selector, true); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkInstance.depositorUniV3, DepositorUniV3Like.collect.selector, true); + + // Set the allocator proxy as the ilk admin instead of the Pause Proxy + RolesLike(sharedInstance.roles).setIlkAdmin(ilk, cfg.allocatorProxy); + + // Allow facilitator to set configurations in the automation contracts + for(uint256 i = 0; i < cfg.facilitators.length; i++) { + WardsLike(ilkInstance.stableSwapper).rely(cfg.facilitators[i]); + WardsLike(ilkInstance.stableDepositorUniV3).rely(cfg.facilitators[i]); + WardsLike(ilkInstance.conduitMover).rely(cfg.facilitators[i]); + } + + // Add keepers to the automation contracts + for(uint256 i = 0; i < cfg.stableSwapperKeepers.length; i++) { + KissLike(ilkInstance.stableSwapper).kiss(cfg.stableSwapperKeepers[i]); + } + for(uint256 i = 0; i < cfg.stableDepositorUniV3Keepers.length; i++) { + KissLike(ilkInstance.stableDepositorUniV3).kiss(cfg.stableDepositorUniV3Keepers[i]); + } + for(uint256 i = 0; i < cfg.conduitMoverKeepers.length; i++) { + KissLike(ilkInstance.conduitMover).kiss(cfg.conduitMoverKeepers[i]); + } + + // Move ownership of the ilk contracts to the allocator proxy + ScriptTools.switchOwner(ilkInstance.vault, ilkInstance.owner, cfg.allocatorProxy); + ScriptTools.switchOwner(ilkInstance.buffer, ilkInstance.owner, cfg.allocatorProxy); + ScriptTools.switchOwner(ilkInstance.swapper, ilkInstance.owner, cfg.allocatorProxy); + ScriptTools.switchOwner(ilkInstance.depositorUniV3, ilkInstance.owner, cfg.allocatorProxy); + ScriptTools.switchOwner(ilkInstance.stableSwapper, ilkInstance.owner, cfg.allocatorProxy); + ScriptTools.switchOwner(ilkInstance.stableDepositorUniV3, ilkInstance.owner, cfg.allocatorProxy); + ScriptTools.switchOwner(ilkInstance.conduitMover, ilkInstance.owner, cfg.allocatorProxy); + + // Add allocator-specific contracts to changelog + string memory ilkString = ScriptTools.ilkToChainlogFormat(ilk); + dss.chainlog.setAddress(ScriptTools.stringToBytes32(string(abi.encodePacked(ilkString, "_VAULT"))), ilkInstance.vault); + dss.chainlog.setAddress(ScriptTools.stringToBytes32(string(abi.encodePacked(ilkString, "_BUFFER"))), ilkInstance.buffer); + dss.chainlog.setAddress(ScriptTools.stringToBytes32(string(abi.encodePacked("PIP_", ilkString))), sharedInstance.oracle); + + // Add to ilk registry + IlkRegistryLike(cfg.ilkRegistry).put({ + _ilk : ilk, + _join : address(0), + _gem : address(0), + _dec : 0, + _class : 5, // RWAs are class 3, D3Ms and Teleport are class 4 + _pip : sharedInstance.oracle, + _xlip : address(0), + _name : bytes32ToStr(ilk), + _symbol : bytes32ToStr(ilk) + }); + } +} diff --git a/deploy/AllocatorInstances.sol b/deploy/AllocatorInstances.sol new file mode 100644 index 00000000..c23a6cf0 --- /dev/null +++ b/deploy/AllocatorInstances.sol @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: © 2023 Dai Foundation +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +pragma solidity >=0.8.0; + +struct AllocatorSharedInstance { + address oracle; + address roles; + address registry; +} + +struct AllocatorIlkInstance { + address owner; + address vault; + address buffer; + address swapper; + address depositorUniV3; + address stableSwapper; + address stableDepositorUniV3; + address conduitMover; +} diff --git a/src/AllocatorVault.sol b/src/AllocatorVault.sol index d8911ed3..79697a51 100644 --- a/src/AllocatorVault.sol +++ b/src/AllocatorVault.sol @@ -37,7 +37,7 @@ interface GemLike { interface NstJoinLike { function nst() external view returns (GemLike); - function vat() external view returns (address); + function vat() external view returns (VatLike); function exit(address, uint256) external; function join(address, uint256) external; } @@ -81,19 +81,17 @@ contract AllocatorVault { // --- constructor --- - constructor(address roles_, address buffer_, address vat_, bytes32 ilk_, address nstJoin_) { + constructor(address roles_, address buffer_, bytes32 ilk_, address nstJoin_) { roles = RolesLike(roles_); buffer = buffer_; - vat = VatLike(vat_); ilk = ilk_; nstJoin = NstJoinLike(nstJoin_); - require(vat_ == nstJoin.vat(), "AllocatorVault/vat-not-match"); - + vat = nstJoin.vat(); nst = nstJoin.nst(); - VatLike(vat_).hope(nstJoin_); + vat.hope(nstJoin_); nst.approve(nstJoin_, type(uint256).max); wards[msg.sender] = 1; diff --git a/test/AllocatorVault.t.sol b/test/AllocatorVault.t.sol index a12ff469..e62cdb67 100644 --- a/test/AllocatorVault.t.sol +++ b/test/AllocatorVault.t.sol @@ -41,7 +41,7 @@ contract AllocatorVaultTest is DssTest { nstJoin = new NstJoinMock(vat, nst); buffer = new AllocatorBuffer(); roles = new RolesMock(); - vault = new AllocatorVault(address(roles), address(buffer), address(vat), ilk, address(nstJoin)); + vault = new AllocatorVault(address(roles), address(buffer), ilk, address(nstJoin)); buffer.approve(address(nst), address(vault), type(uint256).max); vat.slip(ilk, address(vault), int256(1_000_000 * WAD)); diff --git a/test/integration/Deployment.t.sol b/test/integration/Deployment.t.sol new file mode 100644 index 00000000..abce9904 --- /dev/null +++ b/test/integration/Deployment.t.sol @@ -0,0 +1,413 @@ +// SPDX-FileCopyrightText: © 2023 Dai Foundation +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +pragma solidity ^0.8.16; + +import "dss-test/DssTest.sol"; + +import { AllocatorSharedInstance, AllocatorIlkInstance } from "deploy/AllocatorInstances.sol"; +import { AllocatorDeploy } from "deploy/AllocatorDeploy.sol"; +import { AllocatorInit, AllocatorIlkConfig } from "deploy/AllocatorInit.sol"; + +import { SwapperCalleeUniV3 } from "src/funnels/callees/SwapperCalleeUniV3.sol"; + +import { GemMock } from "test/mocks/GemMock.sol"; +import { NstJoinMock } from "test/mocks/NstJoinMock.sol"; +import { VatMock } from "test/mocks/VatMock.sol"; +import { AllocatorConduitMock } from "test/mocks/AllocatorConduitMock.sol"; + +import { AllocatorRoles } from "src/AllocatorRoles.sol"; +import { AllocatorRegistry } from "src/AllocatorRegistry.sol"; +import { AllocatorVault } from "src/AllocatorVault.sol"; +import { AllocatorBuffer } from "src/AllocatorBuffer.sol"; +import { Swapper } from "src/funnels/Swapper.sol"; +import { DepositorUniV3 } from "src/funnels/DepositorUniV3.sol"; +import { StableSwapper } from "src/funnels/automation/StableSwapper.sol"; +import { StableDepositorUniV3 } from "src/funnels/automation/StableDepositorUniV3.sol"; +import { ConduitMover } from "src/funnels/automation/ConduitMover.sol"; + +interface GemLike { + function allowance(address, address) external view returns (uint256); +} + +interface WardsLike { + function wards(address) external view returns (uint256); +} + +interface ChainlogLike { + function getAddress(bytes32) external view returns (address); +} + +interface IlkRegistryLike { + function count() external view returns (uint256); + function pos(bytes32) external view returns (uint256); + function class(bytes32) external view returns (uint256); + function gem(bytes32) external view returns (address); + function pip(bytes32) external view returns (address); + function join(bytes32) external view returns (address); + function xlip(bytes32) external view returns (address); + function dec(bytes32) external view returns (uint256); + function symbol(bytes32) external view returns (string memory); + function name(bytes32) external view returns (string memory); +} + +contract DeploymentTest is DssTest { + + // existing contracts + address constant LOG = 0xdA0Ab1e0017DEbCd72Be8599041a2aa3bA7e740F; + address constant UNIV3_FACTORY = 0x1F98431c8aD98523631AE4a59f267346ea31F984; + address constant UNIV3_ROUTER = 0xE592427A0AEce92De3Edee1F18E0157C05861564; + + // existing contracts to be fetched from chainlog + address VAT; + address JUG; + address ILK_REGISTRY; + address PAUSE_PROXY; + address DAI; + address USDC; + + // actors + address constant allocatorProxy = address(0x1); + address constant facilitator1 = address(0x2); + address constant facilitator2 = address(0x3); + address constant stableSwapperKeeper1 = address(0x4); + address constant stableSwapperKeeper2 = address(0x5); + address constant stableDepositorUniV3Keeper1 = address(0x6); + address constant stableDepositorUniV3Keeper2 = address(0x7); + address constant conduitMoverKeeper1 = address(0x8); + address constant conduitMoverKeeper2 = address(0x9); + + // roles + uint8 constant facilitatorRole = uint8(1); + uint8 constant automationRole = uint8(2); + + // contracts to be deployed + address nst; + address nstJoin; + address uniV3Callee; + address conduit1; + address conduit2; + + // storage to be initiated on setup + AllocatorSharedInstance sharedInst; + AllocatorIlkInstance ilkInst; + bytes usdcDaiPath; + bytes daiUsdcPath; + + // constants + int24 constant REF_TICK = -276324; // tick corresponding to 1 DAI = 1 USDC calculated as ~= math.log(10**(-12))/math.log(1.0001) + bytes32 constant ILK = "ILK-A"; + + function setUp() public { + vm.createSelectFork(vm.envString("ETH_RPC_URL")); + + VAT = ChainlogLike(LOG).getAddress("MCD_VAT"); + JUG = ChainlogLike(LOG).getAddress("MCD_JUG"); + PAUSE_PROXY = ChainlogLike(LOG).getAddress("MCD_PAUSE_PROXY"); + ILK_REGISTRY = ChainlogLike(LOG).getAddress("ILK_REGISTRY"); + USDC = ChainlogLike(LOG).getAddress("USDC"); + DAI = ChainlogLike(LOG).getAddress("MCD_DAI"); + + nst = address(new GemMock(0)); + nstJoin = address(new NstJoinMock(VatMock(VAT), GemMock(nst))); + uniV3Callee = address(new SwapperCalleeUniV3(UNIV3_ROUTER)); + + usdcDaiPath = abi.encodePacked(USDC, uint24(100), DAI); + daiUsdcPath = abi.encodePacked(DAI, uint24(100), USDC); + + sharedInst = AllocatorDeploy.deployShared(address(this), PAUSE_PROXY); + ilkInst = AllocatorDeploy.deployIlk({ + deployer : address(this), + owner : PAUSE_PROXY, + roles : sharedInst.roles, + ilk : ILK, + nstJoin : nstJoin, + uniV3Factory : UNIV3_FACTORY + }); + + // Deploy conduits (assumed to be done separately than the current allocator ilkInst deploy) + conduit1 = address(new AllocatorConduitMock(sharedInst.roles, sharedInst.registry)); + conduit2 = address(new AllocatorConduitMock(sharedInst.roles, sharedInst.registry)); + } + + function emulateSpell() internal { + DssInstance memory dss = MCD.loadFromChainlog(LOG); + + vm.startPrank(PAUSE_PROXY); + AllocatorInit.initShared(dss, sharedInst); + + address[] memory swapTokens = new address[](1); + swapTokens[0] = DAI; + + address[] memory depositTokens = new address[](2); + depositTokens[0] = DAI; + depositTokens[1] = USDC; + + address[] memory facilitators = new address[](2); + facilitators[0] = facilitator1; + facilitators[1] = facilitator2; + + address[] memory stableSwapperKeepers = new address[](2); + stableSwapperKeepers[0] = stableSwapperKeeper1; + stableSwapperKeepers[1] = stableSwapperKeeper2; + + address[] memory stableDepositorUniV3Keepers = new address[](2); + stableDepositorUniV3Keepers[0] = stableDepositorUniV3Keeper1; + stableDepositorUniV3Keepers[1] = stableDepositorUniV3Keeper2; + + address[] memory conduitMoverKeepers = new address[](2); + conduitMoverKeepers[0] = conduitMoverKeeper1; + conduitMoverKeepers[1] = conduitMoverKeeper2; + + AllocatorIlkConfig memory cfg = AllocatorIlkConfig({ + ilk : ILK, + duty : 1000000001243680656318820312, + debtCeiling : 100_000_000, + allocatorProxy : allocatorProxy, + facilitatorRole : facilitatorRole, + automationRole : automationRole, + facilitators : facilitators, + stableSwapperKeepers : stableSwapperKeepers, + stableDepositorUniV3Keepers : stableDepositorUniV3Keepers, + conduitMoverKeepers : conduitMoverKeepers, + swapTokens : swapTokens, + depositTokens : depositTokens, + ilkRegistry : ILK_REGISTRY + }); + + AllocatorInit.initIlk(dss, sharedInst, ilkInst, cfg); + vm.stopPrank(); + + // Init conduits (assumed to be done separately than the current allocator ilkInst init) + vm.startPrank(allocatorProxy); + AllocatorRoles(sharedInst.roles).setUserRole(ILK, address(ilkInst.conduitMover), automationRole, true); + + AllocatorRoles(sharedInst.roles).setRoleAction(ILK, automationRole, conduit1, AllocatorConduitMock.deposit.selector, true); + AllocatorRoles(sharedInst.roles).setRoleAction(ILK, automationRole, conduit1, AllocatorConduitMock.withdraw.selector, true); + AllocatorRoles(sharedInst.roles).setRoleAction(ILK, automationRole, conduit2, AllocatorConduitMock.deposit.selector, true); + AllocatorRoles(sharedInst.roles).setRoleAction(ILK, automationRole, conduit2, AllocatorConduitMock.withdraw.selector, true); + + AllocatorBuffer(ilkInst.buffer).approve(USDC, conduit1, type(uint256).max); + AllocatorBuffer(ilkInst.buffer).approve(USDC, conduit2, type(uint256).max); + vm.stopPrank(); + } + + function testInitSharedValues() public { + emulateSpell(); + + assertEq(ChainlogLike(LOG).getAddress("ALLOCATOR_ROLES"), sharedInst.roles); + assertEq(ChainlogLike(LOG).getAddress("ALLOCATOR_REGISTRY"), sharedInst.registry); + } + + function testInitIlkValues() public { + DssInstance memory dss = MCD.loadFromChainlog(LOG); + + uint256 previousLine = dss.vat.Line(); + uint256 previousIlkRegistryCount = IlkRegistryLike(ILK_REGISTRY).count(); + + emulateSpell(); + + (, uint256 rate, uint256 spot, uint256 line,) = dss.vat.ilks(ILK); + assertEq(rate, RAY); + assertEq(spot, 10**6 * 10**18 * RAY * 10**9 / dss.spotter.par()); + assertEq(line, 100_000_000 * RAD); + assertEq(dss.vat.Line(), previousLine + 100_000_000 * RAD); + + (uint256 duty, uint256 rho) = dss.jug.ilks(ILK); + assertEq(duty, 1000000001243680656318820312); + assertEq(rho, block.timestamp); + + (address pip, uint256 mat) = dss.spotter.ilks(ILK); + assertEq(pip, sharedInst.oracle); + assertEq(mat, RAY); + + assertEq(dss.vat.gem(ILK, ilkInst.vault), 0); + (uint256 ink, uint256 art) = dss.vat.urns(ILK, ilkInst.vault); + assertEq(ink, 1_000_000 * WAD); + assertEq(art, 0); + + assertEq(AllocatorRegistry(sharedInst.registry).buffers(ILK), ilkInst.buffer); + assertEq(address(AllocatorVault(ilkInst.vault).jug()), address(dss.jug)); + + assertEq(GemLike(nst).allowance(ilkInst.buffer, ilkInst.vault), type(uint256).max); + assertEq(GemLike(DAI).allowance(ilkInst.buffer, ilkInst.swapper), type(uint256).max); + assertEq(GemLike(DAI).allowance(ilkInst.buffer, ilkInst.depositorUniV3), type(uint256).max); + assertEq(GemLike(USDC).allowance(ilkInst.buffer, ilkInst.depositorUniV3), type(uint256).max); + + assertEq(AllocatorRoles(sharedInst.roles).ilkAdmins(ILK), allocatorProxy); + + assertEq(AllocatorRoles(sharedInst.roles).hasUserRole(ILK, facilitator1, facilitatorRole), true); + assertEq(AllocatorRoles(sharedInst.roles).hasUserRole(ILK, facilitator2, facilitatorRole), true); + + assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkInst.vault, AllocatorVault.draw.selector, facilitatorRole), true); + assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkInst.vault, AllocatorVault.wipe.selector, facilitatorRole), true); + assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkInst.swapper, Swapper.swap.selector, facilitatorRole), true); + assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkInst.depositorUniV3, DepositorUniV3.deposit.selector, facilitatorRole), true); + assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkInst.depositorUniV3, DepositorUniV3.withdraw.selector, facilitatorRole), true); + assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkInst.depositorUniV3, DepositorUniV3.collect.selector, facilitatorRole), true); + + assertEq(AllocatorRoles(sharedInst.roles).hasUserRole(ILK, ilkInst.stableSwapper, automationRole), true); + assertEq(AllocatorRoles(sharedInst.roles).hasUserRole(ILK, ilkInst.stableDepositorUniV3, automationRole), true); + + assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkInst.swapper, Swapper.swap.selector, automationRole), true); + assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkInst.depositorUniV3, DepositorUniV3.deposit.selector, automationRole), true); + assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkInst.depositorUniV3, DepositorUniV3.withdraw.selector, automationRole), true); + assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkInst.depositorUniV3, DepositorUniV3.collect.selector, automationRole), true); + + assertEq(WardsLike(ilkInst.stableSwapper).wards(facilitator1), 1); + assertEq(WardsLike(ilkInst.stableSwapper).wards(facilitator2), 1); + assertEq(WardsLike(ilkInst.stableDepositorUniV3).wards(facilitator1), 1); + assertEq(WardsLike(ilkInst.stableDepositorUniV3).wards(facilitator2), 1); + assertEq(WardsLike(ilkInst.conduitMover).wards(facilitator1), 1); + assertEq(WardsLike(ilkInst.conduitMover).wards(facilitator2), 1); + + assertEq(StableSwapper(ilkInst.stableSwapper).buds(stableSwapperKeeper1), 1); + assertEq(StableSwapper(ilkInst.stableSwapper).buds(stableSwapperKeeper2), 1); + assertEq(StableDepositorUniV3(ilkInst.stableDepositorUniV3).buds(stableDepositorUniV3Keeper1), 1); + assertEq(StableDepositorUniV3(ilkInst.stableDepositorUniV3).buds(stableDepositorUniV3Keeper2), 1); + assertEq(ConduitMover(ilkInst.conduitMover).buds(conduitMoverKeeper1), 1); + assertEq(ConduitMover(ilkInst.conduitMover).buds(conduitMoverKeeper2), 1); + + assertEq(WardsLike(ilkInst.vault).wards(PAUSE_PROXY), 0); + assertEq(WardsLike(ilkInst.vault).wards(allocatorProxy), 1); + + assertEq(WardsLike(ilkInst.buffer).wards(PAUSE_PROXY), 0); + assertEq(WardsLike(ilkInst.buffer).wards(allocatorProxy), 1); + + assertEq(WardsLike(ilkInst.swapper).wards(PAUSE_PROXY), 0); + assertEq(WardsLike(ilkInst.swapper).wards(allocatorProxy), 1); + + assertEq(WardsLike(ilkInst.depositorUniV3).wards(PAUSE_PROXY), 0); + assertEq(WardsLike(ilkInst.depositorUniV3).wards(allocatorProxy), 1); + + assertEq(WardsLike(ilkInst.stableSwapper).wards(PAUSE_PROXY), 0); + assertEq(WardsLike(ilkInst.stableSwapper).wards(allocatorProxy), 1); + + assertEq(WardsLike(ilkInst.stableDepositorUniV3).wards(PAUSE_PROXY), 0); + assertEq(WardsLike(ilkInst.stableDepositorUniV3).wards(allocatorProxy), 1); + + assertEq(WardsLike(ilkInst.conduitMover).wards(PAUSE_PROXY), 0); + assertEq(WardsLike(ilkInst.conduitMover).wards(allocatorProxy), 1); + + assertEq(ChainlogLike(LOG).getAddress("ILK_A_VAULT"), ilkInst.vault); + assertEq(ChainlogLike(LOG).getAddress("ILK_A_BUFFER"), ilkInst.buffer); + assertEq(ChainlogLike(LOG).getAddress("PIP_ILK_A"), sharedInst.oracle); + + assertEq(IlkRegistryLike(ILK_REGISTRY).count(), previousIlkRegistryCount + 1); + assertEq(IlkRegistryLike(ILK_REGISTRY).pos(ILK), previousIlkRegistryCount); + assertEq(IlkRegistryLike(ILK_REGISTRY).join(ILK), address(0)); + assertEq(IlkRegistryLike(ILK_REGISTRY).gem(ILK), address(0)); + assertEq(IlkRegistryLike(ILK_REGISTRY).dec(ILK), 0); + assertEq(IlkRegistryLike(ILK_REGISTRY).class(ILK), 5); + assertEq(IlkRegistryLike(ILK_REGISTRY).pip(ILK), sharedInst.oracle); + assertEq(IlkRegistryLike(ILK_REGISTRY).xlip(ILK), address(0)); + assertEq(IlkRegistryLike(ILK_REGISTRY).name(ILK), string("ILK-A")); + assertEq(IlkRegistryLike(ILK_REGISTRY).symbol(ILK), string("ILK-A")); + } + + function testVaultDrawWipe() public { + emulateSpell(); + + vm.prank(facilitator1); AllocatorVault(ilkInst.vault).draw(1_000 * WAD); + vm.prank(facilitator1); AllocatorVault(ilkInst.vault).wipe(1_000 * WAD); + } + + function testSwapFromFacilitator() public { + emulateSpell(); + + deal(DAI, ilkInst.buffer, 1_000 * WAD); + + vm.prank(allocatorProxy); Swapper(ilkInst.swapper).setLimits(DAI, USDC, uint96(1_000 * WAD), 1 hours); + vm.prank(facilitator1); Swapper(ilkInst.swapper).swap(DAI, USDC, 1_000 * WAD, 990 * 10**6 , uniV3Callee, daiUsdcPath); + } + + function testSwapFromKeeper() public { + emulateSpell(); + + deal(DAI, ilkInst.buffer, 1_000 * WAD); + + vm.prank(allocatorProxy); Swapper(ilkInst.swapper).setLimits(DAI, USDC, uint96(1_000 * WAD), 1 hours); + vm.prank(facilitator1); StableSwapper(ilkInst.stableSwapper).setConfig(DAI, USDC, 1, 1 hours, uint96(1_000 * WAD), uint96(990 * 10**6)); + vm.prank(stableSwapperKeeper1); StableSwapper(ilkInst.stableSwapper).swap(DAI, USDC, 990 * 10**6, uniV3Callee, daiUsdcPath); + } + + function testDepositWithdrawCollectFromFacilitator() public { + emulateSpell(); + + deal(DAI, ilkInst.buffer, 1_000 * WAD); + deal(USDC, ilkInst.buffer, 1_000 * 10**6); + + vm.prank(allocatorProxy); DepositorUniV3(ilkInst.depositorUniV3).setLimits(DAI, USDC, uint24(100), uint96(2_000 * WAD), uint96(2_000 * 10**6), 1 hours); + DepositorUniV3.LiquidityParams memory dp = DepositorUniV3.LiquidityParams({ + gem0 : DAI, + gem1 : USDC, + fee : uint24(100), + tickLower : REF_TICK - 100, + tickUpper : REF_TICK + 100, + liquidity : 0, + amt0Desired: 1_000 * WAD, + amt1Desired: 1_000 * 10**6, + amt0Min : 900 * WAD, + amt1Min : 900 * 10**6 + }); + + vm.prank(facilitator1); DepositorUniV3(ilkInst.depositorUniV3).deposit(dp); + vm.prank(facilitator1); DepositorUniV3(ilkInst.depositorUniV3).withdraw(dp, false); + + DepositorUniV3.CollectParams memory cp = DepositorUniV3.CollectParams({ + gem0 : DAI, + gem1 : USDC, + fee : uint24(100), + tickLower: REF_TICK - 100, + tickUpper: REF_TICK + 100 + }); + + vm.expectRevert(bytes("NP")); // we make sure it reverts since no fees to collect and not because the call is unauthorized + vm.prank(facilitator1); DepositorUniV3(ilkInst.depositorUniV3).collect(cp); + } + + function testDepositWithdrawCollectFromKeeper() public { + emulateSpell(); + + deal(DAI, ilkInst.buffer, 1_000 * WAD); + deal(USDC, ilkInst.buffer, 1_000 * 10**6); + + vm.prank(allocatorProxy); DepositorUniV3(ilkInst.depositorUniV3).setLimits(DAI, USDC, uint24(100), uint96(2_000 * WAD), uint96(2_000 * 10**6), 1 hours); + + vm.prank(facilitator1); StableDepositorUniV3(ilkInst.stableDepositorUniV3).setConfig(DAI, USDC, uint24(100), REF_TICK - 100, REF_TICK + 100, 1, 1 hours, uint96(1_000 * WAD), uint96(1000 * 10**6), 0, 0); + vm.prank(stableDepositorUniV3Keeper1); StableDepositorUniV3(ilkInst.stableDepositorUniV3).deposit(DAI, USDC, uint24(100), REF_TICK - 100, REF_TICK + 100, 0, 0); + + vm.prank(facilitator1); StableDepositorUniV3(ilkInst.stableDepositorUniV3).setConfig(DAI, USDC, uint24(100), REF_TICK - 100, REF_TICK + 100, -1, 1 hours, uint96(1_000 * WAD), uint96(1000 * 10**6), 0, 0); + vm.prank(stableDepositorUniV3Keeper1); StableDepositorUniV3(ilkInst.stableDepositorUniV3).withdraw(DAI, USDC, uint24(100), REF_TICK - 100, REF_TICK + 100, 0, 0); + + vm.expectRevert(bytes("NP")); // Reverts since no fees to collect and not because the call is unauthorized + vm.prank(stableDepositorUniV3Keeper1); StableDepositorUniV3(ilkInst.stableDepositorUniV3).collect(DAI, USDC, uint24(100), REF_TICK - 100, REF_TICK + 100); + } + + function testMoveFromKeeper() public { + emulateSpell(); + + // Note that although the Conduits setup and init were not done by the tested contracts, we are testing the + // ConduitMover deployment, the facilitators ward on it and the keeper addition to it. + + // Give conduit1 some funds + deal(USDC, ilkInst.buffer, 3_000 * 10**6, true); + vm.prank(ilkInst.conduitMover); AllocatorConduitMock(conduit1).deposit(ILK, USDC, 3_000 * 10**6); + + vm.prank(facilitator1); ConduitMover(ilkInst.conduitMover).setConfig(conduit1, conduit2, USDC, 1, 1 hours, 3_000 * 10**6); + vm.prank(conduitMoverKeeper1); ConduitMover(ilkInst.conduitMover).move(conduit1, conduit2, USDC); + } +} From dc192486bd12efa5045af509c9570214e57997bd Mon Sep 17 00:00:00 2001 From: sunbreak Date: Tue, 12 Sep 2023 16:36:17 -0300 Subject: [PATCH 53/74] Minor spacing fixes --- src/AllocatorRoles.sol | 3 +-- src/AllocatorVault.sol | 1 - src/IAllocatorConduit.sol | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/AllocatorRoles.sol b/src/AllocatorRoles.sol index 6dc749e3..6bef7547 100644 --- a/src/AllocatorRoles.sol +++ b/src/AllocatorRoles.sol @@ -17,8 +17,7 @@ pragma solidity ^0.8.16; -contract AllocatorRoles -{ +contract AllocatorRoles { // --- storage variables --- mapping(address => uint256) public wards; diff --git a/src/AllocatorVault.sol b/src/AllocatorVault.sol index 79697a51..74825ebd 100644 --- a/src/AllocatorVault.sol +++ b/src/AllocatorVault.sol @@ -43,7 +43,6 @@ interface NstJoinLike { } contract AllocatorVault { - // --- storage variables --- mapping(address => uint256) public wards; diff --git a/src/IAllocatorConduit.sol b/src/IAllocatorConduit.sol index 74a47f80..a5256f95 100644 --- a/src/IAllocatorConduit.sol +++ b/src/IAllocatorConduit.sol @@ -21,7 +21,6 @@ pragma solidity >=0.8.0; * @dev Conduits are to be used to manage investment positions for multiple Allocators. */ interface IAllocatorConduit { - /** * @dev Event emitted when a deposit is made to the Conduit. * @param ilk The unique identifier of the ilk. From 422c20e8157784efcd30b2f8f47aeda9856006a7 Mon Sep 17 00:00:00 2001 From: telome <130504305+telome@users.noreply.github.com> Date: Thu, 28 Sep 2023 14:44:42 +0100 Subject: [PATCH 54/74] Use expected amounts in tests (#60) * Use expected amounts in tests * Apply suggestions from code review Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> * Update test/funnels/UniV3Utils.sol Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> * Revert changes to REF_TICK notation * Align getExpectedAmounts with UniswapV3Pool code * Remove unnecessary configs() read * Update test/funnels/UniV3Utils.sol Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> * Use SafeCast to calculate liqDelta * Test that amtMin can be > req --------- Co-authored-by: telome <> Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> --- test/funnels/DepositorUniV3.t.sol | 209 +++++------------ test/funnels/UniV3Utils.sol | 218 ++++++++++++++++++ .../automation/StableDepositorUniV3.t.sol | 94 +++++--- 3 files changed, 341 insertions(+), 180 deletions(-) create mode 100644 test/funnels/UniV3Utils.sol diff --git a/test/funnels/DepositorUniV3.t.sol b/test/funnels/DepositorUniV3.t.sol index c89dad53..edd0f5cc 100644 --- a/test/funnels/DepositorUniV3.t.sol +++ b/test/funnels/DepositorUniV3.t.sol @@ -8,23 +8,13 @@ import { SwapperCalleeUniV3 } from "src/funnels/callees/SwapperCalleeUniV3.sol"; import { AllocatorRoles } from "src/AllocatorRoles.sol"; import { AllocatorBuffer } from "src/AllocatorBuffer.sol"; +import { UniV3Utils } from "test/funnels/UniV3Utils.sol"; + interface GemLike { function approve(address, uint256) external; function balanceOf(address) external view returns (uint256); } -interface UniV3PoolLike { - struct PositionInfo { - uint128 liquidity; - uint256 feeGrowthInside0LastX128; - uint256 feeGrowthInside1LastX128; - uint128 tokensOwed0; - uint128 tokensOwed1; - } - - function positions(bytes32) external view returns (PositionInfo memory); -} - interface SwapRouterLike { function exactInput(ExactInputParams calldata params) external returns (uint256 amountOut); @@ -53,13 +43,13 @@ contract DepositorUniV3Test is DssTest { address constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F; address constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; address constant DAI_USDC_POOL = 0x5777d92f208679DB4b9778590Fa3CAB3aC9e2168; - address constant UNIV3_ROUTER = 0xE592427A0AEce92De3Edee1F18E0157C05861564; - address constant UNIV3_FACTORY = 0x1F98431c8aD98523631AE4a59f267346ea31F984; + address constant UNIV3_ROUTER = UniV3Utils.UNIV3_ROUTER; + address constant UNIV3_FACTORY = UniV3Utils.UNIV3_FACTORY; address constant FACILITATOR = address(0x1337); uint8 constant DEPOSITOR_ROLE = uint8(2); - int24 constant REF_TICK = -276324; // tick corresponding to 1 DAI = 1 USDC calculated as ~= math.log(10**(-12))/math.log(1.0001) + int24 REF_TICK; function setUp() public { vm.createSelectFork(vm.envString("ETH_RPC_URL")); @@ -80,6 +70,8 @@ contract DepositorUniV3Test is DssTest { deal(USDC, address(buffer), 1_000_000 * 10**6, true); buffer.approve(USDC, address(depositor), type(uint256).max); buffer.approve(DAI, address(depositor), type(uint256).max); + + REF_TICK = UniV3Utils.getCurrentTick(DAI, USDC, uint24(100)); } function testConstructor() public { @@ -109,18 +101,7 @@ contract DepositorUniV3Test is DssTest { function testSetLimits() public { // deposit to make sure end and both due are set - DepositorUniV3.LiquidityParams memory dp = DepositorUniV3.LiquidityParams({ - gem0: DAI, - gem1: USDC, - fee: uint24(100), - tickLower: REF_TICK-100, - tickUpper: REF_TICK+100, - liquidity: 0, - amt0Desired: 500 * WAD, - amt1Desired: 500 * 10**6, - amt0Min: 490 * WAD, - amt1Min: 490 * 10**6 - }); + DepositorUniV3.LiquidityParams memory dp = _getTestDepositParams(0, 500 * WAD, 500 * 10**6); vm.prank(FACILITATOR); depositor.deposit(dp); (,,, uint96 due0Before, uint96 due1Before, uint32 endBefore) = depositor.limits(DAI, USDC, 100); @@ -150,44 +131,46 @@ contract DepositorUniV3Test is DssTest { vm.prank(address(0xBEEF)); depositor.setLimits(address(0), address(1), 0, 0, 0, 0); } - // https://github.com/Uniswap/v3-periphery/blob/464a8a49611272f7349c970e0fadb7ec1d3c1086/contracts/libraries/PoolAddress.sol#L33 - function _getPool(address gem0, address gem1, uint24 fee) internal pure returns (UniV3PoolLike pool) { - pool = UniV3PoolLike(address(uint160(uint256(keccak256(abi.encodePacked( - hex'ff', - UNIV3_FACTORY, - keccak256(abi.encode(gem0, gem1, fee)), - bytes32(0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54) // POOL_INIT_CODE_HASH - )))))); + // helps avoid stack too deep errors + function _getTestDepositParams(uint128 liquidity, uint256 amt0Desired, uint256 amt1Desired) internal view returns (DepositorUniV3.LiquidityParams memory dp) { + (uint256 expectedAmt0, uint256 expectedAmt1) = UniV3Utils.getExpectedAmounts(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, liquidity, amt0Desired, amt1Desired, false); + dp = DepositorUniV3.LiquidityParams({ + gem0: DAI, + gem1: USDC, + fee: uint24(100), + tickLower: REF_TICK-100, + tickUpper: REF_TICK+100, + liquidity: liquidity, + amt0Desired: amt0Desired, + amt1Desired: amt1Desired, + amt0Min: expectedAmt0, + amt1Min: expectedAmt1 + }); } - function _getLiquidity(address gem0, address gem1, uint24 fee, int24 tickLower, int24 tickUpper) - internal - view - returns (uint128 liquidity) - { - return (_getPool(gem0, gem1, fee). - positions(keccak256(abi.encodePacked(address(depositor), tickLower, tickUpper)))).liquidity; - + function _getTestWithdrawParams(uint128 liquidity, uint256 amt0Desired, uint256 amt1Desired) internal view returns (DepositorUniV3.LiquidityParams memory dp) { + (uint256 expectedAmt0, uint256 expectedAmt1) = UniV3Utils.getExpectedAmounts(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, liquidity, amt0Desired, amt1Desired, true); + dp = DepositorUniV3.LiquidityParams({ + gem0: DAI, + gem1: USDC, + fee: uint24(100), + tickLower: REF_TICK-100, + tickUpper: REF_TICK+100, + liquidity: liquidity, + amt0Desired: amt0Desired, + amt1Desired: amt1Desired, + amt0Min: expectedAmt0, + amt1Min: expectedAmt1 + }); } function testDeposit() public { - assertEq(_getLiquidity(DAI, USDC, 100, REF_TICK-100, REF_TICK+100), 0); + assertEq(UniV3Utils.getLiquidity(address(depositor), DAI, USDC, 100, REF_TICK-100, REF_TICK+100), 0); uint256 prevUSDC = GemLike(USDC).balanceOf(address(buffer)); uint256 prevDAI = GemLike(DAI).balanceOf(address(buffer)); uint32 initialTime = uint32(block.timestamp); - DepositorUniV3.LiquidityParams memory dp = DepositorUniV3.LiquidityParams({ - gem0: DAI, - gem1: USDC, - fee: uint24(100), - tickLower: REF_TICK-100, - tickUpper: REF_TICK+100, - liquidity: 0, - amt0Desired: 5_000 * WAD, - amt1Desired: 5_000 * 10**6, - amt0Min: 4_900 * WAD, - amt1Min: 4_900 * 10**6 - }); + DepositorUniV3.LiquidityParams memory dp = _getTestDepositParams(0, 5_000 * WAD, 5_000 * 10**6); uint256 snapshot = vm.snapshot(); (uint128 liq, uint256 amt0, uint256 amt1) = depositor.deposit(dp); @@ -201,7 +184,7 @@ contract DepositorUniV3Test is DssTest { assertLt(GemLike(USDC).balanceOf(address(buffer)), prevUSDC); assertEq(GemLike(DAI).balanceOf(address(depositor)), 0); assertEq(GemLike(USDC).balanceOf(address(depositor)), 0); - uint128 liquidityAfterDeposit = _getLiquidity(DAI, USDC, 100, REF_TICK-100, REF_TICK+100); + uint128 liquidityAfterDeposit = UniV3Utils.getLiquidity(address(depositor), DAI, USDC, 100, REF_TICK-100, REF_TICK+100); assertGt(liquidityAfterDeposit, 0); (,,, uint96 due0, uint96 due1, uint32 end) = depositor.limits(DAI, USDC, 100); assertEq(end, initialTime + 3600); @@ -211,10 +194,7 @@ contract DepositorUniV3Test is DssTest { prevUSDC = GemLike(USDC).balanceOf(address(buffer)); prevDAI = GemLike(DAI).balanceOf(address(buffer)); - dp.amt0Desired = 2_000 * WAD; - dp.amt1Desired = 2_000 * 10**6; - dp.amt0Min = 1_960 * WAD; - dp.amt1Min = 1_960 * 10**6; + dp = _getTestDepositParams(0, 2_000 * WAD, 2_000 * 10**6); vm.warp(initialTime + 1800); vm.prank(FACILITATOR); depositor.deposit(dp); @@ -225,14 +205,11 @@ contract DepositorUniV3Test is DssTest { assertLt(GemLike(USDC).balanceOf(address(buffer)), prevUSDC); assertEq(GemLike(DAI).balanceOf(address(depositor)), 0); assertEq(GemLike(USDC).balanceOf(address(depositor)), 0); - assertGt(_getLiquidity(DAI, USDC, 100, REF_TICK-100, REF_TICK+100), liquidityAfterDeposit); + assertGt(UniV3Utils.getLiquidity(address(depositor), DAI, USDC, 100, REF_TICK-100, REF_TICK+100), liquidityAfterDeposit); assertLt(due0, 10_000 * WAD - amt0); assertLt(due1, 10_000 * 10**6 - amt1); - dp.amt0Desired = 8_000 * WAD; - dp.amt1Desired = 8_000 * 10**6; - dp.amt0Min = 7_840 * WAD; - dp.amt1Min = 7_840 * 10**6; + dp = _getTestDepositParams(0, 8_000 * WAD, 8_000 * 10**6); vm.expectRevert("DepositorUniV3/exceeds-due-amt"); vm.prank(FACILITATOR); depositor.deposit(dp); @@ -320,18 +297,8 @@ contract DepositorUniV3Test is DssTest { } function testCollect() public { - DepositorUniV3.LiquidityParams memory dp = DepositorUniV3.LiquidityParams({ - gem0: DAI, - gem1: USDC, - fee: uint24(100), - tickLower: REF_TICK-100, - tickUpper: REF_TICK+100, - liquidity: 0, - amt0Desired: 500 * WAD, - amt1Desired: 500 * 10**6, - amt0Min: 490 * WAD, - amt1Min: 490 * 10**6 - }); + + DepositorUniV3.LiquidityParams memory dp = _getTestDepositParams(0, 500 * WAD, 500 * 10**6); vm.prank(FACILITATOR); depositor.deposit(dp); uint256 prevUSDC = GemLike(USDC).balanceOf(address(buffer)); uint256 prevDAI = GemLike(DAI).balanceOf(address(buffer)); @@ -376,22 +343,11 @@ contract DepositorUniV3Test is DssTest { uint256 initialDAI = GemLike(DAI).balanceOf(address(buffer)); uint256 initialTime = uint32(block.timestamp); - DepositorUniV3.LiquidityParams memory dp = DepositorUniV3.LiquidityParams({ - gem0: DAI, - gem1: USDC, - fee: uint24(100), - tickLower: REF_TICK-100, - tickUpper: REF_TICK+100, - liquidity: 0, - amt0Desired: 500 * WAD, - amt1Desired: 500 * 10**6, - amt0Min: 490 * WAD, - amt1Min: 490 * 10**6 - }); + DepositorUniV3.LiquidityParams memory dp = _getTestDepositParams(0, 500 * WAD, 500 * 10**6); vm.prank(FACILITATOR); (uint128 liq, uint256 deposited0, uint256 deposited1) = depositor.deposit(dp); - assertGt(_getLiquidity(DAI, USDC, 100, REF_TICK-100, REF_TICK+100), 0); + assertGt(UniV3Utils.getLiquidity(address(depositor), DAI, USDC, 100, REF_TICK-100, REF_TICK+100), 0); - dp.liquidity = liq; + dp = _getTestWithdrawParams(liq, 0, 0); uint256 snapshot = vm.snapshot(); (uint128 liquidity, uint256 withdrawn0, uint256 withdrawn1, uint256 fees0, uint256 fees1) = depositor.withdraw(dp, false); @@ -407,7 +363,7 @@ contract DepositorUniV3Test is DssTest { assertGe(GemLike(USDC).balanceOf(address(buffer)) + 1, initialUSDC); assertEq(GemLike(DAI).balanceOf(address(depositor)), 0); assertEq(GemLike(USDC).balanceOf(address(depositor)), 0); - assertEq(_getLiquidity(DAI, USDC, 100, REF_TICK-100, REF_TICK+100), 0); + assertEq(UniV3Utils.getLiquidity(address(depositor), DAI, USDC, 100, REF_TICK-100, REF_TICK+100), 0); assertEq(fees0, 0); assertEq(fees1, 0); assertEq(liquidity, liq); @@ -416,11 +372,7 @@ contract DepositorUniV3Test is DssTest { assertEq(due0, 10_000 * WAD - deposited0 - withdrawn0); assertEq(due1, 10_000 * 10**6 - deposited1 - withdrawn1); - dp.liquidity = 0; - dp.amt0Desired = 8_000 * WAD; - dp.amt1Desired = 8_000 * 10**6; - dp.amt0Min = 7_840 * WAD; - dp.amt1Min = 7_840 * 10**6; + dp = _getTestDepositParams(0, 8_000 * WAD, 8_000 * 10**6); vm.warp(initialTime + 1800); vm.prank(FACILITATOR); (liq,,) = depositor.deposit(dp); @@ -430,7 +382,7 @@ contract DepositorUniV3Test is DssTest { assertLt(due0, 10_000 * WAD - deposited0 - withdrawn0); assertLt(due1, 10_000 * 10**6 - deposited1 - withdrawn1); - dp.liquidity = liq; + dp = _getTestWithdrawParams(liq, 0, 0); vm.expectRevert("DepositorUniV3/exceeds-due-amt"); vm.prank(FACILITATOR); depositor.withdraw(dp, false); @@ -445,20 +397,9 @@ contract DepositorUniV3Test is DssTest { } function testWithdrawWithFeeCollection() public { - DepositorUniV3.LiquidityParams memory dp = DepositorUniV3.LiquidityParams({ - gem0: DAI, - gem1: USDC, - fee: uint24(100), - tickLower: REF_TICK-100, - tickUpper: REF_TICK+100, - liquidity: 0, - amt0Desired: 500 * WAD, - amt1Desired: 500 * 10**6, - amt0Min: 490 * WAD, - amt1Min: 490 * 10**6 - }); + DepositorUniV3.LiquidityParams memory dp = _getTestDepositParams(0, 500 * WAD, 500 * 10**6); vm.prank(FACILITATOR); (uint128 liq,,) = depositor.deposit(dp); - assertGt(_getLiquidity(DAI, USDC, 100, REF_TICK-100, REF_TICK+100), 0); + assertGt(UniV3Utils.getLiquidity(address(depositor), DAI, USDC, 100, REF_TICK-100, REF_TICK+100), 0); uint256 prevUSDC = GemLike(USDC).balanceOf(address(buffer)); uint256 prevDAI = GemLike(DAI).balanceOf(address(buffer)); @@ -474,7 +415,7 @@ contract DepositorUniV3Test is DssTest { }); SwapRouterLike(UNIV3_ROUTER).exactInput(params); - dp.liquidity = liq; + dp = _getTestWithdrawParams(liq, 0, 0); vm.warp(block.timestamp + 3600); uint256 snapshot = vm.snapshot(); @@ -491,25 +432,14 @@ contract DepositorUniV3Test is DssTest { assertEq(GemLike(USDC).balanceOf(address(buffer)), prevUSDC + withdrawn1 + fees1); assertEq(GemLike(DAI).balanceOf(address(depositor)), 0); assertEq(GemLike(USDC).balanceOf(address(depositor)), 0); - assertEq(_getLiquidity(DAI, USDC, 100, REF_TICK-100, REF_TICK+100), 0); + assertEq(UniV3Utils.getLiquidity(address(depositor), DAI, USDC, 100, REF_TICK-100, REF_TICK+100), 0); assertEq(liquidity, liq); } function testWithdrawZeroWithFeeCollection() public { - DepositorUniV3.LiquidityParams memory dp = DepositorUniV3.LiquidityParams({ - gem0: DAI, - gem1: USDC, - fee: uint24(100), - tickLower: REF_TICK-100, - tickUpper: REF_TICK+100, - liquidity: 0, - amt0Desired: 500 * WAD, - amt1Desired: 500 * 10**6, - amt0Min: 490 * WAD, - amt1Min: 490 * 10**6 - }); + DepositorUniV3.LiquidityParams memory dp = _getTestDepositParams(0, 500 * WAD, 500 * 10**6); vm.prank(FACILITATOR); (uint128 liq,,) = depositor.deposit(dp); - assertGt(_getLiquidity(DAI, USDC, 100, REF_TICK-100, REF_TICK+100), 0); + assertGt(UniV3Utils.getLiquidity(address(depositor), DAI, USDC, 100, REF_TICK-100, REF_TICK+100), 0); uint256 prevUSDC = GemLike(USDC).balanceOf(address(buffer)); uint256 prevDAI = GemLike(DAI).balanceOf(address(buffer)); @@ -547,30 +477,17 @@ contract DepositorUniV3Test is DssTest { assertEq(GemLike(USDC).balanceOf(address(buffer)), prevUSDC + fees1); assertEq(GemLike(DAI).balanceOf(address(depositor)), 0); assertEq(GemLike(USDC).balanceOf(address(depositor)), 0); - assertEq(_getLiquidity(DAI, USDC, 100, REF_TICK-100, REF_TICK+100), liq); + assertEq(UniV3Utils.getLiquidity(address(depositor), DAI, USDC, 100, REF_TICK-100, REF_TICK+100), liq); } function testWithdrawAmounts() public { - DepositorUniV3.LiquidityParams memory dp = DepositorUniV3.LiquidityParams({ - gem0: DAI, - gem1: USDC, - fee: uint24(100), - tickLower: REF_TICK-100, - tickUpper: REF_TICK+100, - liquidity: 0, - amt0Desired: 500 * WAD, - amt1Desired: 500 * 10**6, - amt0Min: 490 * WAD, - amt1Min: 490 * 10**6 - }); + DepositorUniV3.LiquidityParams memory dp = _getTestDepositParams(0, 500 * WAD, 500 * 10**6); vm.prank(FACILITATOR); (, uint256 deposited0, uint256 deposited1) = depositor.deposit(dp); - assertGt(_getLiquidity(DAI, USDC, 100, REF_TICK-100, REF_TICK+100), 0); + assertGt(UniV3Utils.getLiquidity(address(depositor), DAI, USDC, 100, REF_TICK-100, REF_TICK+100), 0); - dp.liquidity = 0; - dp.amt0Desired = deposited0; - dp.amt1Desired = deposited1; + dp = _getTestWithdrawParams(0, deposited0, deposited1); - uint256 liquidityBeforeWithdraw = _getLiquidity(DAI, USDC, 100, REF_TICK-100, REF_TICK+100); + uint256 liquidityBeforeWithdraw = UniV3Utils.getLiquidity(address(depositor), DAI, USDC, 100, REF_TICK-100, REF_TICK+100); vm.warp(block.timestamp + 3600); @@ -587,7 +504,7 @@ contract DepositorUniV3Test is DssTest { assertGe(withdrawn1 * 100001 / 100000, deposited1); assertEq(GemLike(DAI).balanceOf(address(depositor)), 0); assertEq(GemLike(USDC).balanceOf(address(depositor)), 0); - assertLt(_getLiquidity(DAI, USDC, 100, REF_TICK-100, REF_TICK+100), liquidityBeforeWithdraw); + assertLt(UniV3Utils.getLiquidity(address(depositor), DAI, USDC, 100, REF_TICK-100, REF_TICK+100), liquidityBeforeWithdraw); assertEq(fees0, 0); assertEq(fees1, 0); assertGt(liquidity, 0); diff --git a/test/funnels/UniV3Utils.sol b/test/funnels/UniV3Utils.sol new file mode 100644 index 00000000..8bd20ad6 --- /dev/null +++ b/test/funnels/UniV3Utils.sol @@ -0,0 +1,218 @@ +pragma solidity ^0.8.16; + +import {LiquidityAmounts, FixedPoint96} from "src/funnels/uniV3/LiquidityAmounts.sol"; +import {TickMath} from "src/funnels/uniV3/TickMath.sol"; +import {FullMath} from "src/funnels/uniV3/FullMath.sol"; + +interface UniV3PoolLike { + function slot0() external view returns ( + uint160 sqrtPriceX96, + int24 tick, + uint16 observationIndex, + uint16 observationCardinality, + uint16 observationCardinalityNext, + uint8 feeProtocol, + bool unlocked + ); + + struct PositionInfo { + uint128 liquidity; + uint256 feeGrowthInside0LastX128; + uint256 feeGrowthInside1LastX128; + uint128 tokensOwed0; + uint128 tokensOwed1; + } + + function positions(bytes32) external view returns (PositionInfo memory); +} + +// https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/contracts/libraries/SafeCast.sol +library SafeCast { + function toInt128(int256 y) internal pure returns (int128 z) { + require((z = int128(y)) == y); + } + + function toInt256(uint256 y) internal pure returns (int256 z) { + require(y < 2**255); + z = int256(y); + } +} + +library UniV3Utils { + using SafeCast for uint256; + using SafeCast for int256; + + address constant UNIV3_ROUTER = 0xE592427A0AEce92De3Edee1F18E0157C05861564; + address constant UNIV3_FACTORY = 0x1F98431c8aD98523631AE4a59f267346ea31F984; + // https://github.com/Uniswap/v3-periphery/blob/464a8a49611272f7349c970e0fadb7ec1d3c1086/contracts/libraries/PoolAddress.sol#L33 + function getPool(address gem0, address gem1, uint24 fee) internal pure returns (UniV3PoolLike pool) { + pool = UniV3PoolLike(address(uint160(uint256(keccak256(abi.encodePacked( + hex'ff', + UNIV3_FACTORY, + keccak256(abi.encode(gem0, gem1, fee)), + bytes32(0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54) // POOL_INIT_CODE_HASH + )))))); + } + + function getLiquidity( + address owner, + address gem0, + address gem1, + uint24 fee, + int24 tickLower, + int24 tickUpper + ) internal view returns (uint128 liquidity) { + return getPool(gem0, gem1, fee).positions(keccak256(abi.encodePacked(owner, tickLower, tickUpper))).liquidity; + } + + function getCurrentTick(address gem0, address gem1, uint24 fee) internal view returns (int24 tick) { + (, tick,,,,,) = getPool(gem0, gem1, fee).slot0(); + } + + function getLiquidityForAmts( + UniV3PoolLike pool, + int24 tickLower, + int24 tickUpper, + uint256 amt0Desired, + uint256 amt1Desired + ) internal view returns (uint128 liquidity) { + (uint160 sqrtPriceX96, , , , , , ) = pool.slot0(); + uint160 sqrtRatioAX96 = TickMath.getSqrtRatioAtTick(tickLower); + uint160 sqrtRatioBX96 = TickMath.getSqrtRatioAtTick(tickUpper); + + liquidity = LiquidityAmounts.getLiquidityForAmounts( + sqrtPriceX96, + sqrtRatioAX96, + sqrtRatioBX96, + amt0Desired, + amt1Desired + ); + } + + // https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/contracts/libraries/UnsafeMath.sol#L12 + function divRoundingUp(uint256 x, uint256 y) internal pure returns (uint256 z) { + assembly { + z := add(div(x, y), gt(mod(x, y), 0)) + } + } + + // https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/contracts/libraries/SqrtPriceMath.sol#L153 + function getAmount0Delta( + uint160 sqrtRatioAX96, + uint160 sqrtRatioBX96, + uint128 liquidity, + bool roundUp + ) internal pure returns (uint256 amount0) { + unchecked { + if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); + + uint256 numerator1 = uint256(liquidity) << FixedPoint96.RESOLUTION; + uint256 numerator2 = sqrtRatioBX96 - sqrtRatioAX96; + + require(sqrtRatioAX96 > 0); + + return + roundUp + ? divRoundingUp( + FullMath.mulDivRoundingUp(numerator1, numerator2, sqrtRatioBX96), + sqrtRatioAX96 + ) + : FullMath.mulDiv(numerator1, numerator2, sqrtRatioBX96) / sqrtRatioAX96; + } + } + + // https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/contracts/libraries/SqrtPriceMath.sol#L182 + function getAmount1Delta( + uint160 sqrtRatioAX96, + uint160 sqrtRatioBX96, + uint128 liquidity, + bool roundUp + ) internal pure returns (uint256 amount1) { + unchecked { + if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); + + return + roundUp + ? FullMath.mulDivRoundingUp(liquidity, sqrtRatioBX96 - sqrtRatioAX96, FixedPoint96.Q96) + : FullMath.mulDiv(liquidity, sqrtRatioBX96 - sqrtRatioAX96, FixedPoint96.Q96); + } + } + + // https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/contracts/libraries/SqrtPriceMath.sol#L201 + function getAmount0Delta( + uint160 sqrtRatioAX96, + uint160 sqrtRatioBX96, + int128 liquidity + ) internal pure returns (int256 amount0) { + unchecked { + return + liquidity < 0 + ? -getAmount0Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(-liquidity), false).toInt256() + : getAmount0Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(liquidity), true).toInt256(); + } + } + + // https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/contracts/libraries/SqrtPriceMath.sol#L217C7-L217C7 + function getAmount1Delta( + uint160 sqrtRatioAX96, + uint160 sqrtRatioBX96, + int128 liquidity + ) internal pure returns (int256 amount1) { + unchecked { + return + liquidity < 0 + ? -getAmount1Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(-liquidity), false).toInt256() + : getAmount1Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(liquidity), true).toInt256(); + } + } + + // adapted from https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/contracts/UniswapV3Pool.sol#L327 + function getExpectedAmounts( + address gem0, + address gem1, + uint24 fee, + int24 tickLower, + int24 tickUpper, + uint128 liquidity, + uint256 amt0Desired, + uint256 amt1Desired, + bool withdrawal + ) internal view returns (uint256 expectedAmt0, uint256 expectedAmt1) { + unchecked { + UniV3PoolLike pool = getPool(gem0, gem1, fee); + (uint160 sqrtPriceX96, int24 tick,,,,,) = pool.slot0(); + int128 liqDelta = (int256(uint256(liquidity == 0 ? getLiquidityForAmts(pool, tickLower, tickUpper, amt0Desired, amt1Desired) : liquidity))).toInt128(); + if (withdrawal) liqDelta = -liqDelta; + + int256 expectedAmt0_; + int256 expectedAmt1_; + if (tick < tickLower) { + expectedAmt0_ = getAmount0Delta( + TickMath.getSqrtRatioAtTick(tickLower), + TickMath.getSqrtRatioAtTick(tickUpper), + liqDelta + ); + } else if (tick < tickUpper) { + expectedAmt0_ = getAmount0Delta( + sqrtPriceX96, + TickMath.getSqrtRatioAtTick(tickUpper), + liqDelta + ); + expectedAmt1_ = getAmount1Delta( + TickMath.getSqrtRatioAtTick(tickLower), + sqrtPriceX96, + liqDelta + ); + } else { + expectedAmt1_ = getAmount1Delta( + TickMath.getSqrtRatioAtTick(tickLower), + TickMath.getSqrtRatioAtTick(tickUpper), + liqDelta + ); + } + + expectedAmt0 = uint256(withdrawal ? -expectedAmt0_: expectedAmt0_); + expectedAmt1 = uint256(withdrawal ? -expectedAmt1_: expectedAmt1_); + } + } +} diff --git a/test/funnels/automation/StableDepositorUniV3.t.sol b/test/funnels/automation/StableDepositorUniV3.t.sol index 6eea77a5..b06c2fbc 100644 --- a/test/funnels/automation/StableDepositorUniV3.t.sol +++ b/test/funnels/automation/StableDepositorUniV3.t.sol @@ -8,6 +8,8 @@ import { StableDepositorUniV3 } from "src/funnels/automation/StableDepositorUniV import { AllocatorRoles } from "src/AllocatorRoles.sol"; import { AllocatorBuffer } from "src/AllocatorBuffer.sol"; +import { UniV3Utils } from "test/funnels/UniV3Utils.sol"; + interface GemLike { function balanceOf(address) external view returns (uint256); function transfer(address, uint256) external; @@ -40,15 +42,18 @@ contract StableDepositorUniV3Test is DssTest { address constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F; address constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; - address constant UNIV3_ROUTER = 0xE592427A0AEce92De3Edee1F18E0157C05861564; - address constant UNIV3_FACTORY = 0x1F98431c8aD98523631AE4a59f267346ea31F984; + address constant UNIV3_ROUTER = UniV3Utils.UNIV3_ROUTER; + address constant UNIV3_FACTORY = UniV3Utils.UNIV3_FACTORY; address constant FACILITATOR = address(0x1337); address constant KEEPER = address(0xb0b); uint8 constant DEPOSITOR_ROLE = uint8(1); - int24 constant REF_TICK = -276324; // tick corresponding to 1 DAI = 1 USDC calculated as ~= math.log(10**(-12))/math.log(1.0001) + int24 REF_TICK; + + uint96 req0; + uint96 req1; function setUp() public { vm.createSelectFork(vm.envString("ETH_RPC_URL")); @@ -72,9 +77,14 @@ contract StableDepositorUniV3Test is DssTest { buffer.approve(USDC, address(depositor), type(uint256).max); buffer.approve(DAI, address(depositor), type(uint256).max); + REF_TICK = UniV3Utils.getCurrentTick(DAI, USDC, uint24(100)); + stableDepositor.rely(FACILITATOR); vm.startPrank(FACILITATOR); - stableDepositor.setConfig(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, 10, 360, uint96(500 * WAD), uint96(500 * 10**6), uint96(490 * WAD), uint96(490 * 10**6)); + (uint256 expectedAmt0, uint256 expectedAmt1) = UniV3Utils.getExpectedAmounts(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, 0, 500 * WAD, 500 * 10**6, false); + req0 = uint96(expectedAmt0 * 90 / 100); + req1 = uint96(expectedAmt1 * 90 / 100); + stableDepositor.setConfig(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, 10, 360, uint96(500 * WAD), uint96(500 * 10**6), req0, req1); stableDepositor.kiss(KEEPER); vm.stopPrank(); @@ -128,16 +138,16 @@ contract StableDepositorUniV3Test is DssTest { uint32 zzz, uint96 amt0, uint96 amt1, - uint96 req0, - uint96 req1, + uint96 req0_, + uint96 req1_, uint32 hop ) = stableDepositor.configs(address(0x123), address(0x456), uint24(314), 5, 6); assertEq(num, 23); assertEq(zzz, 0); assertEq(amt0, uint96(7)); assertEq(amt1, uint96(8)); - assertEq(req0, uint96(9)); - assertEq(req1, uint96(10)); + assertEq(req0_, uint96(9)); + assertEq(req1_, uint96(10)); assertEq(hop, 3600); } @@ -148,7 +158,7 @@ contract StableDepositorUniV3Test is DssTest { assertEq(initNum, 10); uint32 initialTime = uint32(block.timestamp); - vm.prank(KEEPER); stableDepositor.deposit(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, uint128(491 * WAD), uint128(491 * 10**6)); + vm.prank(KEEPER); stableDepositor.deposit(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, req0, req1); uint256 afterDepositDai = GemLike(DAI).balanceOf(address(buffer)); uint256 afterDepositUsdc = GemLike(USDC).balanceOf(address(buffer)); @@ -160,36 +170,53 @@ contract StableDepositorUniV3Test is DssTest { vm.warp(initialTime + 180); vm.expectRevert("StableDepositorUniV3/too-soon"); - vm.prank(KEEPER); stableDepositor.deposit(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, uint128(491 * WAD), uint128(491 * 10**6)); + vm.prank(KEEPER); stableDepositor.deposit(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, req0, req1); vm.warp(initialTime + 360); - vm.prank(KEEPER); stableDepositor.deposit(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, uint128(491 * WAD), uint128(491 * 10**6)); + vm.prank(KEEPER); stableDepositor.deposit(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, req0, req1); (num, zzz,,,,,) = stableDepositor.configs(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100); assertEq(num, initNum - 2); assertEq(zzz, initialTime + 360); - stableDepositor.setConfig(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, -10, 360, uint96(500 * WAD), uint96(500 * 10**6), uint96(490 * WAD), uint96(490 * 10**6)); + vm.warp(initialTime + 2*360); + vm.prank(KEEPER); stableDepositor.deposit(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, req0 + 1, req1 + 1); // also making sure that amt{i}Min is allowed to be > req{i} + (num, zzz,,,,,) = stableDepositor.configs(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100); + + assertEq(num, initNum - 3); + assertEq(zzz, initialTime + 2*360); + + (uint256 expectedAmt0, uint256 expectedAmt1) = UniV3Utils.getExpectedAmounts(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, 0, 500 * WAD, 500 * 10**6, true); + uint96 req0_ = uint96(expectedAmt0 * 90 / 100); + uint96 req1_ = uint96(expectedAmt1 * 90 / 100); + stableDepositor.setConfig(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, -10, 360, uint96(500 * WAD), uint96(500 * 10**6), req0_, req1_); (initNum,,,,,,) = stableDepositor.configs(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100); assertEq(initNum, -10); - vm.prank(KEEPER); stableDepositor.withdraw(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, uint128(491 * WAD), uint128(491 * 10**6)); + vm.prank(KEEPER); stableDepositor.withdraw(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, req0_, req1_); (num, zzz,,,,,) = stableDepositor.configs(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100); assertEq(num, initNum + 1); - assertEq(zzz, initialTime + 360); + assertEq(zzz, initialTime + 2*360); - vm.warp(initialTime + 540); + vm.warp(initialTime + 2*360 + 180); vm.expectRevert("StableDepositorUniV3/too-soon"); - vm.prank(KEEPER); stableDepositor.withdraw(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, uint128(491 * WAD), uint128(491 * 10**6)); + vm.prank(KEEPER); stableDepositor.withdraw(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, req0_, req1_); + + vm.warp(initialTime + 3*360); + vm.prank(KEEPER); stableDepositor.withdraw(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, req0_, req1_); + (num, zzz,,,,,) = stableDepositor.configs(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100); + + assertEq(num, initNum + 2); + assertEq(zzz, initialTime + 3*360); - vm.warp(initialTime + 720); - vm.prank(KEEPER); stableDepositor.withdraw(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, uint128(491 * WAD), uint128(491 * 10**6)); + vm.warp(initialTime + 4*360); + vm.prank(KEEPER); stableDepositor.withdraw(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, req0_ + 1, req1_ + 1); // also making sure that amt{i}Min is allowed to be > req{i} (num, zzz,,,,,) = stableDepositor.configs(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100); assertGt(GemLike(DAI).balanceOf(address(buffer)), afterDepositDai); assertGt(GemLike(USDC).balanceOf(address(buffer)), afterDepositUsdc); - assertEq(num, initNum + 2); - assertEq(zzz, initialTime + 720); + assertEq(num, initNum + 3); + assertEq(zzz, initialTime + 4*360); } function testDepositWithdrawMinZero() public { @@ -203,7 +230,10 @@ contract StableDepositorUniV3Test is DssTest { assertLt(afterDepositDai, prevDai); assertLt(afterDepositUsdc, prevUsdc); - stableDepositor.setConfig(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, -10, 360, uint96(500 * WAD), uint96(500 * 10**6), uint96(490 * WAD), uint96(490 * 10**6)); + (uint256 expectedAmt0, uint256 expectedAmt1) = UniV3Utils.getExpectedAmounts(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, 0, 500 * WAD, 500 * 10**6, true); + uint96 req0_ = uint96(expectedAmt0 * 90 / 100); + uint96 req1_ = uint96(expectedAmt1 * 90 / 100); + stableDepositor.setConfig(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, -10, 360, uint96(500 * WAD), uint96(500 * 10**6), req0_, req1_); vm.prank(KEEPER); stableDepositor.withdraw(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, 0, 0); assertGt(GemLike(DAI).balanceOf(address(buffer)), afterDepositDai); @@ -211,31 +241,27 @@ contract StableDepositorUniV3Test is DssTest { } function testDepositWithdrawExceedingNum() public { - stableDepositor.setConfig(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, -10, 360, uint96(500 * WAD), uint96(500 * 10**6), uint96(490 * WAD), uint96(490 * 10**6)); + stableDepositor.setConfig(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, -10, 360, uint96(500 * WAD), uint96(500 * 10**6), 0, 0); vm.expectRevert("StableDepositorUniV3/exceeds-num"); - vm.prank(KEEPER); stableDepositor.deposit(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, uint128(491 * 10**6), uint128(491 * WAD)); + vm.prank(KEEPER); stableDepositor.deposit(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, 0, 0); - stableDepositor.setConfig(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, 10, 360, uint96(500 * WAD), uint96(500 * 10**6), uint96(490 * WAD), uint96(490 * 10**6)); + stableDepositor.setConfig(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, 10, 360, uint96(500 * WAD), uint96(500 * 10**6), 0, 0); vm.expectRevert("StableDepositorUniV3/exceeds-num"); - vm.prank(KEEPER); stableDepositor.withdraw(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, uint128(491 * 10**6), uint128(491 * WAD)); + vm.prank(KEEPER); stableDepositor.withdraw(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, 0, 0); } function testDepositWithMin0TooSmall() public { - (,,,,, uint96 req0,) = stableDepositor.configs(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100); - vm.expectRevert("StableDepositorUniV3/min-amt0-too-small"); - vm.prank(KEEPER); stableDepositor.deposit(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, req0 - 1, uint128(491 * 10**6)); + vm.prank(KEEPER); stableDepositor.deposit(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, req0 - 1, req1); } function testDepositWithMin1TooSmall() public { - (,,,,,, uint96 req1) = stableDepositor.configs(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100); - vm.expectRevert("StableDepositorUniV3/min-amt1-too-small"); - vm.prank(KEEPER); stableDepositor.deposit(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, uint128(491 * WAD), req1 - 1); + vm.prank(KEEPER); stableDepositor.deposit(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, req0, req1 - 1); } function testCollectByKeeper() public { - vm.prank(KEEPER); stableDepositor.deposit(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, uint128(491 * WAD), uint128(491 * 10**6)); + vm.prank(KEEPER); stableDepositor.deposit(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, req0, req1); uint256 prevDai = GemLike(DAI).balanceOf(address(buffer)); uint256 prevUsdc = GemLike(USDC).balanceOf(address(buffer)); @@ -263,10 +289,10 @@ contract StableDepositorUniV3Test is DssTest { assertEq(stableDepositor.buds(address(this)), 0); vm.expectRevert("StableDepositorUniV3/non-keeper"); - stableDepositor.deposit(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, uint128(491 * WAD), uint128(491 * 10**6)); + stableDepositor.deposit(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, 0, 0); vm.expectRevert("StableDepositorUniV3/non-keeper"); - stableDepositor.withdraw(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, uint128(491 * WAD), uint128(491 * 10**6)); + stableDepositor.withdraw(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, 0, 0); vm.expectRevert("StableDepositorUniV3/non-keeper"); vm.prank(address(0x123)); stableDepositor.collect(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100); From 1d36641f72c8809239da88be1936d7de2e50ba51 Mon Sep 17 00:00:00 2001 From: oldchili <130549691+oldchili@users.noreply.github.com> Date: Thu, 28 Sep 2023 20:38:14 +0300 Subject: [PATCH 55/74] Configure autoline in init script (#62) --- deploy/AllocatorInit.sol | 14 ++++++++++---- test/integration/Deployment.t.sol | 22 +++++++++++++++++++--- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/deploy/AllocatorInit.sol b/deploy/AllocatorInit.sol index 9de9e25b..8e85ccc6 100644 --- a/deploy/AllocatorInit.sol +++ b/deploy/AllocatorInit.sol @@ -118,10 +118,16 @@ interface KissLike { function kiss(address) external; } +interface AutoLineLike { + function setIlk(bytes32, uint256, uint256, uint256) external; +} + struct AllocatorIlkConfig { bytes32 ilk; uint256 duty; - uint256 debtCeiling; + uint256 gap; + uint256 maxLine; + uint256 ttl; address allocatorProxy; uint8 facilitatorRole; uint8 automationRole; @@ -195,9 +201,9 @@ library AllocatorInit { require((cfg.duty >= RAY) && (cfg.duty <= RATES_ONE_HUNDRED_PCT), "AllocatorInit/ilk-duty-out-of-bounds"); dss.jug.file(ilk, "duty", cfg.duty); - require(cfg.debtCeiling < WAD, "AllocatorInit/incorrect-ilk-line-precision"); - dss.vat.file(ilk, "line", cfg.debtCeiling * RAD); - dss.vat.file("Line", dss.vat.Line() + cfg.debtCeiling * RAD); + dss.vat.file(ilk, "line", cfg.gap); + dss.vat.file("Line", dss.vat.Line() + cfg.gap); + AutoLineLike(dss.chainlog.getAddress("MCD_IAM_AUTO_LINE")).setIlk(ilk, cfg.maxLine, cfg.gap, cfg.ttl); dss.spotter.file(ilk, "pip", sharedInstance.oracle); dss.spotter.file(ilk, "mat", RAY); diff --git a/test/integration/Deployment.t.sol b/test/integration/Deployment.t.sol index abce9904..f433fa98 100644 --- a/test/integration/Deployment.t.sol +++ b/test/integration/Deployment.t.sol @@ -64,6 +64,10 @@ interface IlkRegistryLike { function name(bytes32) external view returns (string memory); } +interface AutoLineLike { + function ilks(bytes32) external view returns (uint256, uint256, uint48, uint48, uint48); +} + contract DeploymentTest is DssTest { // existing contracts @@ -175,7 +179,9 @@ contract DeploymentTest is DssTest { AllocatorIlkConfig memory cfg = AllocatorIlkConfig({ ilk : ILK, duty : 1000000001243680656318820312, - debtCeiling : 100_000_000, + maxLine : 100_000_000 * RAD, + gap : 10_000_000 * RAD, + ttl : 1 days, allocatorProxy : allocatorProxy, facilitatorRole : facilitatorRole, automationRole : automationRole, @@ -223,8 +229,18 @@ contract DeploymentTest is DssTest { (, uint256 rate, uint256 spot, uint256 line,) = dss.vat.ilks(ILK); assertEq(rate, RAY); assertEq(spot, 10**6 * 10**18 * RAY * 10**9 / dss.spotter.par()); - assertEq(line, 100_000_000 * RAD); - assertEq(dss.vat.Line(), previousLine + 100_000_000 * RAD); + assertEq(line, 10_000_000 * RAD); + assertEq(dss.vat.Line(), previousLine + 10_000_000 * RAD); + + { + AutoLineLike autoLine = AutoLineLike(ChainlogLike(LOG).getAddress("MCD_IAM_AUTO_LINE")); + (uint256 maxline, uint256 gap, uint48 ttl, uint48 last, uint48 lastInc) = autoLine.ilks(ILK); + assertEq(maxline, 100_000_000 * RAD); + assertEq(gap, 10_000_000 * RAD); + assertEq(ttl, 1 days); + assertEq(last, 0); + assertEq(lastInc, 0); + } (uint256 duty, uint256 rho) = dss.jug.ilks(ILK); assertEq(duty, 1000000001243680656318820312); From f934c91b6db00893d9a0eff420375a6ecebdf585 Mon Sep 17 00:00:00 2001 From: oldchili <130549691+oldchili@users.noreply.github.com> Date: Tue, 10 Oct 2023 11:10:02 +0300 Subject: [PATCH 56/74] Add init validation for UniV3 Factory (#63) --- deploy/AllocatorInit.sol | 9 ++++++--- test/integration/Deployment.t.sol | 3 ++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/deploy/AllocatorInit.sol b/deploy/AllocatorInit.sol index 8e85ccc6..27ad7d41 100644 --- a/deploy/AllocatorInit.sol +++ b/deploy/AllocatorInit.sol @@ -95,6 +95,7 @@ interface DepositorUniV3Like { function roles() external view returns (address); function ilk() external view returns (bytes32); + function uniV3Factory() external view returns (address); function buffer() external view returns (address); function deposit(LiquidityParams memory) external returns (uint128, uint256, uint256); function withdraw(LiquidityParams memory, bool) external returns (uint128, uint256, uint256, uint256, uint256); @@ -138,6 +139,7 @@ struct AllocatorIlkConfig { address[] swapTokens; address[] depositTokens; address ilkRegistry; + address uniV3Factory; } function bytes32ToStr(bytes32 _bytes32) pure returns (string memory) { @@ -184,9 +186,10 @@ library AllocatorInit { require(SwapperLike(ilkInstance.swapper).ilk() == ilk, "AllocatorInit/swapper-ilk-mismatch"); require(SwapperLike(ilkInstance.swapper).buffer() == ilkInstance.buffer, "AllocatorInit/swapper-buffer-mismatch"); - require(DepositorUniV3Like(ilkInstance.depositorUniV3).roles() == sharedInstance.roles, "AllocatorInit/depositorUniV3-roles-mismatch"); - require(DepositorUniV3Like(ilkInstance.depositorUniV3).ilk() == ilk, "AllocatorInit/depositorUniV3-ilk-mismatch"); - require(DepositorUniV3Like(ilkInstance.depositorUniV3).buffer() == ilkInstance.buffer, "AllocatorInit/depositorUniV3-buffer-mismatch"); + require(DepositorUniV3Like(ilkInstance.depositorUniV3).roles() == sharedInstance.roles, "AllocatorInit/depositorUniV3-roles-mismatch"); + require(DepositorUniV3Like(ilkInstance.depositorUniV3).ilk() == ilk, "AllocatorInit/depositorUniV3-ilk-mismatch"); + require(DepositorUniV3Like(ilkInstance.depositorUniV3).uniV3Factory() == cfg.uniV3Factory, "AllocatorInit/depositorUniV3-uniV3Factory-mismatch"); + require(DepositorUniV3Like(ilkInstance.depositorUniV3).buffer() == ilkInstance.buffer, "AllocatorInit/depositorUniV3-buffer-mismatch"); require(StableSwapperLike(ilkInstance.stableSwapper).swapper() == ilkInstance.swapper, "AllocatorInit/stableSwapper-swapper-mismatch"); require(StableDepositorUniV3Like(ilkInstance.stableDepositorUniV3).depositor() == ilkInstance.depositorUniV3, "AllocatorInit/stableDepositorUniV3-depositorUniV3-mismatch"); diff --git a/test/integration/Deployment.t.sol b/test/integration/Deployment.t.sol index f433fa98..278b796f 100644 --- a/test/integration/Deployment.t.sol +++ b/test/integration/Deployment.t.sol @@ -191,7 +191,8 @@ contract DeploymentTest is DssTest { conduitMoverKeepers : conduitMoverKeepers, swapTokens : swapTokens, depositTokens : depositTokens, - ilkRegistry : ILK_REGISTRY + ilkRegistry : ILK_REGISTRY, + uniV3Factory : UNIV3_FACTORY }); AllocatorInit.initIlk(dss, sharedInst, ilkInst, cfg); From c68b72a292850ecddf7a3c31d8a9aa45213a5128 Mon Sep 17 00:00:00 2001 From: oldchili <130549691+oldchili@users.noreply.github.com> Date: Wed, 11 Oct 2023 13:16:22 +0300 Subject: [PATCH 57/74] Add ChainSecurity Deployment Scripts audit --- ...rDAO_Allocator_Deployment_Scripts_audit.pdf | Bin 0 -> 491277 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 audit/ChainSecurity_MakerDAO_Allocator_Deployment_Scripts_audit.pdf diff --git a/audit/ChainSecurity_MakerDAO_Allocator_Deployment_Scripts_audit.pdf b/audit/ChainSecurity_MakerDAO_Allocator_Deployment_Scripts_audit.pdf new file mode 100644 index 0000000000000000000000000000000000000000..1c42f25e7c10907a6ae64769ac7b98c54909c11f GIT binary patch literal 491277 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
    *1;C+KlJwklt=pBvmL6X!s>&>sdrIW{I% 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 WcCiFAjL@>Z_Ke!KTXt%d@&5pzuE6#H literal 0 HcmV?d00001 From 4ad21cd2d7874e403c48737559d8c0447ac3eb62 Mon Sep 17 00:00:00 2001 From: telome <> Date: Thu, 12 Oct 2023 16:59:47 +0100 Subject: [PATCH 58/74] Fix testGetPosition --- test/funnels/DepositorUniV3.t.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/funnels/DepositorUniV3.t.sol b/test/funnels/DepositorUniV3.t.sol index edd0f5cc..ad0c52e3 100644 --- a/test/funnels/DepositorUniV3.t.sol +++ b/test/funnels/DepositorUniV3.t.sol @@ -261,8 +261,8 @@ contract DepositorUniV3Test is DssTest { tokensOwed1 ) = depositor.getPosition(DAI, USDC, 100, REF_TICK-100, REF_TICK+100); assertEq(liquidity, 99777667447878834); - assertGt(feeGrowthInside0LastX128, 0); // initial value now that the position is created - assertGt(feeGrowthInside1LastX128, 0); // initial value now that the position is created + assertGe(feeGrowthInside0LastX128, 0); // initial value now that the position is created + assertGe(feeGrowthInside1LastX128, 0); // initial value now that the position is created assertEq(tokensOwed0, 0); assertEq(tokensOwed1, 0); From 7692abec1b85d9533b9f54392e7f081159e8d343 Mon Sep 17 00:00:00 2001 From: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> Date: Fri, 13 Oct 2023 06:54:37 -0300 Subject: [PATCH 59/74] Changes from audit (#61) * Remove unused interface functions * Roles: Use inbuilt bit negator * Roles: more optimized way to shift bit * StableSwapper: fix typo * Fix SwapperCalleeUniV3 approve interface * Add USDT swap test * Rename ApproveLike -> GemLike * Update test/funnels/callees/SwapperCalleeUniV3.t.sol * Add fee to depositor events * Enforce src == path[0] in callee * Fix typos and clarify keeper's assumptions * Audit fix additions (#64) * Force ConduitMover to withdraw only lot * Add clarification on Buffer-Conduits movement rate limiting responsibilities * Minor changes * Add comment on 0/0 division of divup (#65) --------- Co-authored-by: telome <> Co-authored-by: telome <130504305+telome@users.noreply.github.com> Co-authored-by: oldchili <130549691+oldchili@users.noreply.github.com> --- README.md | 5 +++-- src/AllocatorBuffer.sol | 3 --- src/AllocatorRoles.sol | 18 ++++++------------ src/AllocatorVault.sol | 1 + src/funnels/DepositorUniV3.sol | 12 ++++++------ src/funnels/automation/ConduitMover.sol | 10 +++++++--- src/funnels/automation/StableSwapper.sol | 4 ++-- src/funnels/callees/SwapperCalleeUniV3.sol | 18 +++++++++++++----- test/AllocatorVault.t.sol | 1 + test/funnels/DepositorUniV3.t.sol | 18 +++++++++--------- test/funnels/automation/ConduitMover.t.sol | 8 ++++++++ test/funnels/callees/SwapperCalleeUniV3.t.sol | 14 ++++++++++++++ 12 files changed, 70 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 765a44c7..f60d6100 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ It enforces that: ### Swapper Callees -Contracts that perform the actual swap and send the resulting funds to the Swapper (to be forwarded to the AllocatoBuffer). +Contracts that perform the actual swap and send the resulting funds to the Swapper (to be forwarded to the AllocatorBuffer). - They can be implemented on top of any DEX / swap vehicle. - An example is `SwapperCalleeUniV3`, where swaps in Uniswap V3 can be triggered. @@ -130,7 +130,8 @@ An interface which each Conduit should implement. ## Security Model: - AllocatorDAOs can not incur a loss of more than the debt ceiling (`line`) of their respective `ilk`. - A funnel operator (whether a facilitator or an automated contract) can not incur a loss of more than `cap` amount of funds per `era` interval for a specific configuration. This includes not being able to move funds directly to any unknown address that the AllocatorDAO Proxy did not approve. -- A keeper can not incur a loss of more than the funnel opeator can, and any loss it can incur is also constrained by `req` or `req0` and `req1` for a specific configuration. +- A keeper's maximum loss must be bounded by `cap` amount of funds per `era` (as for a funnel operator) but is additionally constrainted by `lot` (or `amt0` and `amt1`) amount of funds per `hop` for a specific configuration. Moreover, a keeper's execution must guarantee a minimum amount of output tokens, defined by `req` (or `req0` and `req1`) for a specific configuration. +- If a rate limit is needed for depositing or withdrawing in a specific Conduit (in order to limit the harm a rogue facilitator can cause), it is the responsibility of the Conduit itself to implement it. ## Technical Assumptions: - A `uint32` is suitable for storing timestamps or time intervals in the funnels, as the current version of the Allocation System is expected to be deprecated long before 2106. diff --git a/src/AllocatorBuffer.sol b/src/AllocatorBuffer.sol index 1273f10c..73d82294 100644 --- a/src/AllocatorBuffer.sol +++ b/src/AllocatorBuffer.sol @@ -17,10 +17,7 @@ pragma solidity ^0.8.16; interface GemLike { - function balanceOf(address) external view returns (uint256); function approve(address, uint256) external; - function transfer(address, uint256) external; - function transferFrom(address, address, uint256) external; } contract AllocatorBuffer { diff --git a/src/AllocatorRoles.sol b/src/AllocatorRoles.sol index 6bef7547..fc25942f 100644 --- a/src/AllocatorRoles.sol +++ b/src/AllocatorRoles.sol @@ -55,17 +55,11 @@ contract AllocatorRoles { // --- getters --- function hasUserRole(bytes32 ilk, address who, uint8 role) external view returns (bool has) { - has = userRoles[ilk][who] & bytes32(2 ** uint256(role)) != bytes32(0); + has = userRoles[ilk][who] & bytes32(uint256(1) << role) != bytes32(0); } function hasActionRole(bytes32 ilk, address target, bytes4 sig, uint8 role) external view returns (bool has) { - has = actionsRoles[ilk][target][sig] & bytes32(2 ** uint256(role)) != bytes32(0); - } - - // --- internals --- - - function _bitNot(bytes32 input) internal pure returns (bytes32 output) { - output = (input ^ bytes32(type(uint256).max)); + has = actionsRoles[ilk][target][sig] & bytes32(uint256(1) << role) != bytes32(0); } // --- general administration --- @@ -88,21 +82,21 @@ contract AllocatorRoles { // --- ilk administration --- function setUserRole(bytes32 ilk, address who, uint8 role, bool enabled) public ilkAuth(ilk) { - bytes32 mask = bytes32(2 ** uint256(role)); + bytes32 mask = bytes32(uint256(1) << role); if (enabled) { userRoles[ilk][who] |= mask; } else { - userRoles[ilk][who] &= _bitNot(mask); + userRoles[ilk][who] &= ~mask; } emit SetUserRole(ilk, who, role, enabled); } function setRoleAction(bytes32 ilk, uint8 role, address target, bytes4 sig, bool enabled) external ilkAuth(ilk) { - bytes32 mask = bytes32(2 ** uint256(role)); + bytes32 mask = bytes32(uint256(1) << role); if (enabled) { actionsRoles[ilk][target][sig] |= mask; } else { - actionsRoles[ilk][target][sig] &= _bitNot(mask); + actionsRoles[ilk][target][sig] &= ~mask; } emit SetRoleAction(ilk, role, target, sig, enabled); } diff --git a/src/AllocatorVault.sol b/src/AllocatorVault.sol index 74825ebd..4d46ffdb 100644 --- a/src/AllocatorVault.sol +++ b/src/AllocatorVault.sol @@ -100,6 +100,7 @@ contract AllocatorVault { // --- math --- function _divup(uint256 x, uint256 y) internal pure returns (uint256 z) { + // Note: _divup(0,0) will return 0 differing from natural solidity division unchecked { z = x != 0 ? ((x - 1) / y) + 1 : 0; } diff --git a/src/funnels/DepositorUniV3.sol b/src/funnels/DepositorUniV3.sol index ae4cda90..3217e58f 100644 --- a/src/funnels/DepositorUniV3.sol +++ b/src/funnels/DepositorUniV3.sol @@ -91,9 +91,9 @@ contract DepositorUniV3 { event Rely(address indexed usr); event Deny(address indexed usr); event SetLimits(address indexed gem0, address indexed gem1, uint24 indexed fee, uint96 cap0, uint96 cap1, uint32 era); - event Deposit(address indexed sender, address indexed gem0, address indexed gem1, uint128 liquidity, uint256 amt0, uint256 amt1); - event Withdraw(address indexed sender, address indexed gem0, address indexed gem1, uint128 liquidity, uint256 amt0, uint256 amt1, uint256 fees0, uint256 fees1); - event Collect(address indexed sender, address indexed gem0, address indexed gem1, uint256 fees0, uint256 fees1); + event Deposit(address indexed sender, address indexed gem0, address indexed gem1, uint24 fee, uint128 liquidity, uint256 amt0, uint256 amt1); + event Withdraw(address indexed sender, address indexed gem0, address indexed gem1, uint24 fee, uint128 liquidity, uint256 amt0, uint256 amt1, uint256 fees0, uint256 fees1); + event Collect(address indexed sender, address indexed gem0, address indexed gem1, uint24 fee, uint256 fees0, uint256 fees1); constructor(address roles_, bytes32 ilk_, address uniV3Factory_, address buffer_) { roles = RolesLike(roles_); @@ -251,7 +251,7 @@ contract DepositorUniV3 { limits[p.gem0][p.gem1][p.fee].due1 = limit.due1 - uint96(amt1); limits[p.gem0][p.gem1][p.fee].end = limit.end; - emit Deposit(msg.sender, p.gem0, p.gem1, liquidity, amt0, amt1); + emit Deposit(msg.sender, p.gem0, p.gem1, p.fee, liquidity, amt0, amt1); } function withdraw(LiquidityParams memory p, bool takeFees) @@ -295,7 +295,7 @@ contract DepositorUniV3 { }); (fees0, fees1) = (collected0 - amt0, collected1 - amt1); - emit Withdraw(msg.sender, p.gem0, p.gem1, liquidity, amt0, amt1, fees0, fees1); + emit Withdraw(msg.sender, p.gem0, p.gem1, p.fee, liquidity, amt0, amt1, fees0, fees1); } struct CollectParams { @@ -324,6 +324,6 @@ contract DepositorUniV3 { amount1Requested: type(uint128).max }); - emit Collect(msg.sender, p.gem0, p.gem1, fees0, fees1); + emit Collect(msg.sender, p.gem0, p.gem1, p.fee, fees0, fees1); } } diff --git a/src/funnels/automation/ConduitMover.sol b/src/funnels/automation/ConduitMover.sol index eb2e6b6f..610bfd4d 100644 --- a/src/funnels/automation/ConduitMover.sol +++ b/src/funnels/automation/ConduitMover.sol @@ -18,7 +18,7 @@ pragma solidity ^0.8.16; interface ConduitLike { function deposit(bytes32, address, uint256) external; - function withdraw(bytes32, address, uint256) external; + function withdraw(bytes32, address, uint256) external returns (uint256); } contract ConduitMover { @@ -99,8 +99,12 @@ contract ConduitMover { unchecked { configs[from][to][gem].num = cfg.num - 1; } configs[from][to][gem].zzz = uint32(block.timestamp); - if (from != buffer) ConduitLike(from).withdraw(ilk, gem, cfg.lot); - if (to != buffer) ConduitLike(to).deposit(ilk, gem, cfg.lot); + if (from != buffer) { + require(ConduitLike(from).withdraw(ilk, gem, cfg.lot) == cfg.lot, "ConduitMover/lot-withdraw-failed"); + } + if (to != buffer) { + ConduitLike(to).deposit(ilk, gem, cfg.lot); + } emit Move(from, to, gem, cfg.lot); } diff --git a/src/funnels/automation/StableSwapper.sol b/src/funnels/automation/StableSwapper.sol index b10c5d80..d1a35194 100644 --- a/src/funnels/automation/StableSwapper.sol +++ b/src/funnels/automation/StableSwapper.sol @@ -32,7 +32,7 @@ contract StableSwapper { uint32 hop; // Cooldown period it has to wait between swap executions uint32 zzz; // Timestamp of the last swap execution uint96 lot; // The amount swapped by keepers from src to dst every hop - uint96 req; // The minimum required output amount to insist on in the swap form src to dst + uint96 req; // The minimum required output amount to insist on in the swap from src to dst } event Rely(address indexed usr); @@ -52,7 +52,7 @@ contract StableSwapper { _; } - // permissionned to whitelisted keepers + // permissioned to whitelisted keepers modifier toll { require(buds[msg.sender] == 1, "StableSwapper/non-keeper"); _; diff --git a/src/funnels/callees/SwapperCalleeUniV3.sol b/src/funnels/callees/SwapperCalleeUniV3.sol index e05a3689..ed0cc333 100644 --- a/src/funnels/callees/SwapperCalleeUniV3.sol +++ b/src/funnels/callees/SwapperCalleeUniV3.sol @@ -16,11 +16,11 @@ pragma solidity ^0.8.16; -interface ApproveLike { - function approve(address, uint256) external returns (bool); +interface GemLike { + function approve(address, uint256) external; } -// https://github.com/Uniswap/v3-periphery/blob/b06959dd01f5999aa93e1dc530fe573c7bb295f6/contracts/SwapRlefter.sol +// https://github.com/Uniswap/v3-periphery/blob/b06959dd01f5999aa93e1dc530fe573c7bb295f6/contracts/SwapRouter.sol interface SwapRouterLike { function exactInput(ExactInputParams calldata params) external returns (uint256 amountOut); @@ -43,9 +43,17 @@ contract SwapperCalleeUniV3 { } function swapCallback(address src, address /* dst */, uint256 amt, uint256 minOut, address to, bytes calldata data) external { - ApproveLike(src).approve(uniV3Router, amt); + bytes memory path = data; + + address src_; + assembly { + src_ := shr(0x60, mload(add(path, 0x20))) + } + require(src == src_, "SwapperCalleeUniV3/invalid-path"); // forbids lingering approval of src + + GemLike(src).approve(uniV3Router, amt); SwapRouterLike.ExactInputParams memory params = SwapRouterLike.ExactInputParams({ - path: data, + path: path, recipient: to, deadline: block.timestamp, amountIn: amt, diff --git a/test/AllocatorVault.t.sol b/test/AllocatorVault.t.sol index e62cdb67..c13c2afb 100644 --- a/test/AllocatorVault.t.sol +++ b/test/AllocatorVault.t.sol @@ -28,6 +28,7 @@ contract AllocatorVaultTest is DssTest { event Wipe(address indexed sender, uint256 wad); function _divup(uint256 x, uint256 y) internal pure returns (uint256 z) { + // Note: _divup(0,0) will return 0 differing from natural solidity division unchecked { z = x != 0 ? ((x - 1) / y) + 1 : 0; } diff --git a/test/funnels/DepositorUniV3.t.sol b/test/funnels/DepositorUniV3.t.sol index ad0c52e3..72d6c8bc 100644 --- a/test/funnels/DepositorUniV3.t.sol +++ b/test/funnels/DepositorUniV3.t.sol @@ -29,9 +29,9 @@ interface SwapRouterLike { contract DepositorUniV3Test is DssTest { event SetLimits(address indexed gem0, address indexed gem1, uint24 indexed fee, uint96 cap0, uint96 cap1, uint32 era); - event Deposit(address indexed sender, address indexed gem0, address indexed gem1, uint128 liquidity, uint256 amt0, uint256 amt1); - event Withdraw(address indexed sender, address indexed gem0, address indexed gem1, uint128 liquidity, uint256 amt0, uint256 amt1, uint256 fees0, uint256 fees1); - event Collect(address indexed sender, address indexed gem0, address indexed gem1, uint256 fees0, uint256 fees1); + event Deposit(address indexed sender, address indexed gem0, address indexed gem1, uint24 fee, uint128 liquidity, uint256 amt0, uint256 amt1); + event Withdraw(address indexed sender, address indexed gem0, address indexed gem1, uint24 fee, uint128 liquidity, uint256 amt0, uint256 amt1, uint256 fees0, uint256 fees1); + event Collect(address indexed sender, address indexed gem0, address indexed gem1, uint24 fee, uint256 fees0, uint256 fees1); AllocatorRoles public roles; AllocatorBuffer public buffer; @@ -177,7 +177,7 @@ contract DepositorUniV3Test is DssTest { vm.revertTo(snapshot); vm.expectEmit(true, true, true, true); - emit Deposit(FACILITATOR, DAI, USDC, liq, amt0, amt1); + emit Deposit(FACILITATOR, DAI, USDC, uint24(100), liq, amt0, amt1); vm.prank(FACILITATOR); depositor.deposit(dp); assertLt(GemLike(DAI).balanceOf(address(buffer)), prevDAI); @@ -328,7 +328,7 @@ contract DepositorUniV3Test is DssTest { vm.revertTo(snapshot); vm.expectEmit(true, true, true, true); - emit Collect(FACILITATOR, DAI, USDC, expectedFees0, expectedFees1); + emit Collect(FACILITATOR, DAI, USDC, uint24(100), expectedFees0, expectedFees1); vm.prank(FACILITATOR); (uint256 fees0, uint256 fees1) = depositor.collect(cp); assertTrue(fees0 > 0 || fees1 > 0); @@ -354,7 +354,7 @@ contract DepositorUniV3Test is DssTest { vm.revertTo(snapshot); vm.expectEmit(true, true, true, true); - emit Withdraw(FACILITATOR, DAI, USDC, liquidity, withdrawn0, withdrawn1, fees0, fees1); + emit Withdraw(FACILITATOR, DAI, USDC, uint24(100), liquidity, withdrawn0, withdrawn1, fees0, fees1); vm.prank(FACILITATOR); depositor.withdraw(dp, false); assertGe(withdrawn0 + 1, deposited0); @@ -423,7 +423,7 @@ contract DepositorUniV3Test is DssTest { vm.revertTo(snapshot); vm.expectEmit(true, true, true, true); - emit Withdraw(FACILITATOR, DAI, USDC, liquidity, withdrawn0, withdrawn1, fees0, fees1); + emit Withdraw(FACILITATOR, DAI, USDC, uint24(100), liquidity, withdrawn0, withdrawn1, fees0, fees1); vm.prank(FACILITATOR); depositor.withdraw(dp, true); assertTrue(fees0 > 0 || fees1 > 0); @@ -466,7 +466,7 @@ contract DepositorUniV3Test is DssTest { vm.revertTo(snapshot); vm.expectEmit(true, true, true, true); - emit Withdraw(FACILITATOR, DAI, USDC, liquidity, withdrawn0, withdrawn1, fees0, fees1); + emit Withdraw(FACILITATOR, DAI, USDC, uint24(100), liquidity, withdrawn0, withdrawn1, fees0, fees1); vm.prank(FACILITATOR); depositor.withdraw(dp, true); assertEq(liquidity, 0); @@ -496,7 +496,7 @@ contract DepositorUniV3Test is DssTest { vm.revertTo(snapshot); vm.expectEmit(true, true, true, true); - emit Withdraw(FACILITATOR, DAI, USDC, liquidity, withdrawn0, withdrawn1, fees0, fees1); + emit Withdraw(FACILITATOR, DAI, USDC, uint24(100), liquidity, withdrawn0, withdrawn1, fees0, fees1); vm.prank(FACILITATOR); depositor.withdraw(dp, false); // due to liquidity from amounts calculation there is rounding dust diff --git a/test/funnels/automation/ConduitMover.t.sol b/test/funnels/automation/ConduitMover.t.sol index b95707a2..f413d2cf 100644 --- a/test/funnels/automation/ConduitMover.t.sol +++ b/test/funnels/automation/ConduitMover.t.sol @@ -197,4 +197,12 @@ contract ConduitMoverTest is DssTest { vm.expectRevert("ConduitMover/exceeds-num"); vm.prank(KEEPER); mover.move(conduit1, conduit2, address(0x123)); } + + function testMoveLotWithdrawFail() public { + vm.prank(FACILITATOR); mover.setConfig(conduit1, buffer, USDC, 10, 1 hours, uint128(3_100 * 10**6)); + assertEq(GemLike(USDC).balanceOf(conduit1), 3_000 * 10**6); + + vm.expectRevert("ConduitMover/lot-withdraw-failed"); + vm.prank(KEEPER); mover.move(conduit1, buffer, USDC); + } } diff --git a/test/funnels/callees/SwapperCalleeUniV3.t.sol b/test/funnels/callees/SwapperCalleeUniV3.t.sol index 16a4891d..b8e4730e 100644 --- a/test/funnels/callees/SwapperCalleeUniV3.t.sol +++ b/test/funnels/callees/SwapperCalleeUniV3.t.sol @@ -26,6 +26,7 @@ contract SwapperCalleeUniV3Test is DssTest { deal(DAI, address(this), 1_000_000 * WAD, true); deal(USDC, address(this), 1_000_000 * 10**6, true); + deal(USDT, address(this), 1_000_000 * 10**6, true); } function testConstructor() public { @@ -48,6 +49,12 @@ contract SwapperCalleeUniV3Test is DssTest { assertEq(GemLike(to).balanceOf(address(callee)), 0); } + function testSwapUsdt() public { + bytes memory USDT_DAI_PATH = abi.encodePacked(USDT, uint24(100), DAI); + checkStableSwap(USDT, DAI, USDT_DAI_PATH); + checkStableSwap(USDT, DAI, USDT_DAI_PATH); // swapping a 2nd time to verify that USDT allowance has been cleared after the 1st swap + } + function testSwapShortPath() public { bytes memory DAI_USDC_PATH = abi.encodePacked(DAI, uint24(100), USDC); checkStableSwap(DAI, USDC, DAI_USDC_PATH); @@ -57,4 +64,11 @@ contract SwapperCalleeUniV3Test is DssTest { bytes memory USDC_USDT_DAI_PATH = abi.encodePacked(USDC, uint24(100), USDT, uint24(100), DAI); checkStableSwap(USDC, DAI, USDC_USDT_DAI_PATH); } + + function testSwapInvalidPath() public { + bytes memory USDT_DAI_PATH = abi.encodePacked(USDT, uint24(100), DAI); + + vm.expectRevert("SwapperCalleeUniV3/invalid-path"); + this.checkStableSwap(USDC, DAI, USDT_DAI_PATH); // src != path[0] + } } From 7268b572fc82d59d0bc2c552a8e8612e42c41e67 Mon Sep 17 00:00:00 2001 From: telome <130504305+telome@users.noreply.github.com> Date: Wed, 8 Nov 2023 12:08:49 +0000 Subject: [PATCH 60/74] Add SwapperCalleePsm (#66) * Add SwapperCalleePsm * Remove USDT swap tests * Add tests for USDT PSM * Add missing empty line * Rename keg -> pocket * Remove separate Pocket contract for PsmMock * Update src/funnels/callees/SwapperCalleePsm.sol Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> * Update test/mocks/PsmMock.sol Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> --------- Co-authored-by: telome <> Co-authored-by: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> --- src/funnels/callees/SwapperCalleePsm.sol | 71 ++++++++++++++++ test/funnels/Swapper.t.sol | 42 ++++++++++ test/funnels/callees/SwapperCalleePsm.t.sol | 92 +++++++++++++++++++++ test/mocks/PsmMock.sol | 68 +++++++++++++++ 4 files changed, 273 insertions(+) create mode 100644 src/funnels/callees/SwapperCalleePsm.sol create mode 100644 test/funnels/callees/SwapperCalleePsm.t.sol create mode 100644 test/mocks/PsmMock.sol diff --git a/src/funnels/callees/SwapperCalleePsm.sol b/src/funnels/callees/SwapperCalleePsm.sol new file mode 100644 index 00000000..a6956fc2 --- /dev/null +++ b/src/funnels/callees/SwapperCalleePsm.sol @@ -0,0 +1,71 @@ +// SPDX-FileCopyrightText: © 2023 Dai Foundation +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +pragma solidity ^0.8.16; + +interface GemLike { + function approve(address, uint256) external; + function decimals() external view returns (uint8); +} + +interface PsmLike { + function sellGemNoFee(address, uint256) external returns (uint256); + function buyGemNoFee(address, uint256) external returns (uint256); + function dai() external returns (address); + function gem() external returns (address); +} + +contract SwapperCalleePsm { + mapping (address => uint256) public wards; + + address public immutable psm; + address public immutable gem; + uint256 public immutable to18ConversionFactor; + + event Rely(address indexed usr); + event Deny(address indexed usr); + + constructor(address _psm) { + psm = _psm; + gem = PsmLike(psm).gem(); + GemLike(PsmLike(psm).dai()).approve(address(psm), type(uint256).max); + GemLike(gem).approve(address(psm), type(uint256).max); + to18ConversionFactor = 10 ** (18 - GemLike(gem).decimals()); + + wards[msg.sender] = 1; + emit Rely(msg.sender); + } + + modifier auth() { + require(wards[msg.sender] == 1, "SwapperCalleePsm/not-authorized"); + _; + } + + function rely(address usr) external auth { + wards[usr] = 1; + emit Rely(usr); + } + + function deny(address usr) external auth { + wards[usr] = 0; + emit Deny(usr); + } + + function swapCallback(address src, address /* dst */, uint256 amt, uint256 /* minOut */, address to, bytes calldata /* data */) external auth { + if (src == gem) PsmLike(psm).sellGemNoFee(to, amt); + else PsmLike(psm).buyGemNoFee (to, amt / to18ConversionFactor); + } +} diff --git a/test/funnels/Swapper.t.sol b/test/funnels/Swapper.t.sol index 20aac03c..22a0c487 100644 --- a/test/funnels/Swapper.t.sol +++ b/test/funnels/Swapper.t.sol @@ -5,8 +5,10 @@ pragma solidity ^0.8.16; import "dss-test/DssTest.sol"; import { Swapper } from "src/funnels/Swapper.sol"; import { SwapperCalleeUniV3 } from "src/funnels/callees/SwapperCalleeUniV3.sol"; +import { SwapperCalleePsm } from "src/funnels/callees/SwapperCalleePsm.sol"; import { AllocatorRoles } from "src/AllocatorRoles.sol"; import { AllocatorBuffer } from "src/AllocatorBuffer.sol"; +import { PsmMock } from "test/mocks/PsmMock.sol"; interface GemLike { function balanceOf(address) external view returns (uint256); @@ -172,6 +174,46 @@ contract SwapperTest is DssTest { assertEq(end, initialTime + 7200); } + function testSwapPsmCallee() public { + PsmMock psm = new PsmMock(DAI, USDC); + SwapperCalleePsm swapperCalleePsm = new SwapperCalleePsm(address(psm)); + psm.rely(address(swapperCalleePsm)); + swapperCalleePsm.rely(address(swapper)); + deal(DAI, address(psm), 1_000 * WAD, true); + + uint256 prevSrc = GemLike(USDC).balanceOf(address(buffer)); + uint256 prevDst = GemLike(DAI).balanceOf(address(buffer)); + + vm.expectEmit(true, true, true, true); + emit Swap(FACILITATOR, USDC, DAI, 1_000 * 10**6, 1_000 * WAD); + vm.prank(FACILITATOR); uint256 out = swapper.swap(USDC, DAI, 1_000 * 10**6, 1_000 * WAD, address(swapperCalleePsm), ""); + + assertEq(out, 1_000 * WAD); + assertEq(GemLike(USDC).balanceOf(address(buffer)), prevSrc - 1_000 * 10**6); + assertEq(GemLike(DAI).balanceOf(address(buffer)), prevDst + 1_000 * WAD); + assertEq(GemLike(DAI).balanceOf(address(swapper)), 0); + assertEq(GemLike(USDC).balanceOf(address(swapper)), 0); + assertEq(GemLike(DAI).balanceOf(address(swapperCalleePsm)), 0); + assertEq(GemLike(USDC).balanceOf(address(swapperCalleePsm)), 0); + + vm.warp(uint32(block.timestamp) + 3600); + + prevSrc = GemLike(DAI).balanceOf(address(buffer)); + prevDst = GemLike(USDC).balanceOf(address(buffer)); + + vm.expectEmit(true, true, true, false); + emit Swap(FACILITATOR, DAI, USDC, 1_000 * WAD, 1_000 * 10**6); + vm.prank(FACILITATOR); out = swapper.swap(DAI, USDC, 1_000 * WAD, 1_000 * 10**6, address(swapperCalleePsm), ""); + + assertEq(out, 1_000 * 10**6); + assertEq(GemLike(DAI).balanceOf(address(buffer)), prevSrc - 1_000 * WAD); + assertEq(GemLike(USDC).balanceOf(address(buffer)), prevDst + 1_000 * 10**6); + assertEq(GemLike(DAI).balanceOf(address(swapper)), 0); + assertEq(GemLike(USDC).balanceOf(address(swapper)), 0); + assertEq(GemLike(DAI).balanceOf(address(swapperCalleePsm)), 0); + assertEq(GemLike(USDC).balanceOf(address(swapperCalleePsm)), 0); + } + function testSwapAllAferEra() public { vm.prank(FACILITATOR); swapper.swap(USDC, DAI, 10_000 * 10**6, 9900 * WAD, address(uniV3Callee), USDC_DAI_PATH); (, uint64 era,,) = swapper.limits(USDC, DAI); diff --git a/test/funnels/callees/SwapperCalleePsm.t.sol b/test/funnels/callees/SwapperCalleePsm.t.sol new file mode 100644 index 00000000..f96bcc3c --- /dev/null +++ b/test/funnels/callees/SwapperCalleePsm.t.sol @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +pragma solidity ^0.8.16; + +import "dss-test/DssTest.sol"; +import { SwapperCalleePsm } from "src/funnels/callees/SwapperCalleePsm.sol"; +import { PsmMock } from "test/mocks/PsmMock.sol"; + +interface GemLike { + function balanceOf(address) external view returns (uint256); + function transfer(address, uint256) external; + function decimals() external view returns (uint8); +} + +contract SwapperCalleePsmTest is DssTest { + + PsmMock psm; + PsmMock psmUSDT; + SwapperCalleePsm callee; + SwapperCalleePsm calleeUSDT; + + address constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F; + address constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + address constant USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7; + + function setUp() public { + vm.createSelectFork(vm.envString("ETH_RPC_URL")); + + psm = new PsmMock(DAI, USDC); + callee = new SwapperCalleePsm(address(psm)); + psm.rely(address(callee)); + callee.rely(address(this)); + + psmUSDT = new PsmMock(DAI, USDT); + calleeUSDT = new SwapperCalleePsm(address(psmUSDT)); + psmUSDT.rely(address(calleeUSDT)); + calleeUSDT.rely(address(this)); + + deal(DAI, address(this), 1_000_000 * WAD, true); + deal(DAI, address(psm), 1_000_000 * WAD, true); + deal(DAI, address(psmUSDT), 1_000_000 * WAD, true); + deal(USDC, address(this), 1_000_000 * 10**6, true); + deal(USDC, psm.pocket(), 1_000_000 * 10**6, true); + deal(USDT, address(this), 1_000_000 * 10**6, true); + deal(USDT, psmUSDT.pocket(), 1_000_000 * 10**6, true); + } + + function testConstructor() public { + SwapperCalleePsm c = new SwapperCalleePsm(address(psm)); + assertEq(c.psm(), address(psm)); + assertEq(c.gem(), USDC); + assertEq(c.to18ConversionFactor(), 10**12); + assertEq(c.wards(address(this)), 1); + } + + function testAuth() public { + checkAuth(address(callee), "SwapperCalleePsm"); + } + + function testModifiers() public { + bytes4[] memory authedMethods = new bytes4[](1); + authedMethods[0] = callee.swapCallback.selector; + + vm.startPrank(address(0xBEEF)); + checkModifier(address(callee), "SwapperCalleePsm/not-authorized", authedMethods); + vm.stopPrank(); + } + + function checkPsmSwap(SwapperCalleePsm callee_, address from, address to) public { + uint256 prevFrom = GemLike(from).balanceOf(address(this)); + uint256 prevTo = GemLike(to).balanceOf(address(this)); + uint8 fromDecimals = GemLike(from).decimals(); + uint8 toDecimals = GemLike(to).decimals(); + + GemLike(from).transfer(address(callee_), 10_000 * 10**fromDecimals); + callee_.swapCallback(from, to, 10_000 * 10**fromDecimals, 0, address(this), ""); + + assertEq(GemLike(from).balanceOf(address(this)), prevFrom - 10_000 * 10**fromDecimals); + assertEq(GemLike(to ).balanceOf(address(this)), prevTo + 10_000 * 10**toDecimals ); + assertEq(GemLike(from).balanceOf(address(callee_)), 0); + assertEq(GemLike(to ).balanceOf(address(callee_)), 0); + } + + function testDaiToGemSwap() public { + checkPsmSwap(callee, DAI, USDC); + checkPsmSwap(calleeUSDT, DAI, USDT); + } + + function testGemToDaiSwap() public { + checkPsmSwap(callee, USDC, DAI); + checkPsmSwap(calleeUSDT, DAI, USDT); + } +} diff --git a/test/mocks/PsmMock.sol b/test/mocks/PsmMock.sol new file mode 100644 index 00000000..bf3401be --- /dev/null +++ b/test/mocks/PsmMock.sol @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +pragma solidity ^0.8.16; + +interface GemLike { + function approve(address, uint256) external; + function transfer(address, uint256) external; + function transferFrom(address, address, uint256) external; + function decimals() external view returns (uint8); +} + +contract PsmMock { + mapping(address => uint256) public wards; + + address public immutable dai; + address public immutable gem; + uint256 public immutable to18ConversionFactor; + + event Rely(address indexed usr); + event Deny(address indexed usr); + event SellGem(address indexed owner, uint256 value, uint256 fee); + event BuyGem(address indexed owner, uint256 value, uint256 fee); + + modifier auth() { + require(wards[msg.sender] == 1, "PsmMock/not-authorized"); + _; + } + + constructor(address dai_, address gem_) { + dai = dai_; + gem = gem_; + to18ConversionFactor = 10**(18 - GemLike(gem_).decimals()); + + wards[msg.sender] = 1; + emit Rely(msg.sender); + } + + function rely(address usr) external auth { + wards[usr] = 1; + emit Rely(usr); + } + + function deny(address usr) external auth { + wards[usr] = 0; + emit Deny(usr); + } + + function pocket() external view returns (address) { + return address(this); + } + + function sellGemNoFee(address usr, uint256 gemAmt) external auth returns (uint256 daiOutWad) { + daiOutWad = gemAmt * to18ConversionFactor; + + GemLike(gem).transferFrom(msg.sender, address(this), gemAmt); + GemLike(dai).transfer(usr, daiOutWad); + + emit SellGem(usr, gemAmt, 0); + } + + function buyGemNoFee(address usr, uint256 gemAmt) external auth returns (uint256 daiInWad) { + daiInWad = gemAmt * to18ConversionFactor; + + GemLike(dai).transferFrom(msg.sender, address(this), daiInWad); + GemLike(gem).transfer(usr, gemAmt); + + emit BuyGem(usr, gemAmt, 0); + } +} From fdf12ec9a360a6e4ef05cd077b31a9fe56f52d73 Mon Sep 17 00:00:00 2001 From: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> Date: Wed, 15 Nov 2023 12:52:49 -0300 Subject: [PATCH 61/74] AllocatorOracle: 1 WAD price (#69) * AllocatorOracle: 1 WAD price * Add extra check * Clear way to show number * Add clarification in README * Change constant name * Fix aligment * Add comment * Update test/AllocatorOracle.t.sol Co-authored-by: telome <130504305+telome@users.noreply.github.com> --------- Co-authored-by: telome <130504305+telome@users.noreply.github.com> --- README.md | 4 +- deploy/AllocatorInit.sol | 4 +- src/AllocatorOracle.sol | 8 +-- test/AllocatorOracle.t.sol | 10 +-- test/integration/Deployment.t.sol | 102 ++++++++++++++++++------------ 5 files changed, 74 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index f60d6100..6437d630 100644 --- a/README.md +++ b/README.md @@ -49,9 +49,7 @@ The allocation system includes several actor types: Each AllocatorDAO has a unique `ilk` (collateral type) with one VAT vault set up for it. -- Each `ilk` supports a 1 trillion NST max debt ceiling. -- The collateral amount of each vault is 1 million WAD (10^6 * 10^18 indivisible units of collateral). -- All the `ilk`s have a shared simple [oracle](https://github.com/makerdao/dss-allocator/blob/dev/src/AllocatorOracle.sol) that just returns a fixed price of 1 Million (which multiplied by the collateral amount makes sure the max debt ceiling can indeed be reached). +- All the `ilk`s have a shared simple [oracle](https://github.com/makerdao/dss-allocator/blob/dev/src/AllocatorOracle.sol) that just returns a fixed price of 1:1 (which multiplied by a huge amount of collateral makes sure the max debt ceiling can indeed be reached). In case it is necessary a governance spell could also increase it further. ### AllocatorVault diff --git a/deploy/AllocatorInit.sol b/deploy/AllocatorInit.sol index 27ad7d41..e674535b 100644 --- a/deploy/AllocatorInit.sol +++ b/deploy/AllocatorInit.sol @@ -216,8 +216,8 @@ library AllocatorInit { RegistryLike(sharedInstance.registry).file(ilk, "buffer", ilkInstance.buffer); // Initiate the allocator vault - dss.vat.slip(ilk, ilkInstance.vault, int256(1_000_000 * WAD)); - dss.vat.grab(ilk, ilkInstance.vault, ilkInstance.vault, address(0), int256(1_000_000 * WAD), 0); + dss.vat.slip(ilk, ilkInstance.vault, int256(10**12 * WAD)); + dss.vat.grab(ilk, ilkInstance.vault, ilkInstance.vault, address(0), int256(10**12 * WAD), 0); VaultLike(ilkInstance.vault).file("jug", address(dss.jug)); diff --git a/src/AllocatorOracle.sol b/src/AllocatorOracle.sol index eedaf892..ba7171ad 100644 --- a/src/AllocatorOracle.sol +++ b/src/AllocatorOracle.sol @@ -17,9 +17,7 @@ pragma solidity ^0.8.16; contract AllocatorOracle { - // 1M price together with 1M supply, allows up to 1T DAI minting - // and it is a good balance for collateral redemption in Global Shutdown - uint256 internal constant PRICE = 10**6 * 10**18; // 1M in WAD + uint256 internal constant WAD = 10**18; // For 1:1 price /** @notice Return value and status of the oracle @@ -27,7 +25,7 @@ contract AllocatorOracle { @return ok always true */ function peek() public pure returns (bytes32 val, bool ok) { - val = bytes32(PRICE); + val = bytes32(WAD); ok = true; } @@ -36,6 +34,6 @@ contract AllocatorOracle { @return val PRICE constant */ function read() external pure returns (bytes32 val) { - val = bytes32(PRICE); + val = bytes32(WAD); } } diff --git a/test/AllocatorOracle.t.sol b/test/AllocatorOracle.t.sol index 966c61b8..50116a9a 100644 --- a/test/AllocatorOracle.t.sol +++ b/test/AllocatorOracle.t.sol @@ -14,15 +14,15 @@ contract AllocatorOracleTest is DssTest { function testOracle() public { (bytes32 val, bool ok) = oracle.peek(); - assertEq(val, bytes32(uint256(10**6 * 10**18))); + assertEq(val, bytes32(uint256(10**18))); assertTrue(ok); - assertEq(oracle.read(), bytes32(uint256(10**6 * 10**18))); + assertEq(oracle.read(), bytes32(uint256(10**18))); } function testPricing() public { uint256 par = 1 * 10**27; - uint256 price = uint256(oracle.read()); // 1 * 10**6 * 10**18; - uint256 colSupply = 1 * 10**6 * 10**18; + uint256 price = uint256(oracle.read()); // 1 * 10**18; + uint256 colSupply = 1 * 10**12 * 10**18; uint256 colDebt = 1 * 10**6 * 10**45; // Imagine a scenario where the ilk only has 1M debt uint256 totDebt = 50 * 10**9 * 10**45; // Imagine a scenario where the tot Supply of DAI is 50B @@ -52,6 +52,6 @@ contract AllocatorOracleTest is DssTest { console.log("1 = wad * fix / 10^27 => wad = 10^27 / fix"); uint256 amtDaiNeeded = 10**27 / fix; console.log("Amount of wei DAI needed to get 1 wei of gem =", amtDaiNeeded); - assertEq(amtDaiNeeded, 0.00000005 * 10**18); + assertEq(amtDaiNeeded, 50_000); } } diff --git a/test/integration/Deployment.t.sol b/test/integration/Deployment.t.sol index 278b796f..30d60e24 100644 --- a/test/integration/Deployment.t.sol +++ b/test/integration/Deployment.t.sol @@ -70,17 +70,17 @@ interface AutoLineLike { contract DeploymentTest is DssTest { + using stdStorage for StdStorage; + // existing contracts address constant LOG = 0xdA0Ab1e0017DEbCd72Be8599041a2aa3bA7e740F; address constant UNIV3_FACTORY = 0x1F98431c8aD98523631AE4a59f267346ea31F984; address constant UNIV3_ROUTER = 0xE592427A0AEce92De3Edee1F18E0157C05861564; // existing contracts to be fetched from chainlog - address VAT; - address JUG; + DssInstance dss; address ILK_REGISTRY; address PAUSE_PROXY; - address DAI; address USDC; // actors @@ -118,19 +118,17 @@ contract DeploymentTest is DssTest { function setUp() public { vm.createSelectFork(vm.envString("ETH_RPC_URL")); - VAT = ChainlogLike(LOG).getAddress("MCD_VAT"); - JUG = ChainlogLike(LOG).getAddress("MCD_JUG"); + dss = MCD.loadFromChainlog(LOG); PAUSE_PROXY = ChainlogLike(LOG).getAddress("MCD_PAUSE_PROXY"); ILK_REGISTRY = ChainlogLike(LOG).getAddress("ILK_REGISTRY"); USDC = ChainlogLike(LOG).getAddress("USDC"); - DAI = ChainlogLike(LOG).getAddress("MCD_DAI"); nst = address(new GemMock(0)); - nstJoin = address(new NstJoinMock(VatMock(VAT), GemMock(nst))); + nstJoin = address(new NstJoinMock(VatMock(address(dss.vat)), GemMock(nst))); uniV3Callee = address(new SwapperCalleeUniV3(UNIV3_ROUTER)); - usdcDaiPath = abi.encodePacked(USDC, uint24(100), DAI); - daiUsdcPath = abi.encodePacked(DAI, uint24(100), USDC); + usdcDaiPath = abi.encodePacked(USDC, uint24(100), address(dss.dai)); + daiUsdcPath = abi.encodePacked(address(dss.dai), uint24(100), USDC); sharedInst = AllocatorDeploy.deployShared(address(this), PAUSE_PROXY); ilkInst = AllocatorDeploy.deployIlk({ @@ -148,16 +146,14 @@ contract DeploymentTest is DssTest { } function emulateSpell() internal { - DssInstance memory dss = MCD.loadFromChainlog(LOG); - vm.startPrank(PAUSE_PROXY); AllocatorInit.initShared(dss, sharedInst); address[] memory swapTokens = new address[](1); - swapTokens[0] = DAI; + swapTokens[0] = address(dss.dai); address[] memory depositTokens = new address[](2); - depositTokens[0] = DAI; + depositTokens[0] = address(dss.dai); depositTokens[1] = USDC; address[] memory facilitators = new address[](2); @@ -220,8 +216,6 @@ contract DeploymentTest is DssTest { } function testInitIlkValues() public { - DssInstance memory dss = MCD.loadFromChainlog(LOG); - uint256 previousLine = dss.vat.Line(); uint256 previousIlkRegistryCount = IlkRegistryLike(ILK_REGISTRY).count(); @@ -229,7 +223,7 @@ contract DeploymentTest is DssTest { (, uint256 rate, uint256 spot, uint256 line,) = dss.vat.ilks(ILK); assertEq(rate, RAY); - assertEq(spot, 10**6 * 10**18 * RAY * 10**9 / dss.spotter.par()); + assertEq(spot, 10**18 * RAY * 10**9 / dss.spotter.par()); assertEq(line, 10_000_000 * RAD); assertEq(dss.vat.Line(), previousLine + 10_000_000 * RAD); @@ -253,16 +247,16 @@ contract DeploymentTest is DssTest { assertEq(dss.vat.gem(ILK, ilkInst.vault), 0); (uint256 ink, uint256 art) = dss.vat.urns(ILK, ilkInst.vault); - assertEq(ink, 1_000_000 * WAD); + assertEq(ink, 1_000_000_000_000 * WAD); assertEq(art, 0); assertEq(AllocatorRegistry(sharedInst.registry).buffers(ILK), ilkInst.buffer); assertEq(address(AllocatorVault(ilkInst.vault).jug()), address(dss.jug)); - assertEq(GemLike(nst).allowance(ilkInst.buffer, ilkInst.vault), type(uint256).max); - assertEq(GemLike(DAI).allowance(ilkInst.buffer, ilkInst.swapper), type(uint256).max); - assertEq(GemLike(DAI).allowance(ilkInst.buffer, ilkInst.depositorUniV3), type(uint256).max); - assertEq(GemLike(USDC).allowance(ilkInst.buffer, ilkInst.depositorUniV3), type(uint256).max); + assertEq(GemLike(nst).allowance(ilkInst.buffer, ilkInst.vault), type(uint256).max); + assertEq(GemLike(address(dss.dai)).allowance(ilkInst.buffer, ilkInst.swapper), type(uint256).max); + assertEq(GemLike(address(dss.dai)).allowance(ilkInst.buffer, ilkInst.depositorUniV3), type(uint256).max); + assertEq(GemLike(USDC).allowance(ilkInst.buffer, ilkInst.depositorUniV3), type(uint256).max); assertEq(AllocatorRoles(sharedInst.roles).ilkAdmins(ILK), allocatorProxy); @@ -345,31 +339,31 @@ contract DeploymentTest is DssTest { function testSwapFromFacilitator() public { emulateSpell(); - deal(DAI, ilkInst.buffer, 1_000 * WAD); + deal(address(dss.dai), ilkInst.buffer, 1_000 * WAD); - vm.prank(allocatorProxy); Swapper(ilkInst.swapper).setLimits(DAI, USDC, uint96(1_000 * WAD), 1 hours); - vm.prank(facilitator1); Swapper(ilkInst.swapper).swap(DAI, USDC, 1_000 * WAD, 990 * 10**6 , uniV3Callee, daiUsdcPath); + vm.prank(allocatorProxy); Swapper(ilkInst.swapper).setLimits(address(dss.dai), USDC, uint96(1_000 * WAD), 1 hours); + vm.prank(facilitator1); Swapper(ilkInst.swapper).swap(address(dss.dai), USDC, 1_000 * WAD, 990 * 10**6 , uniV3Callee, daiUsdcPath); } function testSwapFromKeeper() public { emulateSpell(); - deal(DAI, ilkInst.buffer, 1_000 * WAD); + deal(address(dss.dai), ilkInst.buffer, 1_000 * WAD); - vm.prank(allocatorProxy); Swapper(ilkInst.swapper).setLimits(DAI, USDC, uint96(1_000 * WAD), 1 hours); - vm.prank(facilitator1); StableSwapper(ilkInst.stableSwapper).setConfig(DAI, USDC, 1, 1 hours, uint96(1_000 * WAD), uint96(990 * 10**6)); - vm.prank(stableSwapperKeeper1); StableSwapper(ilkInst.stableSwapper).swap(DAI, USDC, 990 * 10**6, uniV3Callee, daiUsdcPath); + vm.prank(allocatorProxy); Swapper(ilkInst.swapper).setLimits(address(dss.dai), USDC, uint96(1_000 * WAD), 1 hours); + vm.prank(facilitator1); StableSwapper(ilkInst.stableSwapper).setConfig(address(dss.dai), USDC, 1, 1 hours, uint96(1_000 * WAD), uint96(990 * 10**6)); + vm.prank(stableSwapperKeeper1); StableSwapper(ilkInst.stableSwapper).swap(address(dss.dai), USDC, 990 * 10**6, uniV3Callee, daiUsdcPath); } function testDepositWithdrawCollectFromFacilitator() public { emulateSpell(); - deal(DAI, ilkInst.buffer, 1_000 * WAD); + deal(address(dss.dai), ilkInst.buffer, 1_000 * WAD); deal(USDC, ilkInst.buffer, 1_000 * 10**6); - vm.prank(allocatorProxy); DepositorUniV3(ilkInst.depositorUniV3).setLimits(DAI, USDC, uint24(100), uint96(2_000 * WAD), uint96(2_000 * 10**6), 1 hours); + vm.prank(allocatorProxy); DepositorUniV3(ilkInst.depositorUniV3).setLimits(address(dss.dai), USDC, uint24(100), uint96(2_000 * WAD), uint96(2_000 * 10**6), 1 hours); DepositorUniV3.LiquidityParams memory dp = DepositorUniV3.LiquidityParams({ - gem0 : DAI, + gem0 : address(dss.dai), gem1 : USDC, fee : uint24(100), tickLower : REF_TICK - 100, @@ -385,7 +379,7 @@ contract DeploymentTest is DssTest { vm.prank(facilitator1); DepositorUniV3(ilkInst.depositorUniV3).withdraw(dp, false); DepositorUniV3.CollectParams memory cp = DepositorUniV3.CollectParams({ - gem0 : DAI, + gem0 : address(dss.dai), gem1 : USDC, fee : uint24(100), tickLower: REF_TICK - 100, @@ -399,19 +393,19 @@ contract DeploymentTest is DssTest { function testDepositWithdrawCollectFromKeeper() public { emulateSpell(); - deal(DAI, ilkInst.buffer, 1_000 * WAD); + deal(address(dss.dai), ilkInst.buffer, 1_000 * WAD); deal(USDC, ilkInst.buffer, 1_000 * 10**6); - vm.prank(allocatorProxy); DepositorUniV3(ilkInst.depositorUniV3).setLimits(DAI, USDC, uint24(100), uint96(2_000 * WAD), uint96(2_000 * 10**6), 1 hours); + vm.prank(allocatorProxy); DepositorUniV3(ilkInst.depositorUniV3).setLimits(address(dss.dai), USDC, uint24(100), uint96(2_000 * WAD), uint96(2_000 * 10**6), 1 hours); - vm.prank(facilitator1); StableDepositorUniV3(ilkInst.stableDepositorUniV3).setConfig(DAI, USDC, uint24(100), REF_TICK - 100, REF_TICK + 100, 1, 1 hours, uint96(1_000 * WAD), uint96(1000 * 10**6), 0, 0); - vm.prank(stableDepositorUniV3Keeper1); StableDepositorUniV3(ilkInst.stableDepositorUniV3).deposit(DAI, USDC, uint24(100), REF_TICK - 100, REF_TICK + 100, 0, 0); + vm.prank(facilitator1); StableDepositorUniV3(ilkInst.stableDepositorUniV3).setConfig(address(dss.dai), USDC, uint24(100), REF_TICK - 100, REF_TICK + 100, 1, 1 hours, uint96(1_000 * WAD), uint96(1000 * 10**6), 0, 0); + vm.prank(stableDepositorUniV3Keeper1); StableDepositorUniV3(ilkInst.stableDepositorUniV3).deposit(address(dss.dai), USDC, uint24(100), REF_TICK - 100, REF_TICK + 100, 0, 0); - vm.prank(facilitator1); StableDepositorUniV3(ilkInst.stableDepositorUniV3).setConfig(DAI, USDC, uint24(100), REF_TICK - 100, REF_TICK + 100, -1, 1 hours, uint96(1_000 * WAD), uint96(1000 * 10**6), 0, 0); - vm.prank(stableDepositorUniV3Keeper1); StableDepositorUniV3(ilkInst.stableDepositorUniV3).withdraw(DAI, USDC, uint24(100), REF_TICK - 100, REF_TICK + 100, 0, 0); + vm.prank(facilitator1); StableDepositorUniV3(ilkInst.stableDepositorUniV3).setConfig(address(dss.dai), USDC, uint24(100), REF_TICK - 100, REF_TICK + 100, -1, 1 hours, uint96(1_000 * WAD), uint96(1000 * 10**6), 0, 0); + vm.prank(stableDepositorUniV3Keeper1); StableDepositorUniV3(ilkInst.stableDepositorUniV3).withdraw(address(dss.dai), USDC, uint24(100), REF_TICK - 100, REF_TICK + 100, 0, 0); vm.expectRevert(bytes("NP")); // Reverts since no fees to collect and not because the call is unauthorized - vm.prank(stableDepositorUniV3Keeper1); StableDepositorUniV3(ilkInst.stableDepositorUniV3).collect(DAI, USDC, uint24(100), REF_TICK - 100, REF_TICK + 100); + vm.prank(stableDepositorUniV3Keeper1); StableDepositorUniV3(ilkInst.stableDepositorUniV3).collect(address(dss.dai), USDC, uint24(100), REF_TICK - 100, REF_TICK + 100); } function testMoveFromKeeper() public { @@ -427,4 +421,34 @@ contract DeploymentTest is DssTest { vm.prank(facilitator1); ConduitMover(ilkInst.conduitMover).setConfig(conduit1, conduit2, USDC, 1, 1 hours, 3_000 * 10**6); vm.prank(conduitMoverKeeper1); ConduitMover(ilkInst.conduitMover).move(conduit1, conduit2, USDC); } + + function testEndCage() public { + // This test doesn't mean ES is supported, just aims to check that in case of planned governance shutdown is needed, the End could handle well a huge number of ink + emulateSpell(); + + vm.prank(facilitator1); AllocatorVault(ilkInst.vault).draw(1_000_000 * WAD); + + uint256 ink; uint256 art; + (ink, art) = dss.vat.urns(ILK, address(ilkInst.vault)); + assertEq(ink, 1_000_000_000_000 * WAD); + assertEq(art, 1_000_000 * WAD); + assertEq(dss.vat.gem(ILK, address(dss.end)), 0); + + vm.prank(PAUSE_PROXY); dss.end.cage(); + dss.end.cage(ILK); + assertEq(dss.end.tag(ILK), RAY); + dss.end.skim(ILK, address(ilkInst.vault)); + + (ink, art) = dss.vat.urns(ILK, address(ilkInst.vault)); + assertEq(ink, (1_000_000_000_000 - 1_000_000) * WAD); + assertEq(art, 0); + assertEq(dss.vat.gem(ILK, address(dss.end)), 1_000_000 * WAD); + + stdstore.target(address(dss.vat)).sig("dai(address)").with_key(address(dss.vow)).depth(0).checked_write(uint256(0)); + vm.warp(block.timestamp + dss.end.wait()); + dss.end.thaw(); + + dss.end.flow(ILK); + assertEq(dss.end.fix(ILK), 1_000_000 * RAD / (dss.vat.debt() / RAY)); + } } From ca2c5546e6a8fb23f941aa051e7300628f2241f1 Mon Sep 17 00:00:00 2001 From: telome <130504305+telome@users.noreply.github.com> Date: Wed, 15 Nov 2023 18:09:53 +0000 Subject: [PATCH 62/74] Test for Rely events in constructors + minor test re-arranging (#71) * Test for Rely events in constructors + minor test re-arranging * Fix SwapperCalleeUniV3Test --------- Co-authored-by: telome <> --- test/AllocatorBuffer.t.sol | 7 +++++ test/AllocatorRegistry.t.sol | 7 +++++ test/AllocatorRoles.t.sol | 7 +++++ test/AllocatorVault.t.sol | 12 ++++++++ test/funnels/DepositorUniV3.t.sol | 2 ++ test/funnels/Swapper.t.sol | 2 ++ test/funnels/automation/ConduitMover.t.sol | 15 ++++++---- .../automation/StableDepositorUniV3.t.sol | 30 +++++++++---------- test/funnels/automation/StableSwapper.t.sol | 21 +++++++------ test/funnels/callees/SwapperCalleePsm.t.sol | 2 ++ 10 files changed, 74 insertions(+), 31 deletions(-) diff --git a/test/AllocatorBuffer.t.sol b/test/AllocatorBuffer.t.sol index 0476eddd..0c367e89 100644 --- a/test/AllocatorBuffer.t.sol +++ b/test/AllocatorBuffer.t.sol @@ -19,6 +19,13 @@ contract AllocatorBufferTest is DssTest { buffer = new AllocatorBuffer(); } + function testConstructor() public { + vm.expectEmit(true, true, true, true); + emit Rely(address(this)); + AllocatorBuffer b = new AllocatorBuffer(); + assertEq(b.wards(address(this)), 1); + } + function testAuth() public { checkAuth(address(buffer), "AllocatorBuffer"); } diff --git a/test/AllocatorRegistry.t.sol b/test/AllocatorRegistry.t.sol index a24abeca..1d03ed67 100644 --- a/test/AllocatorRegistry.t.sol +++ b/test/AllocatorRegistry.t.sol @@ -14,6 +14,13 @@ contract AllocatorRegistryTest is DssTest { registry = new AllocatorRegistry(); } + function testConstructor() public { + vm.expectEmit(true, true, true, true); + emit Rely(address(this)); + AllocatorRegistry r = new AllocatorRegistry(); + assertEq(r.wards(address(this)), 1); + } + function testAuth() public { checkAuth(address(registry), "AllocatorRegistry"); } diff --git a/test/AllocatorRoles.t.sol b/test/AllocatorRoles.t.sol index 0aea0380..34f862b1 100644 --- a/test/AllocatorRoles.t.sol +++ b/test/AllocatorRoles.t.sol @@ -21,6 +21,13 @@ contract AllocatorRolesTest is DssTest { authed = new AuthedMock(address(roles), ilk); } + function testConstructor() public { + vm.expectEmit(true, true, true, true); + emit Rely(address(this)); + AllocatorRoles r = new AllocatorRoles(); + assertEq(r.wards(address(this)), 1); + } + function testAuth() public { checkAuth(address(roles), "AllocatorRoles"); } diff --git a/test/AllocatorVault.t.sol b/test/AllocatorVault.t.sol index c13c2afb..4f4cde38 100644 --- a/test/AllocatorVault.t.sol +++ b/test/AllocatorVault.t.sol @@ -52,6 +52,18 @@ contract AllocatorVaultTest is DssTest { stdstore.target(address(vat)).sig("dai(address)").with_key(address(nstJoin)).depth(0).checked_write(100_000 * RAD); } + function testConstructor() public { + vm.expectEmit(true, true, true, true); + emit Rely(address(this)); + address join = address(new NstJoinMock(vat, nst)); + AllocatorVault v = new AllocatorVault(address(0xBEEF), address(0xCCC), "SubDAO 1", join); + assertEq(address(v.roles()), address(0xBEEF)); + assertEq(v.buffer(), address(0xCCC)); + assertEq(v.ilk(), "SubDAO 1"); + assertEq(address(v.nstJoin()), join); + assertEq(v.wards(address(this)), 1); + } + function testAuth() public { checkAuth(address(vault), "AllocatorVault"); } diff --git a/test/funnels/DepositorUniV3.t.sol b/test/funnels/DepositorUniV3.t.sol index 72d6c8bc..7d627b8c 100644 --- a/test/funnels/DepositorUniV3.t.sol +++ b/test/funnels/DepositorUniV3.t.sol @@ -75,6 +75,8 @@ contract DepositorUniV3Test is DssTest { } function testConstructor() public { + vm.expectEmit(true, true, true, true); + emit Rely(address(this)); DepositorUniV3 d = new DepositorUniV3(address(0xBEEF), "SubDAO 1", address(0xAAA), address(0xCCC)); assertEq(address(d.roles()), address(0xBEEF)); assertEq(d.ilk(), "SubDAO 1"); diff --git a/test/funnels/Swapper.t.sol b/test/funnels/Swapper.t.sol index 22a0c487..99855870 100644 --- a/test/funnels/Swapper.t.sol +++ b/test/funnels/Swapper.t.sol @@ -67,6 +67,8 @@ contract SwapperTest is DssTest { } function testConstructor() public { + vm.expectEmit(true, true, true, true); + emit Rely(address(this)); Swapper s = new Swapper(address(0xBEEF), "SubDAO 1", address(0xAAA)); assertEq(address(s.roles()), address(0xBEEF)); assertEq(s.ilk(), "SubDAO 1"); diff --git a/test/funnels/automation/ConduitMover.t.sol b/test/funnels/automation/ConduitMover.t.sol index f413d2cf..b8f0ff6b 100644 --- a/test/funnels/automation/ConduitMover.t.sol +++ b/test/funnels/automation/ConduitMover.t.sol @@ -76,6 +76,8 @@ contract ConduitMoverTest is DssTest { } function testConstructor() public { + vm.expectEmit(true, true, true, true); + emit Rely(address(this)); ConduitMover m = new ConduitMover("xyz", address(0xABC)); assertEq(m.ilk(), "xyz"); assertEq(m.buffer(), address(0xABC)); @@ -95,6 +97,13 @@ contract ConduitMoverTest is DssTest { vm.startPrank(address(0xBEEF)); checkModifier(address(mover), "ConduitMover/not-authorized", authedMethods); vm.stopPrank(); + + bytes4[] memory keeperMethods = new bytes4[](1); + keeperMethods[0] = ConduitMover.move.selector; + + vm.startPrank(address(0xBEEF)); + checkModifier(address(mover), "ConduitMover/non-keeper", keeperMethods); + vm.stopPrank(); } function testKissDiss() public { @@ -187,12 +196,6 @@ contract ConduitMoverTest is DssTest { assertEq(lot, 1_000 * 10**6); } - function testMoveNonKeeper() public { - assertEq(mover.buds(address(this)), 0); - vm.expectRevert("ConduitMover/non-keeper"); - mover.move(conduit1, conduit2, USDC); - } - function testMoveExceedingNum() public { vm.expectRevert("ConduitMover/exceeds-num"); vm.prank(KEEPER); mover.move(conduit1, conduit2, address(0x123)); diff --git a/test/funnels/automation/StableDepositorUniV3.t.sol b/test/funnels/automation/StableDepositorUniV3.t.sol index b06c2fbc..9b61d690 100644 --- a/test/funnels/automation/StableDepositorUniV3.t.sol +++ b/test/funnels/automation/StableDepositorUniV3.t.sol @@ -91,6 +91,8 @@ contract StableDepositorUniV3Test is DssTest { } function testConstructor() public { + vm.expectEmit(true, true, true, true); + emit Rely(address(this)); StableDepositorUniV3 s = new StableDepositorUniV3(address(0xABC)); assertEq(address(s.depositor()), address(0xABC)); assertEq(s.wards(address(this)), 1); @@ -102,13 +104,22 @@ contract StableDepositorUniV3Test is DssTest { function testModifiers() public { bytes4[] memory authedMethods = new bytes4[](3); - authedMethods[0] = stableDepositor.kiss.selector; - authedMethods[1] = stableDepositor.diss.selector; - authedMethods[2] = stableDepositor.setConfig.selector; + authedMethods[0] = StableDepositorUniV3.kiss.selector; + authedMethods[1] = StableDepositorUniV3.diss.selector; + authedMethods[2] = StableDepositorUniV3.setConfig.selector; vm.startPrank(address(0xBEEF)); checkModifier(address(stableDepositor), "StableDepositorUniV3/not-authorized", authedMethods); vm.stopPrank(); + + bytes4[] memory keeperMethods = new bytes4[](3); + keeperMethods[0] = StableDepositorUniV3.deposit.selector; + keeperMethods[1] = StableDepositorUniV3.withdraw.selector; + keeperMethods[2] = StableDepositorUniV3.collect.selector; + + vm.startPrank(address(0xBEEF)); + checkModifier(address(stableDepositor), "StableDepositorUniV3/non-keeper", keeperMethods); + vm.stopPrank(); } function testKissDiss() public { @@ -284,17 +295,4 @@ contract StableDepositorUniV3Test is DssTest { assertEq(GemLike(DAI).balanceOf(address(buffer)), prevDai + fees0); assertEq(GemLike(USDC).balanceOf(address(buffer)), prevUsdc + fees1); } - - function testOperationsNonKeeper() public { - assertEq(stableDepositor.buds(address(this)), 0); - - vm.expectRevert("StableDepositorUniV3/non-keeper"); - stableDepositor.deposit(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, 0, 0); - - vm.expectRevert("StableDepositorUniV3/non-keeper"); - stableDepositor.withdraw(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100, 0, 0); - - vm.expectRevert("StableDepositorUniV3/non-keeper"); - vm.prank(address(0x123)); stableDepositor.collect(DAI, USDC, uint24(100), REF_TICK-100, REF_TICK+100); - } } diff --git a/test/funnels/automation/StableSwapper.t.sol b/test/funnels/automation/StableSwapper.t.sol index 6c6dd4ec..fc6d7eed 100644 --- a/test/funnels/automation/StableSwapper.t.sol +++ b/test/funnels/automation/StableSwapper.t.sol @@ -64,6 +64,8 @@ contract StableSwapperTest is DssTest { } function testConstructor() public { + vm.expectEmit(true, true, true, true); + emit Rely(address(this)); StableSwapper s = new StableSwapper(address(0xABC)); assertEq(address(s.swapper()), address(0xABC)); assertEq(s.wards(address(this)), 1); @@ -75,13 +77,20 @@ contract StableSwapperTest is DssTest { function testModifiers() public { bytes4[] memory authedMethods = new bytes4[](3); - authedMethods[0] = stableSwapper.kiss.selector; - authedMethods[1] = stableSwapper.diss.selector; - authedMethods[2] = stableSwapper.setConfig.selector; + authedMethods[0] = StableSwapper.kiss.selector; + authedMethods[1] = StableSwapper.diss.selector; + authedMethods[2] = StableSwapper.setConfig.selector; vm.startPrank(address(0xBEEF)); checkModifier(address(stableSwapper), "StableSwapper/not-authorized", authedMethods); vm.stopPrank(); + + bytes4[] memory keeperMethods = new bytes4[](1); + keeperMethods[0] = StableSwapper.swap.selector; + + vm.startPrank(address(0xBEEF)); + checkModifier(address(stableSwapper), "StableSwapper/non-keeper", keeperMethods); + vm.stopPrank(); } function testKissDiss() public { @@ -173,12 +182,6 @@ contract StableSwapperTest is DssTest { vm.prank(KEEPER); stableSwapper.swap(USDC, DAI, 0, address(uniV3Callee), USDC_DAI_PATH); } - function testSwapNonKeeper() public { - assertEq(stableSwapper.buds(address(this)), 0); - vm.expectRevert("StableSwapper/non-keeper"); - stableSwapper.swap(USDC, DAI, 9900 * WAD, address(uniV3Callee), USDC_DAI_PATH); - } - function testSwapExceedingNum() public { vm.expectRevert("StableSwapper/exceeds-num"); vm.prank(KEEPER); stableSwapper.swap(USDC, USDC, 0, address(uniV3Callee), USDC_DAI_PATH); diff --git a/test/funnels/callees/SwapperCalleePsm.t.sol b/test/funnels/callees/SwapperCalleePsm.t.sol index f96bcc3c..10e68590 100644 --- a/test/funnels/callees/SwapperCalleePsm.t.sol +++ b/test/funnels/callees/SwapperCalleePsm.t.sol @@ -45,6 +45,8 @@ contract SwapperCalleePsmTest is DssTest { } function testConstructor() public { + vm.expectEmit(true, true, true, true); + emit Rely(address(this)); SwapperCalleePsm c = new SwapperCalleePsm(address(psm)); assertEq(c.psm(), address(psm)); assertEq(c.gem(), USDC); From 35f468af4ce1549c0c975adfb18ca22a5f875c08 Mon Sep 17 00:00:00 2001 From: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> Date: Wed, 15 Nov 2023 18:41:49 -0300 Subject: [PATCH 63/74] Add VaultMinter automation contract (#70) * Add VaultMinter automation contract * Minor changes to tests * Add VaultMinter to deployment scripts + other minor changes * Fix some wording * Fix events * Update test/integration/Deployment.t.sol Co-authored-by: oldchili <130549691+oldchili@users.noreply.github.com> --------- Co-authored-by: oldchili <130549691+oldchili@users.noreply.github.com> --- README.md | 5 + deploy/AllocatorDeploy.sol | 13 ++ deploy/AllocatorInit.sol | 15 ++ deploy/AllocatorInstances.sol | 1 + src/funnels/automation/VaultMinter.sol | 118 ++++++++++++ test/funnels/automation/VaultMinter.t.sol | 210 ++++++++++++++++++++++ test/integration/Deployment.t.sol | 39 +++- 7 files changed, 394 insertions(+), 7 deletions(-) create mode 100644 src/funnels/automation/VaultMinter.sol create mode 100644 test/funnels/automation/VaultMinter.t.sol diff --git a/README.md b/README.md index 6437d630..2554c4f1 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,11 @@ A primitive for depositing liquidity to Uniswap V3 in a fixed range. As the Swapper, it includes rate limit protection and is designed so facilitators and automation contracts can use it. +### VaultMinter + +An automation contract sample, which can be used by the AllocatorDAOs to `draw` or `wipe` from/to the `AllocatorVault`. +- It can be useful for automating generation of funds from the vault to the buffer or repayment from the buffer to the vault. + ### StableSwapper An automation contract, which can be used by the AllocatorDAOs to set up recurring swaps of stable tokens (e.g NST to USDC). diff --git a/deploy/AllocatorDeploy.sol b/deploy/AllocatorDeploy.sol index 5ea8de5a..a3c2cf56 100644 --- a/deploy/AllocatorDeploy.sol +++ b/deploy/AllocatorDeploy.sol @@ -25,6 +25,7 @@ import { AllocatorBuffer } from "src/AllocatorBuffer.sol"; import { AllocatorVault } from "src/AllocatorVault.sol"; import { Swapper } from "src/funnels/Swapper.sol"; import { DepositorUniV3 } from "src/funnels/DepositorUniV3.sol"; +import { VaultMinter } from "src/funnels/automation/VaultMinter.sol"; import { StableSwapper } from "src/funnels/automation/StableSwapper.sol"; import { StableDepositorUniV3 } from "src/funnels/automation/StableDepositorUniV3.sol"; import { ConduitMover } from "src/funnels/automation/ConduitMover.sol"; @@ -77,17 +78,29 @@ library AllocatorDeploy { ScriptTools.switchOwner(_depositorUniV3, deployer, owner); ilkInstance.depositorUniV3 = _depositorUniV3; + { + address _vaultMinter = address(new VaultMinter(_vault)); + ScriptTools.switchOwner(_vaultMinter, deployer, owner); + ilkInstance.vaultMinter = _vaultMinter; + } + + { address _stableSwapper = address(new StableSwapper(_swapper)); ScriptTools.switchOwner(_stableSwapper, deployer, owner); ilkInstance.stableSwapper = _stableSwapper; + } + { address _stableDepositorUniV3 = address(new StableDepositorUniV3(_depositorUniV3)); ScriptTools.switchOwner(_stableDepositorUniV3, deployer, owner); ilkInstance.stableDepositorUniV3 = _stableDepositorUniV3; + } + { address _conduitMover = address(new ConduitMover(ilk, _buffer)); ScriptTools.switchOwner(_conduitMover, deployer, owner); ilkInstance.conduitMover = _conduitMover; + } ilkInstance.owner = owner; } diff --git a/deploy/AllocatorInit.sol b/deploy/AllocatorInit.sol index e674535b..6d056b1b 100644 --- a/deploy/AllocatorInit.sol +++ b/deploy/AllocatorInit.sol @@ -102,6 +102,10 @@ interface DepositorUniV3Like { function collect(CollectParams memory) external returns (uint256, uint256); } +interface VaultMinterLike { + function vault() external view returns (address); +} + interface StableSwapperLike { function swapper() external view returns (address); } @@ -133,6 +137,7 @@ struct AllocatorIlkConfig { uint8 facilitatorRole; uint8 automationRole; address[] facilitators; + address[] vaultMinterKeepers; address[] stableSwapperKeepers; address[] stableDepositorUniV3Keepers; address[] conduitMoverKeepers; @@ -191,6 +196,8 @@ library AllocatorInit { require(DepositorUniV3Like(ilkInstance.depositorUniV3).uniV3Factory() == cfg.uniV3Factory, "AllocatorInit/depositorUniV3-uniV3Factory-mismatch"); require(DepositorUniV3Like(ilkInstance.depositorUniV3).buffer() == ilkInstance.buffer, "AllocatorInit/depositorUniV3-buffer-mismatch"); + require(VaultMinterLike(ilkInstance.vaultMinter).vault() == ilkInstance.vault, "AllocatorInit/vaultMinter-vault-mismatch"); + require(StableSwapperLike(ilkInstance.stableSwapper).swapper() == ilkInstance.swapper, "AllocatorInit/stableSwapper-swapper-mismatch"); require(StableDepositorUniV3Like(ilkInstance.stableDepositorUniV3).depositor() == ilkInstance.depositorUniV3, "AllocatorInit/stableDepositorUniV3-depositorUniV3-mismatch"); @@ -246,9 +253,12 @@ library AllocatorInit { RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.facilitatorRole, ilkInstance.depositorUniV3, DepositorUniV3Like.collect.selector, true); // Allow the automation contracts to operate on the funnels + RolesLike(sharedInstance.roles).setUserRole(ilk, ilkInstance.vaultMinter, cfg.automationRole, true); RolesLike(sharedInstance.roles).setUserRole(ilk, ilkInstance.stableSwapper, cfg.automationRole, true); RolesLike(sharedInstance.roles).setUserRole(ilk, ilkInstance.stableDepositorUniV3, cfg.automationRole, true); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkInstance.vault, VaultLike.draw.selector, true); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkInstance.vault, VaultLike.wipe.selector, true); RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkInstance.swapper, SwapperLike.swap.selector, true); RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkInstance.depositorUniV3, DepositorUniV3Like.deposit.selector, true); RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkInstance.depositorUniV3, DepositorUniV3Like.withdraw.selector, true); @@ -259,12 +269,16 @@ library AllocatorInit { // Allow facilitator to set configurations in the automation contracts for(uint256 i = 0; i < cfg.facilitators.length; i++) { + WardsLike(ilkInstance.vaultMinter).rely(cfg.facilitators[i]); WardsLike(ilkInstance.stableSwapper).rely(cfg.facilitators[i]); WardsLike(ilkInstance.stableDepositorUniV3).rely(cfg.facilitators[i]); WardsLike(ilkInstance.conduitMover).rely(cfg.facilitators[i]); } // Add keepers to the automation contracts + for(uint256 i = 0; i < cfg.vaultMinterKeepers.length; i++) { + KissLike(ilkInstance.vaultMinter).kiss(cfg.vaultMinterKeepers[i]); + } for(uint256 i = 0; i < cfg.stableSwapperKeepers.length; i++) { KissLike(ilkInstance.stableSwapper).kiss(cfg.stableSwapperKeepers[i]); } @@ -280,6 +294,7 @@ library AllocatorInit { ScriptTools.switchOwner(ilkInstance.buffer, ilkInstance.owner, cfg.allocatorProxy); ScriptTools.switchOwner(ilkInstance.swapper, ilkInstance.owner, cfg.allocatorProxy); ScriptTools.switchOwner(ilkInstance.depositorUniV3, ilkInstance.owner, cfg.allocatorProxy); + ScriptTools.switchOwner(ilkInstance.vaultMinter, ilkInstance.owner, cfg.allocatorProxy); ScriptTools.switchOwner(ilkInstance.stableSwapper, ilkInstance.owner, cfg.allocatorProxy); ScriptTools.switchOwner(ilkInstance.stableDepositorUniV3, ilkInstance.owner, cfg.allocatorProxy); ScriptTools.switchOwner(ilkInstance.conduitMover, ilkInstance.owner, cfg.allocatorProxy); diff --git a/deploy/AllocatorInstances.sol b/deploy/AllocatorInstances.sol index c23a6cf0..c3bd633e 100644 --- a/deploy/AllocatorInstances.sol +++ b/deploy/AllocatorInstances.sol @@ -28,6 +28,7 @@ struct AllocatorIlkInstance { address buffer; address swapper; address depositorUniV3; + address vaultMinter; address stableSwapper; address stableDepositorUniV3; address conduitMover; diff --git a/src/funnels/automation/VaultMinter.sol b/src/funnels/automation/VaultMinter.sol new file mode 100644 index 00000000..0746a926 --- /dev/null +++ b/src/funnels/automation/VaultMinter.sol @@ -0,0 +1,118 @@ +// SPDX-FileCopyrightText: © 2023 Dai Foundation +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +pragma solidity ^0.8.16; + +interface AllocatorVaultLike { + function draw(uint256) external; + function wipe(uint256) external; +} + +contract VaultMinter { + mapping (address => uint256) public wards; // Admins + mapping (address => uint256) public buds; // Whitelisted keepers + MinterConfig public config; // Configuration for keepers + + address public immutable vault; // The address of the vault contract + + struct MinterConfig { + int64 num; // The remaining number of times that a draw or wipe can be executed by keepers (> 0: draw, < 0: wipe) + uint32 hop; // Cooldown period it has to wait between each action + uint32 zzz; // Timestamp of the last action + uint128 lot; // The amount to draw or wipe every hop + } + + event Rely(address indexed usr); + event Deny(address indexed usr); + event Kiss(address indexed usr); + event Diss(address indexed usr); + event SetConfig(int64 num, uint32 hop, uint128 lot); + event Draw(uint128 lot); + event Wipe(uint128 lot); + + constructor(address vault_) { + vault = vault_; + + wards[msg.sender] = 1; + emit Rely(msg.sender); + } + + modifier auth { + require(wards[msg.sender] == 1, "VaultMinter/not-authorized"); + _; + } + + modifier toll { + require(buds[msg.sender] == 1, "VaultMinter/non-keeper"); + _; + } + + function rely(address usr) external auth { + wards[usr] = 1; + emit Rely(usr); + } + + function deny(address usr) external auth { + wards[usr] = 0; + emit Deny(usr); + } + + function kiss(address usr) external auth { + buds[usr] = 1; + emit Kiss(usr); + } + + function diss(address usr) external auth { + buds[usr] = 0; + emit Diss(usr); + } + + function setConfig(int64 num, uint32 hop, uint128 lot) external auth { + config = MinterConfig({ + num: num, + hop: hop, + zzz: 0, + lot: lot + }); + emit SetConfig(num, hop, lot); + } + + function draw() toll external { + MinterConfig memory cfg = config; + + require(cfg.num > 0, "VaultMinter/exceeds-num"); + require(block.timestamp >= cfg.zzz + cfg.hop, "VaultMinter/too-soon"); + unchecked { config.num = cfg.num - 1; } + config.zzz = uint32(block.timestamp); + + AllocatorVaultLike(vault).draw(cfg.lot); + + emit Draw(cfg.lot); + } + + function wipe() toll external { + MinterConfig memory cfg = config; + + require(cfg.num < 0, "VaultMinter/exceeds-num"); + require(block.timestamp >= cfg.zzz + cfg.hop, "VaultMinter/too-soon"); + unchecked { config.num = cfg.num + 1; } + config.zzz = uint32(block.timestamp); + + AllocatorVaultLike(vault).wipe(cfg.lot); + + emit Wipe(cfg.lot); + } +} diff --git a/test/funnels/automation/VaultMinter.t.sol b/test/funnels/automation/VaultMinter.t.sol new file mode 100644 index 00000000..d74a15b5 --- /dev/null +++ b/test/funnels/automation/VaultMinter.t.sol @@ -0,0 +1,210 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.8.16; + +import "dss-test/DssTest.sol"; +import { VaultMinter } from "src/funnels/automation/VaultMinter.sol"; +import { AllocatorRoles } from "src/AllocatorRoles.sol"; +import { AllocatorVault } from "src/AllocatorVault.sol"; +import { AllocatorBuffer } from "src/AllocatorBuffer.sol"; +import { VatMock } from "test/mocks/VatMock.sol"; +import { JugMock } from "test/mocks/JugMock.sol"; +import { GemMock } from "test/mocks/GemMock.sol"; +import { NstJoinMock } from "test/mocks/NstJoinMock.sol"; + +contract VaultMinterTest is DssTest { + using stdStorage for StdStorage; + + event Kiss(address indexed usr); + event Diss(address indexed usr); + event SetConfig(int64 num, uint32 hop, uint128 lot); + event Draw(uint128 lot); + event Wipe(uint128 lot); + + VatMock public vat; + JugMock public jug; + GemMock public nst; + NstJoinMock public nstJoin; + AllocatorBuffer public buffer; + AllocatorRoles public roles; + AllocatorVault public vault; + VaultMinter public minter; + + bytes32 constant ILK = "aaa"; + address constant FACILITATOR = address(0x1337); + address constant KEEPER = address(0xb0b); + uint8 constant MINTER_ROLE = uint8(1); + + function setUp() public { + vat = new VatMock(); + jug = new JugMock(vat); + nst = new GemMock(0); + nstJoin = new NstJoinMock(vat, nst); + buffer = new AllocatorBuffer(); + roles = new AllocatorRoles(); + vault = new AllocatorVault(address(roles), address(buffer), ILK, address(nstJoin)); + vault.file("jug", address(jug)); + buffer.approve(address(nst), address(vault), type(uint256).max); + + vat.slip(ILK, address(vault), int256(1_000_000 * WAD)); + vat.grab(ILK, address(vault), address(vault), address(0), int256(1_000_000 * WAD), 0); + + minter = new VaultMinter(address(vault)); + + // Allow minter to perform operations in the vault + roles.setIlkAdmin(ILK, address(this)); + roles.setRoleAction(ILK, MINTER_ROLE, address(vault), AllocatorVault.draw.selector, true); + roles.setRoleAction(ILK, MINTER_ROLE, address(vault), AllocatorVault.wipe.selector, true); + roles.setUserRole(ILK, address(minter), MINTER_ROLE, true); + + // Set up keeper to mint and burn + minter.rely(FACILITATOR); + vm.prank(FACILITATOR); minter.kiss(KEEPER); + + vm.warp(1 hours); + } + + function testConstructor() public { + vm.expectEmit(true, true, true, true); + emit Rely(address(this)); + VaultMinter m = new VaultMinter(address(0xABC)); + assertEq(m.vault(), address(0xABC)); + assertEq(m.wards(address(this)), 1); + } + + function testAuth() public { + checkAuth(address(minter), "VaultMinter"); + } + + function testModifiers() public { + bytes4[] memory authedMethods = new bytes4[](3); + authedMethods[0] = VaultMinter.kiss.selector; + authedMethods[1] = VaultMinter.diss.selector; + authedMethods[2] = VaultMinter.setConfig.selector; + + vm.startPrank(address(0xBEEF)); + checkModifier(address(minter), "VaultMinter/not-authorized", authedMethods); + vm.stopPrank(); + + bytes4[] memory keeperMethods = new bytes4[](2); + keeperMethods[0] = VaultMinter.draw.selector; + keeperMethods[1] = VaultMinter.wipe.selector; + + vm.startPrank(address(0xBEEF)); + checkModifier(address(minter), "VaultMinter/non-keeper", keeperMethods); + vm.stopPrank(); + } + + function testKissDiss() public { + address testAddress = address(0x123); + assertEq(minter.buds(testAddress), 0); + + vm.expectEmit(true, true, true, true); + emit Kiss(testAddress); + minter.kiss(testAddress); + assertEq(minter.buds(testAddress), 1); + + vm.expectEmit(true, true, true, true); + emit Diss(testAddress); + minter.diss(testAddress); + assertEq(minter.buds(testAddress), 0); + } + + function testSetConfig() public { + vm.expectEmit(true, true, true, true); + emit SetConfig(int64(23), uint32(360 seconds), uint128(314)); + minter.setConfig(int64(23), uint32(360 seconds), uint128(314)); + + (int64 num, uint32 hop, uint32 zzz, uint128 lot) = minter.config(); + assertEq(num, 23); + assertEq(hop, 360); + assertEq(zzz, 0); + assertEq(lot, 314); + + vm.expectEmit(true, true, true, true); + emit SetConfig(-int64(10), uint32(180 seconds), uint128(411)); + minter.setConfig(-int64(10), uint32(180 seconds), uint128(411)); + + (num, hop, zzz, lot) = minter.config(); + assertEq(num, -int64(10)); + assertEq(hop, 180); + assertEq(zzz, 0); + assertEq(lot, 411); + } + + function testDrawWipeByKeeper() public { + minter.setConfig(int64(10), uint32(1 hours), uint128(1_000 * WAD)); + + assertEq(nst.balanceOf(address(buffer)), 0); + (int64 num, uint32 hop, uint32 zzz, uint128 lot) = minter.config(); + assertEq(num, 10); + assertEq(hop, 1 hours); + assertEq(zzz, 0); + assertEq(lot, 1_000 * WAD); + + vm.expectEmit(true, true, true, true); + emit Draw(uint128(1_000 * WAD)); + vm.prank(KEEPER); minter.draw(); + + assertEq(nst.balanceOf(address(buffer)), 1_000 * WAD); + (num, hop, zzz, lot) = minter.config(); + assertEq(num, 9); + assertEq(hop, 1 hours); + assertEq(zzz, block.timestamp); + assertEq(lot, 1_000 * WAD); + + vm.warp(block.timestamp + 1 hours - 1); + vm.expectRevert("VaultMinter/too-soon"); + vm.prank(KEEPER); minter.draw(); + + vm.warp(block.timestamp + 1); + vm.prank(KEEPER); minter.draw(); + + assertEq(nst.balanceOf(address(buffer)), 2_000 * WAD); + (num, hop, zzz, lot) = minter.config(); + assertEq(num, 8); + assertEq(hop, 1 hours); + assertEq(zzz, block.timestamp); + assertEq(lot, 1_000 * WAD); + + minter.setConfig(-int64(10), uint32(1 hours), uint128(100 * WAD)); + + (num, hop, zzz, lot) = minter.config(); + assertEq(num, -10); + assertEq(hop, 1 hours); + assertEq(zzz, 0); + assertEq(lot, 100 * WAD); + + vm.expectEmit(true, true, true, true); + emit Wipe(uint128(100 * WAD)); + vm.prank(KEEPER); minter.wipe(); + + assertEq(nst.balanceOf(address(buffer)), 1_900 * WAD); + (num, hop, zzz, lot) = minter.config(); + assertEq(num, -9); + assertEq(hop, 1 hours); + assertEq(zzz, block.timestamp); + assertEq(lot, 100 * WAD); + + vm.warp(block.timestamp + 1 hours - 1); + vm.expectRevert("VaultMinter/too-soon"); + vm.prank(KEEPER); minter.wipe(); + + vm.warp(block.timestamp + 1); + vm.prank(KEEPER); minter.wipe(); + + assertEq(nst.balanceOf(address(buffer)), 1_800 * WAD); + (num, hop, zzz, lot) = minter.config(); + assertEq(num, -8); + assertEq(hop, 1 hours); + assertEq(zzz, block.timestamp); + assertEq(lot, 100 * WAD); + } + + function testMintBurnExceedingNum() public { + vm.expectRevert("VaultMinter/exceeds-num"); + vm.prank(KEEPER); minter.draw(); + vm.expectRevert("VaultMinter/exceeds-num"); + vm.prank(KEEPER); minter.wipe(); + } +} diff --git a/test/integration/Deployment.t.sol b/test/integration/Deployment.t.sol index 30d60e24..5770e1a1 100644 --- a/test/integration/Deployment.t.sol +++ b/test/integration/Deployment.t.sol @@ -35,6 +35,7 @@ import { AllocatorVault } from "src/AllocatorVault.sol"; import { AllocatorBuffer } from "src/AllocatorBuffer.sol"; import { Swapper } from "src/funnels/Swapper.sol"; import { DepositorUniV3 } from "src/funnels/DepositorUniV3.sol"; +import { VaultMinter } from "src/funnels/automation/VaultMinter.sol"; import { StableSwapper } from "src/funnels/automation/StableSwapper.sol"; import { StableDepositorUniV3 } from "src/funnels/automation/StableDepositorUniV3.sol"; import { ConduitMover } from "src/funnels/automation/ConduitMover.sol"; @@ -87,12 +88,14 @@ contract DeploymentTest is DssTest { address constant allocatorProxy = address(0x1); address constant facilitator1 = address(0x2); address constant facilitator2 = address(0x3); - address constant stableSwapperKeeper1 = address(0x4); - address constant stableSwapperKeeper2 = address(0x5); - address constant stableDepositorUniV3Keeper1 = address(0x6); - address constant stableDepositorUniV3Keeper2 = address(0x7); - address constant conduitMoverKeeper1 = address(0x8); - address constant conduitMoverKeeper2 = address(0x9); + address constant vaultMinterKeeper1 = address(0x4); + address constant vaultMinterKeeper2 = address(0x5); + address constant stableSwapperKeeper1 = address(0x6); + address constant stableSwapperKeeper2 = address(0x7); + address constant stableDepositorUniV3Keeper1 = address(0x8); + address constant stableDepositorUniV3Keeper2 = address(0x9); + address constant conduitMoverKeeper1 = address(0xA); + address constant conduitMoverKeeper2 = address(0xB); // roles uint8 constant facilitatorRole = uint8(1); @@ -160,6 +163,10 @@ contract DeploymentTest is DssTest { facilitators[0] = facilitator1; facilitators[1] = facilitator2; + address[] memory vaultMinterKeepers = new address[](2); + vaultMinterKeepers[0] = vaultMinterKeeper1; + vaultMinterKeepers[1] = vaultMinterKeeper2; + address[] memory stableSwapperKeepers = new address[](2); stableSwapperKeepers[0] = stableSwapperKeeper1; stableSwapperKeepers[1] = stableSwapperKeeper2; @@ -182,6 +189,7 @@ contract DeploymentTest is DssTest { facilitatorRole : facilitatorRole, automationRole : automationRole, facilitators : facilitators, + vaultMinterKeepers : vaultMinterKeepers, stableSwapperKeepers : stableSwapperKeepers, stableDepositorUniV3Keepers : stableDepositorUniV3Keepers, conduitMoverKeepers : conduitMoverKeepers, @@ -278,6 +286,8 @@ contract DeploymentTest is DssTest { assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkInst.depositorUniV3, DepositorUniV3.withdraw.selector, automationRole), true); assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkInst.depositorUniV3, DepositorUniV3.collect.selector, automationRole), true); + assertEq(WardsLike(ilkInst.vaultMinter).wards(facilitator1), 1); + assertEq(WardsLike(ilkInst.vaultMinter).wards(facilitator2), 1); assertEq(WardsLike(ilkInst.stableSwapper).wards(facilitator1), 1); assertEq(WardsLike(ilkInst.stableSwapper).wards(facilitator2), 1); assertEq(WardsLike(ilkInst.stableDepositorUniV3).wards(facilitator1), 1); @@ -285,6 +295,8 @@ contract DeploymentTest is DssTest { assertEq(WardsLike(ilkInst.conduitMover).wards(facilitator1), 1); assertEq(WardsLike(ilkInst.conduitMover).wards(facilitator2), 1); + assertEq(VaultMinter(ilkInst.vaultMinter).buds(vaultMinterKeeper1), 1); + assertEq(VaultMinter(ilkInst.vaultMinter).buds(vaultMinterKeeper2), 1); assertEq(StableSwapper(ilkInst.stableSwapper).buds(stableSwapperKeeper1), 1); assertEq(StableSwapper(ilkInst.stableSwapper).buds(stableSwapperKeeper2), 1); assertEq(StableDepositorUniV3(ilkInst.stableDepositorUniV3).buds(stableDepositorUniV3Keeper1), 1); @@ -304,6 +316,9 @@ contract DeploymentTest is DssTest { assertEq(WardsLike(ilkInst.depositorUniV3).wards(PAUSE_PROXY), 0); assertEq(WardsLike(ilkInst.depositorUniV3).wards(allocatorProxy), 1); + assertEq(WardsLike(ilkInst.vaultMinter).wards(PAUSE_PROXY), 0); + assertEq(WardsLike(ilkInst.vaultMinter).wards(allocatorProxy), 1); + assertEq(WardsLike(ilkInst.stableSwapper).wards(PAUSE_PROXY), 0); assertEq(WardsLike(ilkInst.stableSwapper).wards(allocatorProxy), 1); @@ -329,13 +344,23 @@ contract DeploymentTest is DssTest { assertEq(IlkRegistryLike(ILK_REGISTRY).symbol(ILK), string("ILK-A")); } - function testVaultDrawWipe() public { + function testVaultDrawWipeFromFacilitator() public { emulateSpell(); vm.prank(facilitator1); AllocatorVault(ilkInst.vault).draw(1_000 * WAD); vm.prank(facilitator1); AllocatorVault(ilkInst.vault).wipe(1_000 * WAD); } + function testVaultDrawWipeFromFromKeeper() public { + emulateSpell(); + + vm.prank(facilitator1); VaultMinter(ilkInst.vaultMinter).setConfig(1, 1 hours, uint96(1_000 * WAD)); + vm.prank(vaultMinterKeeper1); VaultMinter(ilkInst.vaultMinter).draw(); + + vm.prank(facilitator1); VaultMinter(ilkInst.vaultMinter).setConfig(-1, 1 hours, uint96(1_000 * WAD)); + vm.prank(vaultMinterKeeper1); VaultMinter(ilkInst.vaultMinter).wipe(); + } + function testSwapFromFacilitator() public { emulateSpell(); From 7d8403dd98f8fc20ccda12cb1bd281c7c499f330 Mon Sep 17 00:00:00 2001 From: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> Date: Mon, 20 Nov 2023 09:12:49 -0300 Subject: [PATCH 64/74] Add Certora specs (#46) * Add initial set of Certora specs (WIP) * Add pull_request for CI * Fix Certora CI * Fix syntax error * Add new rules to Roles * Apply modifications in spec for vault changes * Swapper specs (WIP) * Fix typo * Swapper spec fixes * Make some mock contracts more general * More renaming of mocks * Fix + more renaming * More renaming * Initial set of rules for DepositorUniV3 * Remove comment * Swapper spec fixes * Fix Swapper spec + Move some mocks + Add CI for Swapper and Depositor * DepositorUniV3: deposit rule * DepositorUniV3: deposit_revert rule * DepositorUniV3: withdraw and withdraw_revert rules * Fix mock * DepositorUniV3: Check return values for deposit and withdraw (WIP) * DepositorUniV3: add collect and collect_revert rules * DepositorUniV3: add uniswapV3MintCallback and uniswapV3MintCallback_revert rules * DepositorUniV3: add getPosition rule * Add StableSwapper specs * Use certora-cli beta for now due to a bug in production tool * Add initial set of rules for StableDepositorUniV3 (WIP) + Missing CI for StableSwapper * Vault: Remove init specs * StableSwapper: Fix error messages * StableDepositorUniV3: deposit, withdraw and collect rules * StableDepositorUniV3: deposit_revert, withdraw_revert and collect_revert rules * Solve timeout issue on Vault draw_revert rule + simplify run commands for other spec files * CI: Use multi_assert_check to avoid timeout on draw_revert * CI: Run only vault with multi_assert_check * Vault: Minor change to draw_revert + add wipe and wipe_revert (wip as it is timing out) * Fix error messages Co-authored-by: telome <130504305+telome@users.noreply.github.com> * Remove unnecessary assert * Move some asserts to require as they are third party logic * Check src balance for Swapper * Variables renaming * Add external call check for automation contracts * Automation contracts: check all params are passed correctly * Rename other variables * Check address receiving call is correct * Add ConduitMover spec (pending to finish move_revert) * Finish ConduitMover * Add counters * Fix message * Add --wait_for_results * Update move_revert to latest changes * Use config files (#68) * Change AllocatorOracle spec due to code change * Add rule for checking non corresponding storage keeps unchanged (#67) * Add rule for checking non corresponding storage keeps unchanged * Remove unused variables * Test for Rely events in constructors + minor test re-arranging (#71) * Test for Rely events in constructors + minor test re-arranging * Fix SwapperCalleeUniV3Test --------- Co-authored-by: telome <> * Add VaultMinter automation contract (#70) * Add VaultMinter automation contract * Minor changes to tests * Add VaultMinter to deployment scripts + other minor changes * Fix some wording * Fix events * Update test/integration/Deployment.t.sol Co-authored-by: oldchili <130549691+oldchili@users.noreply.github.com> --------- Co-authored-by: oldchili <130549691+oldchili@users.noreply.github.com> * Add VaultMinter specs * Make reverts rules shorter using double implication * Remove unnecessary lines * Improve comment * Remove other unnecessary line --------- Co-authored-by: telome <130504305+telome@users.noreply.github.com> Co-authored-by: oldchili <130549691+oldchili@users.noreply.github.com> --- .github/workflows/certora.yml | 51 ++ .gitignore | 8 + Makefile | 12 + certora/AllocatorBuffer.conf | 17 + certora/AllocatorBuffer.spec | 118 ++++ certora/AllocatorOracle.conf | 10 + certora/AllocatorOracle.spec | 23 + certora/AllocatorRegistry.conf | 10 + certora/AllocatorRegistry.spec | 123 ++++ certora/AllocatorRoles.conf | 10 + certora/AllocatorRoles.spec | 236 +++++++ certora/AllocatorVault.conf | 36 ++ certora/AllocatorVault.spec | 280 ++++++++ certora/funnels/Auxiliar.sol | 13 + certora/funnels/DepositorUniV3.conf | 28 + certora/funnels/DepositorUniV3.spec | 606 ++++++++++++++++++ certora/funnels/Swapper.conf | 26 + certora/funnels/Swapper.spec | 243 +++++++ certora/funnels/automation/ConduitMover.conf | 10 + certora/funnels/automation/ConduitMover.spec | 334 ++++++++++ .../automation/StableDepositorUniV3.conf | 10 + .../automation/StableDepositorUniV3.spec | 479 ++++++++++++++ certora/funnels/automation/StableSwapper.conf | 10 + certora/funnels/automation/StableSwapper.spec | 294 +++++++++ certora/funnels/automation/VaultMinter.conf | 10 + certora/funnels/automation/VaultMinter.spec | 325 ++++++++++ test/mocks/CalleeMock.sol | 16 + test/mocks/Gem0Mock.sol | 8 + test/mocks/Gem1Mock.sol | 8 + test/mocks/JugMock.sol | 4 +- test/mocks/NstMock.sol | 80 +++ test/mocks/PoolUniV3Mock.sol | 50 ++ test/mocks/VatMock.sol | 14 +- 33 files changed, 3496 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/certora.yml create mode 100644 Makefile create mode 100644 certora/AllocatorBuffer.conf create mode 100644 certora/AllocatorBuffer.spec create mode 100644 certora/AllocatorOracle.conf create mode 100644 certora/AllocatorOracle.spec create mode 100644 certora/AllocatorRegistry.conf create mode 100644 certora/AllocatorRegistry.spec create mode 100644 certora/AllocatorRoles.conf create mode 100644 certora/AllocatorRoles.spec create mode 100644 certora/AllocatorVault.conf create mode 100644 certora/AllocatorVault.spec create mode 100644 certora/funnels/Auxiliar.sol create mode 100644 certora/funnels/DepositorUniV3.conf create mode 100644 certora/funnels/DepositorUniV3.spec create mode 100644 certora/funnels/Swapper.conf create mode 100644 certora/funnels/Swapper.spec create mode 100644 certora/funnels/automation/ConduitMover.conf create mode 100644 certora/funnels/automation/ConduitMover.spec create mode 100644 certora/funnels/automation/StableDepositorUniV3.conf create mode 100644 certora/funnels/automation/StableDepositorUniV3.spec create mode 100644 certora/funnels/automation/StableSwapper.conf create mode 100644 certora/funnels/automation/StableSwapper.spec create mode 100644 certora/funnels/automation/VaultMinter.conf create mode 100644 certora/funnels/automation/VaultMinter.spec create mode 100644 test/mocks/CalleeMock.sol create mode 100644 test/mocks/Gem0Mock.sol create mode 100644 test/mocks/Gem1Mock.sol create mode 100644 test/mocks/NstMock.sol create mode 100644 test/mocks/PoolUniV3Mock.sol diff --git a/.github/workflows/certora.yml b/.github/workflows/certora.yml new file mode 100644 index 00000000..b106dd88 --- /dev/null +++ b/.github/workflows/certora.yml @@ -0,0 +1,51 @@ +name: Certora + +on: [push, pull_request] + +jobs: + certora: + name: Certora + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + allocator: + - buffer + - vault + - roles + - oracle + - registry + - swapper + - depositoruniv3 + - stable-swapper + - stable-depositoruniv3 + - conduit-mover + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - uses: actions/setup-java@v3 + with: + distribution: 'zulu' + java-version: '11' + java-package: jre + + - name: Set up Python 3.8 + uses: actions/setup-python@v4 + with: + python-version: 3.8 + + - name: Install solc-select + run: pip3 install solc-select + + - name: Solc Select 0.8.16 + run: solc-select install 0.8.16 + + - name: Install Certora + run: pip3 install certora-cli-beta + + - name: Certora verify ${{ matrix.allocator }} + run: make certora-${{ matrix.allocator }} + env: + CERTORAKEY: ${{ secrets.CERTORAKEY }} diff --git a/.gitignore b/.gitignore index 941feff6..a7e4a060 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,11 @@ docs/ # Dotenv file .env tmp + +# Certora +.*certora* +.last_confs/ +*.zip +resource_errors.json +.zip-output-url.txt +certora_debug_log.txt diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..42b768f9 --- /dev/null +++ b/Makefile @@ -0,0 +1,12 @@ +PATH := ~/.solc-select/artifacts/solc-0.8.16:~/.solc-select/artifacts:$(PATH) +certora-buffer :; PATH=${PATH} certoraRun certora/AllocatorBuffer.conf$(if $(rule), --rule $(rule),) +certora-vault :; PATH=${PATH} certoraRun certora/AllocatorVault.conf$(if $(rule), --rule $(rule),) +certora-roles :; PATH=${PATH} certoraRun certora/AllocatorRoles.conf$(if $(rule), --rule $(rule),) +certora-oracle :; PATH=${PATH} certoraRun certora/AllocatorOracle.conf$(if $(rule), --rule $(rule),) +certora-registry :; PATH=${PATH} certoraRun certora/AllocatorRegistry.conf$(if $(rule), --rule $(rule),) +certora-swapper :; PATH=${PATH} certoraRun certora/funnels/Swapper.conf$(if $(rule), --rule $(rule),) +certora-depositoruniv3 :; PATH=${PATH} certoraRun certora/funnels/DepositorUniV3.conf$(if $(rule), --rule $(rule),) +certora-vault-minter :; PATH=${PATH} certoraRun certora/funnels/automation/VaultMinter.conf$(if $(rule), --rule $(rule),) +certora-stable-swapper :; PATH=${PATH} certoraRun certora/funnels/automation/StableSwapper.conf$(if $(rule), --rule $(rule),) +certora-stable-depositoruniv3 :; PATH=${PATH} certoraRun certora/funnels/automation/StableDepositorUniV3.conf$(if $(rule), --rule $(rule),) +certora-conduit-mover :; PATH=${PATH} certoraRun certora/funnels/automation/ConduitMover.conf$(if $(rule), --rule $(rule),) diff --git a/certora/AllocatorBuffer.conf b/certora/AllocatorBuffer.conf new file mode 100644 index 00000000..b81471da --- /dev/null +++ b/certora/AllocatorBuffer.conf @@ -0,0 +1,17 @@ +{ + "files": [ + "src/AllocatorBuffer.sol", + "test/mocks/GemMock.sol" + ], + "rule_sanity": "basic", + "solc": "solc-0.8.16", + "solc_optimize_map": { + "AllocatorBuffer": "200", + "GemMock": "0" + }, + "verify": "AllocatorBuffer:certora/AllocatorBuffer.spec", + "parametric_contracts": [ + "AllocatorBuffer" + ], + "wait_for_results": "all" +} diff --git a/certora/AllocatorBuffer.spec b/certora/AllocatorBuffer.spec new file mode 100644 index 00000000..fe099a4d --- /dev/null +++ b/certora/AllocatorBuffer.spec @@ -0,0 +1,118 @@ +// AllocatorBuffer.spec + +using GemMock as gem; + +methods { + function wards(address) external returns (uint256) envfree; + function gem.allowance(address, address) external returns (uint256) envfree; + function _.approve(address, uint256) external => DISPATCHER(true) UNRESOLVED; +} + +// Verify that each storage layout is only modified in the corresponding functions +rule storageAffected(method f) { + env e; + + address anyAddr; + + mathint wardsBefore = wards(anyAddr); + + calldataarg args; + f(e, args); + + mathint wardsAfter = wards(anyAddr); + + assert wardsAfter != wardsBefore => f.selector == sig:rely(address).selector || f.selector == sig:deny(address).selector, "wards[x] changed in an unexpected function"; +} + +// Verify correct storage changes for non reverting rely +rule rely(address usr) { + env e; + + address other; + require other != usr; + + mathint wardsOtherBefore = wards(other); + + rely(e, usr); + + mathint wardsUsrAfter = wards(usr); + mathint wardsOtherAfter = wards(other); + + assert wardsUsrAfter == 1, "rely did not set the wards"; + assert wardsOtherAfter == wardsOtherBefore, "rely did not keep unchanged the rest of wards[x]"; +} + +// Verify revert rules on rely +rule rely_revert(address usr) { + env e; + + mathint wardsSender = wards(e.msg.sender); + + rely@withrevert(e, usr); + + bool revert1 = e.msg.value > 0; + bool revert2 = wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting deny +rule deny(address usr) { + env e; + + address other; + require other != usr; + + mathint wardsOtherBefore = wards(other); + + deny(e, usr); + + mathint wardsUsrAfter = wards(usr); + mathint wardsOtherAfter = wards(other); + + assert wardsUsrAfter == 0, "deny did not set the wards"; + assert wardsOtherAfter == wardsOtherBefore, "deny did not keep unchanged the rest of wards[x]"; +} + +// Verify revert rules on deny +rule deny_revert(address usr) { + env e; + + mathint wardsSender = wards(e.msg.sender); + + deny@withrevert(e, usr); + + bool revert1 = e.msg.value > 0; + bool revert2 = wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting approve +rule approve(address asset, address spender, uint256 amount) { + env e; + + require asset == gem; + + approve(e, asset, spender, amount); + + mathint allowance = gem.allowance(currentContract, spender); + + assert allowance == to_mathint(amount), "approve did not set allowance to amount value"; +} + +// Verify revert rules on approve +rule approve_revert(address asset, address spender, uint256 amount) { + env e; + + require asset == gem; + + mathint wardsSender = wards(e.msg.sender); + + approve@withrevert(e, asset, spender, amount); + + bool revert1 = e.msg.value > 0; + bool revert2 = wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} diff --git a/certora/AllocatorOracle.conf b/certora/AllocatorOracle.conf new file mode 100644 index 00000000..127e1c57 --- /dev/null +++ b/certora/AllocatorOracle.conf @@ -0,0 +1,10 @@ +{ + "files": [ + "src/AllocatorOracle.sol" + ], + "rule_sanity": "basic", + "solc": "solc-0.8.16", + "solc_optimize": "200", + "verify": "AllocatorOracle:certora/AllocatorOracle.spec", + "wait_for_results": "all" +} diff --git a/certora/AllocatorOracle.spec b/certora/AllocatorOracle.spec new file mode 100644 index 00000000..072f4dbb --- /dev/null +++ b/certora/AllocatorOracle.spec @@ -0,0 +1,23 @@ +// AllocatorOracle.spec + +methods { + function peek() external returns (bytes32, bool) envfree; + function read() external returns (bytes32) envfree; +} + +// Verify correct response from peek +rule peek() { + bytes32 val; + bool ok; + val, ok = peek(); + + assert val == to_bytes32(10^18), "peek did not return the expected val result"; + assert ok, "peek did not return the expected ok result"; +} + +// Verify correct response from read +rule read() { + bytes32 val = read(); + + assert val == to_bytes32(10^18), "read did not return the expected result"; +} diff --git a/certora/AllocatorRegistry.conf b/certora/AllocatorRegistry.conf new file mode 100644 index 00000000..7bb23ed5 --- /dev/null +++ b/certora/AllocatorRegistry.conf @@ -0,0 +1,10 @@ +{ + "files": [ + "src/AllocatorRegistry.sol" + ], + "rule_sanity": "basic", + "solc": "solc-0.8.16", + "solc_optimize": "200", + "verify": "AllocatorRegistry:certora/AllocatorRegistry.spec", + "wait_for_results": "all" +} diff --git a/certora/AllocatorRegistry.spec b/certora/AllocatorRegistry.spec new file mode 100644 index 00000000..0fd524d6 --- /dev/null +++ b/certora/AllocatorRegistry.spec @@ -0,0 +1,123 @@ +// AllocatorRegistry.spec + +methods { + function wards(address) external returns (uint256) envfree; + function buffers(bytes32) external returns (address) envfree; +} + +// Verify that each storage layout is only modified in the corresponding functions +rule storageAffected(method f) { + env e; + + address anyAddr; + bytes32 anyBytes32; + + mathint wardsBefore = wards(anyAddr); + address buffersBefore = buffers(anyBytes32); + + calldataarg args; + f(e, args); + + mathint wardsAfter = wards(anyAddr); + address buffersAfter = buffers(anyBytes32); + + assert wardsAfter != wardsBefore => f.selector == sig:rely(address).selector || f.selector == sig:deny(address).selector, "wards[x] changed in an unexpected function"; + assert buffersAfter != buffersBefore => f.selector == sig:file(bytes32,bytes32,address).selector, "buffers[x] changed in an unexpected function"; +} + +// Verify correct storage changes for non reverting rely +rule rely(address usr) { + env e; + + address other; + require other != usr; + + mathint wardsOtherBefore = wards(other); + + rely(e, usr); + + mathint wardsUsrAfter = wards(usr); + mathint wardsOtherAfter = wards(other); + + assert wardsUsrAfter == 1, "rely did not set the wards"; + assert wardsOtherAfter == wardsOtherBefore, "rely did not keep unchanged the rest of wards[x]"; +} + +// Verify revert rules on rely +rule rely_revert(address usr) { + env e; + + mathint wardsSender = wards(e.msg.sender); + + rely@withrevert(e, usr); + + bool revert1 = e.msg.value > 0; + bool revert2 = wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting deny +rule deny(address usr) { + env e; + + address other; + require other != usr; + + mathint wardsOtherBefore = wards(other); + + deny(e, usr); + + mathint wardsUsrAfter = wards(usr); + mathint wardsOtherAfter = wards(other); + + assert wardsUsrAfter == 0, "deny did not set the wards"; + assert wardsOtherAfter == wardsOtherBefore, "deny did not keep unchanged the rest of wards[x]"; +} + +// Verify revert rules on deny +rule deny_revert(address usr) { + env e; + + mathint wardsSender = wards(e.msg.sender); + + deny@withrevert(e, usr); + + bool revert1 = e.msg.value > 0; + bool revert2 = wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting file +rule file(bytes32 ilk, bytes32 what, address data) { + env e; + + bytes32 otherBytes32; + require otherBytes32 != ilk; + + address buffersOtherBefore = buffers(otherBytes32); + + file(e, ilk, what, data); + + address buffersIlkAfter = buffers(ilk); + address buffersOtherAfter = buffers(otherBytes32); + + assert buffersIlkAfter == data, "file did not set buffers[ilk] to data"; + assert buffersOtherAfter == buffersOtherBefore, "file did not keep unchanged the rest of buffers[x]"; +} + +// Verify revert rules on file +rule file_revert(bytes32 ilk, bytes32 what, address data) { + env e; + + mathint wardsSender = wards(e.msg.sender); + + file@withrevert(e, ilk, what, data); + + bool revert1 = e.msg.value > 0; + bool revert2 = wardsSender != 1; + bool revert3 = what != to_bytes32(0x6275666665720000000000000000000000000000000000000000000000000000); + + assert lastReverted <=> revert1 || revert2 || revert3, "Revert rules failed"; +} diff --git a/certora/AllocatorRoles.conf b/certora/AllocatorRoles.conf new file mode 100644 index 00000000..10376ef8 --- /dev/null +++ b/certora/AllocatorRoles.conf @@ -0,0 +1,10 @@ +{ + "files": [ + "src/AllocatorRoles.sol" + ], + "rule_sanity": "basic", + "solc": "solc-0.8.16", + "solc_optimize": "200", + "verify": "AllocatorRoles:certora/AllocatorRoles.spec", + "wait_for_results": "all" +} diff --git a/certora/AllocatorRoles.spec b/certora/AllocatorRoles.spec new file mode 100644 index 00000000..00f52ccc --- /dev/null +++ b/certora/AllocatorRoles.spec @@ -0,0 +1,236 @@ +// AllocatorRoles.spec + +methods { + function wards(address) external returns (uint256) envfree; + function ilkAdmins(bytes32) external returns (address) envfree; + function userRoles(bytes32, address) external returns (bytes32) envfree; + function actionsRoles(bytes32, address, bytes4) external returns (bytes32) envfree; + function hasUserRole(bytes32, address, uint8) external returns (bool) envfree; + function hasActionRole(bytes32, address, bytes4, uint8) external returns (bool) envfree; + function canCall(bytes32, address, address, bytes4) external returns (bool) envfree; +} + +definition bitNot(uint256 input) returns uint256 = input xor max_uint256; + +// Verify correct response from hasUserRole +rule hasUserRole(bytes32 ilk, address who, uint8 role) { + bool ok = userRoles(ilk, who) & to_bytes32(assert_uint256(2^role)) != to_bytes32(0); + + bool ok2 = hasUserRole(ilk, who, role); + + assert ok2 == ok, "hasUserRole did not return the expected result"; +} + +// Verify correct response from hasActionRole +rule hasActionRole(bytes32 ilk, address target, bytes4 sign, uint8 role) { + bool ok = actionsRoles(ilk, target, sign) & to_bytes32(assert_uint256(2^role)) != to_bytes32(0); + + bool ok2 = hasActionRole(ilk, target, sign, role); + + assert ok2 == ok, "hasActionRole did not return the expected result"; +} + +// Verify that each storage layout is only modified in the corresponding functions +rule storageAffected(method f) { + env e; + + address anyAddr; + bytes32 anyBytes32; + bytes4 anyBytes4; + + mathint wardsBefore = wards(anyAddr); + address ilkAdminsBefore = ilkAdmins(anyBytes32); + bytes32 userRolesBefore = userRoles(anyBytes32, anyAddr); + bytes32 actionsRolesBefore = actionsRoles(anyBytes32, anyAddr, anyBytes4); + + calldataarg args; + f(e, args); + + mathint wardsAfter = wards(anyAddr); + address ilkAdminsAfter = ilkAdmins(anyBytes32); + bytes32 userRolesAfter = userRoles(anyBytes32, anyAddr); + bytes32 actionsRolesAfter = actionsRoles(anyBytes32, anyAddr, anyBytes4); + + assert wardsAfter != wardsBefore => f.selector == sig:rely(address).selector || f.selector == sig:deny(address).selector, "wards[x] changed in an unexpected function"; + assert ilkAdminsAfter != ilkAdminsBefore => f.selector == sig:setIlkAdmin(bytes32,address).selector, "ilkAdmins[x] changed in an unexpected function"; + assert userRolesAfter != userRolesBefore => f.selector == sig:setUserRole(bytes32,address,uint8,bool).selector, "userRoles[x][y] changed in an unexpected function"; + assert actionsRolesAfter != actionsRolesBefore => f.selector == sig:setRoleAction(bytes32,uint8,address,bytes4,bool).selector, "actionsRoles[x][y][z] changed in an unexpected function"; +} + +// Verify correct storage changes for non reverting rely +rule rely(address usr) { + env e; + + address other; + require other != usr; + + mathint wardsOtherBefore = wards(other); + + rely(e, usr); + + mathint wardsUsrAfter = wards(usr); + mathint wardsOtherAfter = wards(other); + + assert wardsUsrAfter == 1, "rely did not set the wards"; + assert wardsOtherAfter == wardsOtherBefore, "rely did not keep unchanged the rest of wards[x]"; +} + +// Verify revert rules on rely +rule rely_revert(address usr) { + env e; + + mathint wardsSender = wards(e.msg.sender); + + rely@withrevert(e, usr); + + bool revert1 = e.msg.value > 0; + bool revert2 = wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting deny +rule deny(address usr) { + env e; + + address other; + require other != usr; + + mathint wardsOtherBefore = wards(other); + + deny(e, usr); + + mathint wardsUsrAfter = wards(usr); + mathint wardsOtherAfter = wards(other); + + assert wardsUsrAfter == 0, "deny did not set the wards"; + assert wardsOtherAfter == wardsOtherBefore, "deny did not keep unchanged the rest of wards[x]"; +} + +// Verify revert rules on deny +rule deny_revert(address usr) { + env e; + + mathint wardsSender = wards(e.msg.sender); + + deny@withrevert(e, usr); + + bool revert1 = e.msg.value > 0; + bool revert2 = wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting setIlkAdmin +rule setIlkAdmin(bytes32 ilk, address usr) { + env e; + + bytes32 otherBytes32; + require otherBytes32 != ilk; + + address ilkAdminsOtherBefore = ilkAdmins(otherBytes32); + + setIlkAdmin(e, ilk, usr); + + address ilkAdminsIlkAfter = ilkAdmins(ilk); + address ilkAdminsOtherAfter = ilkAdmins(otherBytes32); + + assert ilkAdminsIlkAfter == usr, "setIlkAdmin did not set ilkAdmins[ilk] to usr"; + assert ilkAdminsOtherAfter == ilkAdminsOtherBefore, "setIlkAdmin did not keep unchanged the rest of ilkAdmins[x]"; +} + +// Verify revert rules on setIlkAdmin +rule setIlkAdmin_revert(bytes32 ilk, address usr) { + env e; + + mathint wardsSender = wards(e.msg.sender); + + setIlkAdmin@withrevert(e, ilk, usr); + + bool revert1 = e.msg.value > 0; + bool revert2 = wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting setUserRole +rule setUserRole(bytes32 ilk, address who, uint8 role, bool enabled) { + env e; + + bytes32 otherBytes32; + address otherAddr; + require otherBytes32 != ilk || otherAddr != who; + + bytes32 userRolesIlkWhoBefore = userRoles(ilk, who); + bytes32 userRolesOtherBefore = userRoles(otherBytes32, otherAddr); + uint256 mask = assert_uint256(2^role); + bytes32 value = enabled ? userRolesIlkWhoBefore | to_bytes32(mask) : userRolesIlkWhoBefore & to_bytes32(bitNot(mask)); + + setUserRole(e, ilk, who, role, enabled); + + bytes32 userRolesIlkWhoAfter = userRoles(ilk, who); + bytes32 userRolesOtherAfter = userRoles(otherBytes32, otherAddr); + + assert userRolesIlkWhoAfter == value, "setUserRole did not set userRoles[ilk][who] by the corresponding value"; + assert userRolesOtherAfter == userRolesOtherBefore, "setUserRole did not keep unchanged the rest of userRoles[x][y]"; +} + +// Verify revert rules on setUserRole +rule setUserRole_revert(bytes32 ilk, address who, uint8 role, bool enabled) { + env e; + + address ilkAuthIlk = ilkAdmins(ilk); + + setUserRole@withrevert(e, ilk, who, role, enabled); + + bool revert1 = e.msg.value > 0; + bool revert2 = ilkAuthIlk != e.msg.sender; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting setRoleAction +rule setRoleAction(bytes32 ilk, uint8 role, address target, bytes4 sign, bool enabled) { + env e; + + bytes32 otherBytes32; + address otherAddr; + bytes4 otherBytes4; + require otherBytes32 != ilk || otherAddr != target || otherBytes4 != sign; + + bytes32 actionsRolesIlkTargetSigBefore = actionsRoles(ilk, target, sign); + bytes32 actionsRolesOtherBefore = actionsRoles(otherBytes32, otherAddr, otherBytes4); + uint256 mask = assert_uint256(2^role); + bytes32 value = enabled ? actionsRolesIlkTargetSigBefore | to_bytes32(mask) : actionsRolesIlkTargetSigBefore & to_bytes32(bitNot(mask)); + + setRoleAction(e, ilk, role, target, sign, enabled); + + bytes32 actionsRolesIlkTargetSigAfter = actionsRoles(ilk, target, sign); + bytes32 actionsRolesOtherAfter = actionsRoles(otherBytes32, otherAddr, otherBytes4); + + assert actionsRolesIlkTargetSigAfter == value, "setRoleAction did not set actionsRoles[ilk][target][sig] by the corresponding value"; + assert actionsRolesOtherAfter == actionsRolesOtherBefore, "setRoleAction did not keep unchanged the rest of actionsRoles[x][y][z]"; +} + +// Verify revert rules on setRoleAction +rule setRoleAction_revert(bytes32 ilk, uint8 role, address target, bytes4 sign, bool enabled) { + env e; + + address ilkAuthIlk = ilkAdmins(ilk); + + setRoleAction@withrevert(e, ilk, role, target, sign, enabled); + + bool revert1 = e.msg.value > 0; + bool revert2 = ilkAuthIlk != e.msg.sender; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct response from canCall +rule canCall(bytes32 ilk, address caller, address target, bytes4 sign) { + bool ok = userRoles(ilk, caller) & actionsRoles(ilk, target, sign) != to_bytes32(0); + + bool ok2 = canCall(ilk, caller, target, sign); + + assert ok2 == ok, "canCall did not return the expected result"; +} diff --git a/certora/AllocatorVault.conf b/certora/AllocatorVault.conf new file mode 100644 index 00000000..98118487 --- /dev/null +++ b/certora/AllocatorVault.conf @@ -0,0 +1,36 @@ +{ + "files": [ + "src/AllocatorVault.sol", + "src/AllocatorRoles.sol", + "test/mocks/VatMock.sol", + "test/mocks/JugMock.sol", + "test/mocks/NstJoinMock.sol", + "test/mocks/NstMock.sol" + ], + "link": [ + "AllocatorVault:roles=AllocatorRoles", + "AllocatorVault:vat=VatMock", + "AllocatorVault:jug=JugMock", + "AllocatorVault:nstJoin=NstJoinMock", + "AllocatorVault:nst=NstMock", + "JugMock:vat=VatMock", + "NstJoinMock:vat=VatMock", + "NstJoinMock:nst=NstMock" + ], + "rule_sanity": "basic", + "solc": "solc-0.8.16", + "solc_optimize_map": { + "AllocatorVault": "200", + "AllocatorRoles": "200", + "VatMock": "0", + "JugMock": "0", + "NstJoinMock": "0", + "NstMock": "0" + }, + "verify": "AllocatorVault:certora/AllocatorVault.spec", + "parametric_contracts": [ + "AllocatorVault" + ], + "multi_assert_check": true, + "wait_for_results": "all" +} diff --git a/certora/AllocatorVault.spec b/certora/AllocatorVault.spec new file mode 100644 index 00000000..20105b54 --- /dev/null +++ b/certora/AllocatorVault.spec @@ -0,0 +1,280 @@ +// AllocatorVault.spec + +using AllocatorRoles as roles; +using VatMock as vat; +using JugMock as jug; +using NstJoinMock as nstJoin; +using NstMock as nst; + +methods { + function ilk() external returns (bytes32) envfree; + function wards(address) external returns (uint256) envfree; + function jug() external returns (address) envfree; + function buffer() external returns (address) envfree; + function roles.canCall(bytes32, address, address, bytes4) external returns (bool) envfree; + function vat.can(address, address) external returns (uint256) envfree; + function vat.dai(address) external returns (uint256) envfree; + function vat.gem(bytes32, address) external returns (uint256) envfree; + function vat.urns(bytes32, address) external returns (uint256, uint256) envfree; + function vat.rate() external returns (uint256) envfree; + function jug.duty() external returns (uint256) envfree; + function jug.rho() external returns (uint256) envfree; + function nst.allowance(address, address) external returns (uint256) envfree; + function nst.balanceOf(address) external returns (uint256) envfree; + function nst.totalSupply() external returns (uint256) envfree; +} + +definition WAD() returns mathint = 10^18; +definition RAY() returns mathint = 10^27; +definition max_int256() returns mathint = 2^255 - 1; +definition divUp(mathint x, mathint y) returns mathint = x != 0 ? ((x - 1) / y) + 1 : 0; + +// Verify that each storage layout is only modified in the corresponding functions +rule storageAffected(method f) { + env e; + + address anyAddr; + + mathint wardsBefore = wards(anyAddr); + address jugBefore = jug(); + + calldataarg args; + f(e, args); + + mathint wardsAfter = wards(anyAddr); + address jugAfter = jug(); + + assert wardsAfter != wardsBefore => f.selector == sig:rely(address).selector || f.selector == sig:deny(address).selector, "wards[x] changed in an unexpected function"; + assert jugAfter != jugBefore => f.selector == sig:file(bytes32,address).selector, "jug changed in an unexpected function"; +} + +// Verify correct storage changes for non reverting rely +rule rely(address usr) { + env e; + + address other; + require other != usr; + + mathint wardsOtherBefore = wards(other); + + rely(e, usr); + + mathint wardsUsrAfter = wards(usr); + mathint wardsOtherAfter = wards(other); + + assert wardsUsrAfter == 1, "rely did not set the wards"; + assert wardsOtherAfter == wardsOtherBefore, "rely did not keep unchanged the rest of wards[x]"; +} + +// Verify revert rules on rely +rule rely_revert(address usr) { + env e; + + bool canCall = roles.canCall(ilk(), e.msg.sender, currentContract, to_bytes4(0x65fae35e)); + mathint wardsSender = wards(e.msg.sender); + + rely@withrevert(e, usr); + + bool revert1 = e.msg.value > 0; + bool revert2 = !canCall && wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting deny +rule deny(address usr) { + env e; + + address other; + require other != usr; + + mathint wardsOtherBefore = wards(other); + + deny(e, usr); + + mathint wardsUsrAfter = wards(usr); + mathint wardsOtherAfter = wards(other); + + assert wardsUsrAfter == 0, "deny did not set the wards"; + assert wardsOtherAfter == wardsOtherBefore, "deny did not keep unchanged the rest of wards[x]"; +} + +// Verify revert rules on deny +rule deny_revert(address usr) { + env e; + + bool canCall = roles.canCall(ilk(), e.msg.sender, currentContract, to_bytes4(0x9c52a7f1)); + mathint wardsSender = wards(e.msg.sender); + + deny@withrevert(e, usr); + + bool revert1 = e.msg.value > 0; + bool revert2 = !canCall && wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting file +rule file(bytes32 what, address data) { + env e; + + file(e, what, data); + + address jugAfter = jug(); + + assert jugAfter == data, "file did not set jug"; +} + +// Verify revert rules on file +rule file_revert(bytes32 what, address data) { + env e; + + bool canCall = roles.canCall(ilk(), e.msg.sender, currentContract, to_bytes4(0xd4e8be83)); + mathint wardsSender = wards(e.msg.sender); + + file@withrevert(e, what, data); + + bool revert1 = e.msg.value > 0; + bool revert2 = !canCall && wardsSender != 1; + bool revert3 = what != to_bytes32(0x6a75670000000000000000000000000000000000000000000000000000000000); + + assert lastReverted <=> revert1 || revert2 || revert3, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting draw +rule draw(uint256 wad) { + env e; + + mathint nstTotalSupplyBefore = nst.totalSupply(); + mathint nstBalanceOfBufferBefore = nst.balanceOf(buffer()); + require nstBalanceOfBufferBefore <= nstTotalSupplyBefore; + mathint vatInkVaultBefore; mathint vatArtVaultBefore; + vatInkVaultBefore, vatArtVaultBefore = vat.urns(ilk(), currentContract); + mathint rate = vat.rate() + (jug.duty() - RAY()) * (e.block.timestamp - jug.rho()); + require rate > 0; + mathint dart = divUp(wad * RAY(), rate); + + draw(e, wad); + + mathint nstTotalSupplyAfter = nst.totalSupply(); + mathint nstBalanceOfBufferAfter = nst.balanceOf(buffer()); + mathint vatInkVaultAfter; mathint vatArtVaultAfter; + vatInkVaultAfter, vatArtVaultAfter = vat.urns(ilk(), currentContract); + + assert vatInkVaultAfter == vatInkVaultBefore, "draw did not keep vat.urns(ilk,vault).ink unchanged"; + assert vatArtVaultAfter == vatArtVaultBefore + dart, "draw did not increase vat.urns(ilk,vault).art by dart"; + assert nstBalanceOfBufferAfter == nstBalanceOfBufferBefore + wad, "draw did not increase nst.balanceOf(buffer) by wad"; + assert nstTotalSupplyAfter == nstTotalSupplyBefore + wad, "draw did not increase nst.totalSupply() by wad"; +} + +// Verify revert rules on draw +rule draw_revert(uint256 wad) { + env e; + + bool canCall = roles.canCall(ilk(), e.msg.sender, currentContract, to_bytes4(0x3b304147)); + mathint wardsSender = wards(e.msg.sender); + mathint nstTotalSupply = nst.totalSupply(); + mathint nstBalanceOfBuffer = nst.balanceOf(buffer()); + require nstBalanceOfBuffer <= nstTotalSupply; + mathint vatInkVault; mathint vatArtVault; + vatInkVault, vatArtVault = vat.urns(ilk(), currentContract); + mathint duty = jug.duty(); + require duty >= RAY(); + mathint rho = jug.rho(); + require to_mathint(e.block.timestamp) >= rho; + mathint rate = vat.rate() + (duty - RAY()) * (e.block.timestamp - jug.rho()); + require rate > 0 && rate <= max_int256(); + mathint dart = divUp(wad * RAY(), rate); + mathint vatDaiVault = vat.dai(currentContract); + mathint vatCanVaultNstJoin = vat.can(currentContract, nstJoin); + mathint vatDaiNstJoin = vat.dai(nstJoin); + + draw@withrevert(e, wad); + + bool revert1 = e.msg.value > 0; + bool revert2 = !canCall && wardsSender != 1; + bool revert3 = wad * RAY() > max_uint256; + bool revert4 = dart > max_int256(); + bool revert5 = vatArtVault + dart > max_uint256; + bool revert6 = rate * dart > max_int256(); + bool revert7 = vatDaiVault + rate * dart > max_uint256; + bool revert8 = vatCanVaultNstJoin != 1; + bool revert9 = vatDaiNstJoin + wad * RAY() > max_uint256; + bool revert10 = nstTotalSupply + wad > max_uint256; + + assert lastReverted <=> revert1 || revert2 || revert3 || + revert4 || revert5 || revert6 || + revert7 || revert8 || revert9 || + revert10, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting wipe +rule wipe(uint256 wad) { + env e; + + mathint nstTotalSupplyBefore = nst.totalSupply(); + mathint nstBalanceOfBufferBefore = nst.balanceOf(buffer()); + require nstBalanceOfBufferBefore <= nstTotalSupplyBefore; + mathint vatInkVaultBefore; mathint vatArtVaultBefore; + vatInkVaultBefore, vatArtVaultBefore = vat.urns(ilk(), currentContract); + mathint rate = vat.rate() + (jug.duty() - RAY()) * (e.block.timestamp - jug.rho()); + require rate > 0; + mathint dart = wad * RAY() / rate; + + wipe(e, wad); + + mathint nstTotalSupplyAfter = nst.totalSupply(); + mathint nstBalanceOfBufferAfter = nst.balanceOf(buffer()); + mathint vatInkVaultAfter; mathint vatArtVaultAfter; + vatInkVaultAfter, vatArtVaultAfter = vat.urns(ilk(), currentContract); + + assert vatInkVaultAfter == vatInkVaultBefore, "wipe did not keep vat.urns(ilk,vault).ink unchanged"; + assert vatArtVaultAfter == vatArtVaultBefore - dart, "wipe did not decrease vat.urns(ilk,vault).art by dart"; + assert nstBalanceOfBufferAfter == nstBalanceOfBufferBefore - wad, "wipe did not decrease nst.balanceOf(buffer) by wad"; + assert nstTotalSupplyAfter == nstTotalSupplyBefore - wad, "wipe did not decrease nst.totalSupply() by wad"; +} + +// Verify revert rules on wipe +rule wipe_revert(uint256 wad) { + env e; + + bool canCall = roles.canCall(ilk(), e.msg.sender, currentContract, to_bytes4(0xb38a1620)); + mathint wardsSender = wards(e.msg.sender); + mathint nstTotalSupply = nst.totalSupply(); + address buffer = buffer(); + require buffer != currentContract; + mathint nstBalanceOfBuffer = nst.balanceOf(buffer); + mathint nstBalanceOfVault = nst.balanceOf(currentContract); + require nstBalanceOfBuffer + nstBalanceOfVault <= nstTotalSupply; + mathint nstAllowanceBufferVault = nst.allowance(buffer, currentContract); + mathint nstAllowanceVaultNstJoin = nst.allowance(currentContract, nstJoin); + mathint vatInkVault; mathint vatArtVault; + vatInkVault, vatArtVault = vat.urns(ilk(), currentContract); + mathint duty = jug.duty(); + require duty >= RAY(); + mathint rho = jug.rho(); + require to_mathint(e.block.timestamp) >= rho; + mathint rate = vat.rate() + (duty - RAY()) * (e.block.timestamp - jug.rho()); + require rate > 0 && rate <= max_int256(); + mathint dart = wad * RAY() / rate; + mathint vatDaiVault = vat.dai(currentContract); + mathint vatDaiNstJoin = vat.dai(nstJoin); + + wipe@withrevert(e, wad); + + bool revert1 = e.msg.value > 0; + bool revert2 = !canCall && wardsSender != 1; + bool revert3 = nstBalanceOfBuffer < to_mathint(wad); + bool revert4 = nstAllowanceBufferVault < to_mathint(wad); + bool revert5 = wad * RAY() > max_uint256; + bool revert6 = nstAllowanceVaultNstJoin < to_mathint(wad); + bool revert7 = vatArtVault < dart; + bool revert8 = vatDaiNstJoin < wad * RAY(); + bool revert9 = vatDaiVault + wad * RAY() > max_uint256; + bool revert10 = rate * dart > max_int256(); + + assert lastReverted <=> revert1 || revert2 || revert3 || + revert4 || revert5 || revert6 || + revert7 || revert8 || revert9 || + revert10, "Revert rules failed"; +} diff --git a/certora/funnels/Auxiliar.sol b/certora/funnels/Auxiliar.sol new file mode 100644 index 00000000..007ceb11 --- /dev/null +++ b/certora/funnels/Auxiliar.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.8.16; + +contract Auxiliar { + function getHash(address addr, int24 tickLower, int24 tickUpper) external pure returns (bytes32 hashC) { + hashC = keccak256(abi.encodePacked(addr, tickLower, tickUpper)); + } + + function decode(bytes calldata data) external pure returns (address gem0, address gem1, uint24 fee) { + (gem0, gem1, fee) = abi.decode(data, (address, address, uint24)); + } +} diff --git a/certora/funnels/DepositorUniV3.conf b/certora/funnels/DepositorUniV3.conf new file mode 100644 index 00000000..ae5dbe0e --- /dev/null +++ b/certora/funnels/DepositorUniV3.conf @@ -0,0 +1,28 @@ +{ + "files": [ + "src/funnels/DepositorUniV3.sol", + "src/AllocatorRoles.sol", + "test/mocks/PoolUniV3Mock.sol", + "test/mocks/Gem0Mock.sol", + "test/mocks/Gem1Mock.sol", + "certora/funnels/Auxiliar.sol" + ], + "link": [ + "DepositorUniV3:roles=AllocatorRoles" + ], + "rule_sanity": "basic", + "solc": "solc-0.8.16", + "solc_optimize_map": { + "DepositorUniV3": "200", + "AllocatorRoles": "200", + "PoolUniV3Mock": "0", + "Gem0Mock": "0", + "Gem1Mock": "0", + "Auxiliar": "0" + }, + "verify": "DepositorUniV3:certora/funnels/DepositorUniV3.spec", + "parametric_contracts": [ + "DepositorUniV3" + ], + "wait_for_results": "all" +} diff --git a/certora/funnels/DepositorUniV3.spec b/certora/funnels/DepositorUniV3.spec new file mode 100644 index 00000000..27221a6b --- /dev/null +++ b/certora/funnels/DepositorUniV3.spec @@ -0,0 +1,606 @@ +// DepositorUniV3.spec + +using AllocatorRoles as roles; +using PoolUniV3Mock as poolCon; +using Gem0Mock as gem0Con; +using Gem1Mock as gem1Con; +using Auxiliar as aux; + +methods { + function ilk() external returns (bytes32) envfree; + function buffer() external returns (address) envfree; + function wards(address) external returns (uint256) envfree; + function limits(address, address, uint24) external returns (uint96, uint96, uint32, uint96, uint96, uint32) envfree; + function _getPool(address gem0, address gem1, uint24 fee) internal returns (address) => getPoolSummary(gem0, gem1, fee); + function _getLiquidityForAmts(address pool, int24 tickLower, int24 tickUpper, uint256 amt0Desired, uint256 amt1Desired) internal returns (uint128) => getLiquidityForAmtsSummary(pool, tickLower, tickUpper, amt0Desired, amt1Desired); + function getPosition(address, address, uint24, int24, int24) external returns (uint128, uint256, uint256, uint128, uint128) envfree; + function roles.canCall(bytes32, address, address, bytes4) external returns (bool) envfree; + function _.mint(address, int24, int24, uint128, bytes) external => DISPATCHER(true); + function _.burn(int24, int24, uint128) external => DISPATCHER(true); + function _.collect(address, int24, int24, uint128, uint128) external => DISPATCHER(true); + function _.uniswapV3MintCallback(uint256, uint256, bytes) external => DISPATCHER(true); + function poolCon.gem0() external returns (address) envfree; + function poolCon.gem1() external returns (address) envfree; + function poolCon.fee() external returns (uint24) envfree; + function poolCon.random0() external returns (uint128) envfree; + function poolCon.random1() external returns (uint128) envfree; + function poolCon.random2() external returns (uint128) envfree; + function poolCon.random3() external returns (uint128) envfree; + function _.positions(bytes32) external => DISPATCHER(true); + function gem0Con.balanceOf(address) external returns (uint256) envfree; + function gem1Con.balanceOf(address) external returns (uint256) envfree; + function gem0Con.allowance(address, address) external returns (uint256) envfree; + function gem1Con.allowance(address, address) external returns (uint256) envfree; + function aux.getHash(address, int24, int24) external returns (bytes32) envfree; + function aux.decode(bytes) external returns (address, address, uint24) envfree; + function _.transfer(address, uint256) external => DISPATCHER(true) UNRESOLVED; + function _.transferFrom(address, address, uint256) external => DISPATCHER(true) UNRESOLVED; +} + +ghost mapping(address => mapping(int24 => mapping(int24 => mapping(uint256 => mapping(uint256 => uint128))))) _liquidityMap; + +function getLiquidityForAmtsSummary(address pool, int24 tickLower, int24 tickUpper, uint256 amt0Desired, uint256 amt1Desired) returns uint128 { + return _liquidityMap[pool][tickLower][tickUpper][amt0Desired][amt1Desired]; +} + +ghost mapping(address => mapping(address => mapping(uint24 => address))) _poolMap; + +function getPoolSummary(address gem0, address gem1, uint24 fee) returns address { + return _poolMap[gem0][gem1][fee]; +} + +// Verify that each storage layout is only modified in the corresponding functions +rule storageAffected(method f) { + env e; + + address anyAddr; + address anyAddr_2; + uint24 anyUint24; + + mathint wardsBefore = wards(anyAddr); + mathint cap0Before; mathint cap1Before; mathint eraBefore; mathint due0Before; mathint due1Before; mathint endBefore; + cap0Before, cap1Before, eraBefore, due0Before, due1Before, endBefore = limits(anyAddr, anyAddr_2, anyUint24); + + calldataarg args; + f(e, args); + + mathint wardsAfter = wards(anyAddr); + mathint cap0After; mathint cap1After; mathint eraAfter; mathint due0After; mathint due1After; mathint endAfter; + cap0After, cap1After, eraAfter, due0After, due1After, endAfter = limits(anyAddr, anyAddr_2, anyUint24); + + assert wardsAfter != wardsBefore => f.selector == sig:rely(address).selector || f.selector == sig:deny(address).selector, "wards[x] changed in an unexpected function"; + assert cap0After != cap0Before => f.selector == sig:setLimits(address,address,uint24,uint96,uint96,uint32).selector, "limits[x][y][z].cap0 changed in an unexpected function"; + assert cap1After != cap1Before => f.selector == sig:setLimits(address,address,uint24,uint96,uint96,uint32).selector, "limits[x][y][z].cap1 changed in an unexpected function"; + assert eraAfter != eraBefore => f.selector == sig:setLimits(address,address,uint24,uint96,uint96,uint32).selector, "limits[x][y][z].era changed in an unexpected function"; + assert due0After != due0Before => f.selector == sig:setLimits(address,address,uint24,uint96,uint96,uint32).selector || f.selector == sig:deposit(DepositorUniV3.LiquidityParams).selector || f.selector == sig:withdraw(DepositorUniV3.LiquidityParams,bool).selector, "limits[x][y][z].due0 changed in an unexpected function"; + assert due1After != due1Before => f.selector == sig:setLimits(address,address,uint24,uint96,uint96,uint32).selector || f.selector == sig:deposit(DepositorUniV3.LiquidityParams).selector || f.selector == sig:withdraw(DepositorUniV3.LiquidityParams,bool).selector, "limits[x][y][z].due1 changed in an unexpected function"; + assert endAfter != endBefore => f.selector == sig:setLimits(address,address,uint24,uint96,uint96,uint32).selector || f.selector == sig:deposit(DepositorUniV3.LiquidityParams).selector || f.selector == sig:withdraw(DepositorUniV3.LiquidityParams,bool).selector, "limits[x][y][z].end changed in an unexpected function"; +} + +// Verify correct storage changes for non reverting rely +rule rely(address usr) { + env e; + + address other; + require other != usr; + + mathint wardsOtherBefore = wards(other); + + rely(e, usr); + + mathint wardsUsrAfter = wards(usr); + mathint wardsOtherAfter = wards(other); + + assert wardsUsrAfter == 1, "rely did not set the wards"; + assert wardsOtherAfter == wardsOtherBefore, "rely did not keep unchanged the rest of wards[x]"; +} + +// Verify revert rules on rely +rule rely_revert(address usr) { + env e; + + bool canCall = roles.canCall(ilk(), e.msg.sender, currentContract, to_bytes4(0x65fae35e)); + mathint wardsSender = wards(e.msg.sender); + + rely@withrevert(e, usr); + + bool revert1 = e.msg.value > 0; + bool revert2 = !canCall && wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting deny +rule deny(address usr) { + env e; + + address other; + require other != usr; + + mathint wardsOtherBefore = wards(other); + + deny(e, usr); + + mathint wardsUsrAfter = wards(usr); + mathint wardsOtherAfter = wards(other); + + assert wardsUsrAfter == 0, "deny did not set the wards"; + assert wardsOtherAfter == wardsOtherBefore, "deny did not keep unchanged the rest of wards[x]"; +} + +// Verify revert rules on deny +rule deny_revert(address usr) { + env e; + + bool canCall = roles.canCall(ilk(), e.msg.sender, currentContract, to_bytes4(0x9c52a7f1)); + mathint wardsSender = wards(e.msg.sender); + + deny@withrevert(e, usr); + + bool revert1 = e.msg.value > 0; + bool revert2 = !canCall && wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting setLimits +rule setLimits(address gem0, address gem1, uint24 fee, uint96 cap0, uint96 cap1, uint32 era) { + env e; + + address otherAddr; + address otherAddr_2; + uint24 otherUint24; + require otherAddr != gem0 || otherAddr_2 != gem1 || otherUint24 != fee; + + mathint cap0OtherBefore; mathint cap1OtherBefore; mathint eraOtherBefore; mathint due0OtherBefore; mathint due1OtherBefore; mathint endOtherBefore; + cap0OtherBefore, cap1OtherBefore, eraOtherBefore, due0OtherBefore, due1OtherBefore, endOtherBefore = limits(otherAddr, otherAddr_2, otherUint24); + + setLimits(e, gem0, gem1, fee, cap0, cap1, era); + + mathint cap0Gem0Gem1FeeAfter; mathint cap1Gem0Gem1FeeAfter; mathint eraGem0Gem1FeeAfter; mathint due0Gem0Gem1FeeAfter; mathint due1Gem0Gem1FeeAfter; mathint endGem0Gem1FeeAfter; + cap0Gem0Gem1FeeAfter, cap1Gem0Gem1FeeAfter, eraGem0Gem1FeeAfter, due0Gem0Gem1FeeAfter, due1Gem0Gem1FeeAfter, endGem0Gem1FeeAfter = limits(gem0, gem1, fee); + mathint cap0OtherAfter; mathint cap1OtherAfter; mathint eraOtherAfter; mathint due0OtherAfter; mathint due1OtherAfter; mathint endOtherAfter; + cap0OtherAfter, cap1OtherAfter, eraOtherAfter, due0OtherAfter, due1OtherAfter, endOtherAfter = limits(otherAddr, otherAddr_2, otherUint24); + + assert cap0Gem0Gem1FeeAfter == to_mathint(cap0), "setLimits did not set limits[gem0][gem1][fee].cap0 to cap0"; + assert cap1Gem0Gem1FeeAfter == to_mathint(cap1), "setLimits did not set limits[gem0][gem1][fee].cap1 to cap1"; + assert eraGem0Gem1FeeAfter == to_mathint(era), "setLimits did not set limits[gem0][gem1][fee].era to era"; + assert due0Gem0Gem1FeeAfter == 0, "setLimits did not set limits[gem0][gem1][fee].due0 to 0"; + assert due1Gem0Gem1FeeAfter == 0, "setLimits did not set limits[gem0][gem1][fee].due1 to 0"; + assert endGem0Gem1FeeAfter == 0, "setLimits did not set limits[gem0][gem1][fee].end to 0"; + assert cap0OtherAfter == cap0OtherBefore, "setLimits did not keep unchanged the rest of limits[x][y][z].cap0"; + assert cap1OtherAfter == cap1OtherBefore, "setLimits did not keep unchanged the rest of limits[x][y][z].cap1"; + assert eraOtherAfter == eraOtherBefore, "setLimits did not keep unchanged the rest of limits[x][y][z].era"; + assert due0OtherAfter == due0OtherBefore, "setLimits did not keep unchanged the rest of limits[x][y][z].due0"; + assert due1OtherAfter == due1OtherBefore, "setLimits did not keep unchanged the rest of limits[x][y][z].due1"; + assert endOtherAfter == endOtherBefore, "setLimits did not keep unchanged the rest of limits[x][y][z].end"; +} + +// Verify revert rules on setLimits +rule setLimits_revert(address gem0, address gem1, uint24 fee, uint96 cap0, uint96 cap1, uint32 era) { + env e; + + bool canCall = roles.canCall(ilk(), e.msg.sender, currentContract, to_bytes4(0x222df168)); + mathint wardsSender = wards(e.msg.sender); + + setLimits@withrevert(e, gem0, gem1, fee, cap0, cap1, era); + + bool revert1 = e.msg.value > 0; + bool revert2 = !canCall && wardsSender != 1; + bool revert3 = gem0 >= gem1; + + assert lastReverted <=> revert1 || revert2 || revert3, "Revert rules failed"; +} + +// Verify correct response from getPosition +rule getPosition(address gem0, address gem1, uint24 fee, int24 tickLower, int24 tickUpper) { + env e; + + bytes32 hashC = aux.getHash(currentContract, tickLower, tickUpper); + mathint expLiquidity; mathint expFeeGrowthInside0LastX128; mathint expFeeGrowthInside1LastX128; mathint expTokensOwed0; mathint expTokensOwed1; + expLiquidity, expFeeGrowthInside0LastX128, expFeeGrowthInside1LastX128, expTokensOwed0, expTokensOwed1 = poolCon.positions(e, hashC); + + mathint liquidity; mathint feeGrowthInside0LastX128; mathint feeGrowthInside1LastX128; mathint tokensOwed0; mathint tokensOwed1; + liquidity, feeGrowthInside0LastX128, feeGrowthInside1LastX128, tokensOwed0, tokensOwed1 = getPosition(gem0, gem1, fee, tickLower, tickUpper); + + assert liquidity == expLiquidity, "getPosition did not return the expected liquidity value"; + assert feeGrowthInside0LastX128 == expFeeGrowthInside0LastX128, "getPosition did not return the expected feeGrowthInside0LastX128 value"; + assert feeGrowthInside1LastX128 == expFeeGrowthInside1LastX128, "getPosition did not return the expected feeGrowthInside1LastX128 value"; + assert tokensOwed0 == expTokensOwed0, "getPosition did not return the expected tokensOwed0 value"; + assert tokensOwed1 == expTokensOwed1, "getPosition did not return the expected tokensOwed1 value"; +} + +// Verify correct storage changes for non reverting uniswapV3MintCallback +rule uniswapV3MintCallback(uint256 amt0Owed, uint256 amt1Owed, bytes data) { + env e; + + address gem0; address gem1; uint24 fee; + gem0, gem1, fee = aux.decode(data); + + require gem0 == gem0Con; + require gem1 == gem1Con; + + address buffer = buffer(); + require buffer != e.msg.sender; + + mathint gem0BalanceOfBufferBefore = gem0Con.balanceOf(buffer); + mathint gem1BalanceOfBufferBefore = gem1Con.balanceOf(buffer); + mathint gem0BalanceOfSenderBefore = gem0Con.balanceOf(e.msg.sender); + mathint gem1BalanceOfSenderBefore = gem1Con.balanceOf(e.msg.sender); + + require gem0BalanceOfBufferBefore + gem0BalanceOfSenderBefore <= max_uint256; + require gem1BalanceOfBufferBefore + gem1BalanceOfSenderBefore <= max_uint256; + + uniswapV3MintCallback(e, amt0Owed, amt1Owed, data); + + mathint gem0BalanceOfBufferAfter = gem0Con.balanceOf(buffer); + mathint gem1BalanceOfBufferAfter = gem1Con.balanceOf(buffer); + mathint gem0BalanceOfSenderAfter = gem0Con.balanceOf(e.msg.sender); + mathint gem1BalanceOfSenderAfter = gem1Con.balanceOf(e.msg.sender); + + assert gem0BalanceOfBufferAfter == gem0BalanceOfBufferBefore - amt0Owed, "uniswapV3MintCallback did not decrease gem0.balanceOf(buffer) by amt0Owed"; + assert gem1BalanceOfBufferAfter == gem1BalanceOfBufferBefore - amt1Owed, "uniswapV3MintCallback did not decrease gem1.balanceOf(buffer) by amt1Owed"; + assert gem0BalanceOfSenderAfter == gem0BalanceOfSenderBefore + amt0Owed, "uniswapV3MintCallback did not increase gem0.balanceOf(pool) by amt0Owed"; + assert gem1BalanceOfSenderAfter == gem1BalanceOfSenderBefore + amt1Owed, "uniswapV3MintCallback did not increase gem1.balanceOf(pool) by amt1Owed"; +} + +// Verify revert rules on uniswapV3MintCallback +rule uniswapV3MintCallback_revert(uint256 amt0Owed, uint256 amt1Owed, bytes data) { + env e; + + address gem0; address gem1; uint24 fee; + gem0, gem1, fee = aux.decode(data); + + require gem0 == gem0Con; + require gem1 == gem1Con; + + address buffer = buffer(); + require buffer != currentContract; + require buffer != e.msg.sender; + + address pool = getPoolSummary(gem0, gem1, fee); + + mathint gem0BalanceOfBuffer = gem0Con.balanceOf(buffer); + mathint gem1BalanceOfBuffer = gem1Con.balanceOf(buffer); + mathint gem0AllowanceBufferDepositor = gem0Con.allowance(buffer, currentContract); + mathint gem1AllowanceBufferDepositor = gem1Con.allowance(buffer, currentContract); + + require gem0BalanceOfBuffer + gem0Con.balanceOf(e.msg.sender) <= max_uint256; + require gem1BalanceOfBuffer + gem1Con.balanceOf(e.msg.sender) <= max_uint256; + + uniswapV3MintCallback@withrevert(e, amt0Owed, amt1Owed, data); + + bool revert1 = e.msg.value > 0; + bool revert2 = e.msg.sender != pool; + bool revert3 = gem0BalanceOfBuffer < to_mathint(amt0Owed); + bool revert4 = gem0AllowanceBufferDepositor < to_mathint(amt0Owed); + bool revert5 = gem1BalanceOfBuffer < to_mathint(amt1Owed); + bool revert6 = gem1AllowanceBufferDepositor < to_mathint(amt1Owed); + + assert lastReverted <=> revert1 || revert2 || revert3 || + revert4 || revert5 || revert6, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting deposit +rule deposit(DepositorUniV3.LiquidityParams p) { + env e; + + require p.gem0 == gem0Con; + require p.gem1 == gem1Con; + require p.gem0 == poolCon.gem0(); + require p.gem1 == poolCon.gem1(); + require p.fee == poolCon.fee(); + + address otherAddr; + address otherAddr_2; + uint24 otherUint24; + require otherAddr != p.gem0 || otherAddr_2 != p.gem1 || otherUint24 != p.fee; + + require e.block.timestamp <= max_uint32; + + address buffer = buffer(); + require buffer != poolCon; + + mathint a; mathint b; mathint c; + + mathint cap0Gem0Gem1Fee; mathint cap1Gem0Gem1Fee; mathint eraGem0Gem1Fee; mathint due0Gem0Gem1FeeBefore; mathint due1Gem0Gem1FeeBefore; mathint endGem0Gem1FeeBefore; + cap0Gem0Gem1Fee, cap1Gem0Gem1Fee, eraGem0Gem1Fee, due0Gem0Gem1FeeBefore, due1Gem0Gem1FeeBefore, endGem0Gem1FeeBefore = limits(p.gem0, p.gem1, p.fee); + mathint due0OtherBefore; mathint due1OtherBefore; mathint endOtherBefore; + a, b, c, due0OtherBefore, due1OtherBefore, endOtherBefore = limits(otherAddr, otherAddr_2, otherUint24); + mathint gem0BalanceOfBufferBefore = gem0Con.balanceOf(buffer); + mathint gem1BalanceOfBufferBefore = gem1Con.balanceOf(buffer); + mathint gem0BalanceOfPoolBefore = gem0Con.balanceOf(poolCon); + mathint gem1BalanceOfPoolBefore = gem1Con.balanceOf(poolCon); + + require gem0BalanceOfBufferBefore + gem0BalanceOfPoolBefore <= max_uint256; + require gem1BalanceOfBufferBefore + gem1BalanceOfPoolBefore <= max_uint256; + + mathint amt0 = poolCon.random0(); + mathint amt1 = poolCon.random1(); + + mathint liquidity = p.liquidity > 0 ? p.liquidity : getLiquidityForAmtsSummary(poolCon, p.tickLower, p.tickUpper, p.amt0Desired, p.amt1Desired); + + mathint retLiq; mathint retAmt0; mathint retAmt1; + retLiq, retAmt0, retAmt1 = deposit(e, p); + + mathint due0Gem0Gem1FeeAfter; mathint due1Gem0Gem1FeeAfter; mathint endGem0Gem1FeeAfter; + a, b, c, due0Gem0Gem1FeeAfter, due1Gem0Gem1FeeAfter, endGem0Gem1FeeAfter = limits(p.gem0, p.gem1, p.fee); + mathint due0OtherAfter; mathint due1OtherAfter; mathint endOtherAfter; + a, b, c, due0OtherAfter, due1OtherAfter, endOtherAfter = limits(otherAddr, otherAddr_2, otherUint24); + mathint gem0BalanceOfBufferAfter = gem0Con.balanceOf(buffer); + mathint gem1BalanceOfBufferAfter = gem1Con.balanceOf(buffer); + mathint gem0BalanceOfPoolAfter = gem0Con.balanceOf(poolCon); + mathint gem1BalanceOfPoolAfter = gem1Con.balanceOf(poolCon); + + mathint expectedDue0 = (to_mathint(e.block.timestamp) >= endGem0Gem1FeeBefore ? cap0Gem0Gem1Fee : due0Gem0Gem1FeeBefore) - amt0; + mathint expectedDue1 = (to_mathint(e.block.timestamp) >= endGem0Gem1FeeBefore ? cap1Gem0Gem1Fee : due1Gem0Gem1FeeBefore) - amt1; + mathint expectedEnd = to_mathint(e.block.timestamp) >= endGem0Gem1FeeBefore ? e.block.timestamp + eraGem0Gem1Fee : endGem0Gem1FeeBefore; + + assert due0Gem0Gem1FeeAfter == expectedDue0, "deposit did not set limits[gem0][gem1][fee].due0 to the expected value"; + assert due1Gem0Gem1FeeAfter == expectedDue1, "deposit did not set limits[gem0][gem1][fee].due1 to the expected value"; + assert endGem0Gem1FeeAfter == expectedEnd, "deposit did not set limits[gem0][gem1][fee].end to the expected value"; + assert due0OtherAfter == due0OtherBefore, "deposit did not keep unchanged the rest of limits[x][y][z].due0"; + assert due1OtherAfter == due1OtherBefore, "deposit did not keep unchanged the rest of limits[x][y][z].due1"; + assert endOtherAfter == endOtherBefore, "deposit did not keep unchanged the rest of limits[x][y][z].end"; + assert gem0BalanceOfBufferAfter == gem0BalanceOfBufferBefore - amt0, "deposit did not decrease gem0.balanceOf(buffer) by amt0"; + assert gem1BalanceOfBufferAfter == gem1BalanceOfBufferBefore - amt1, "deposit did not decrease gem1.balanceOf(buffer) by amt1"; + assert gem0BalanceOfPoolAfter == gem0BalanceOfPoolBefore + amt0, "deposit did not increase gem0.balanceOf(pool) by amt0"; + assert gem1BalanceOfPoolAfter == gem1BalanceOfPoolBefore + amt1, "deposit did not increase gem1.balanceOf(pool) by amt1"; + assert retLiq == liquidity, "deposit did not return the expected liquidity"; + assert retAmt0 == amt0, "deposit did not return the expected amt0"; + assert retAmt1 == amt1, "deposit did not return the expected amt1"; +} + +// Verify revert rules on deposit +rule deposit_revert(DepositorUniV3.LiquidityParams p) { + env e; + + require p.gem0 == gem0Con; + require p.gem1 == gem1Con; + require p.gem0 == poolCon.gem0(); + require p.gem1 == poolCon.gem1(); + require p.fee == poolCon.fee(); + + require e.block.timestamp <= max_uint32; + + address buffer = buffer(); + require buffer != currentContract; + require buffer != poolCon; + + bool canCall = roles.canCall(ilk(), e.msg.sender, currentContract, to_bytes4(0xc82cb114)); + mathint wardsSender = wards(e.msg.sender); + mathint cap0Gem0Gem1Fee; mathint cap1Gem0Gem1Fee; mathint eraGem0Gem1Fee; mathint due0Gem0Gem1Fee; mathint due1Gem0Gem1Fee; mathint endGem0Gem1Fee; + cap0Gem0Gem1Fee, cap1Gem0Gem1Fee, eraGem0Gem1Fee, due0Gem0Gem1Fee, due1Gem0Gem1Fee, endGem0Gem1Fee = limits(p.gem0, p.gem1, p.fee); + mathint amt0 = poolCon.random0(); + mathint amt1 = poolCon.random1(); + mathint gem0AllowanceBufferDepositor = gem0Con.allowance(buffer, currentContract); + mathint gem0BalanceOfBuffer = gem0Con.balanceOf(buffer); + mathint gem1AllowanceBufferDepositor = gem1Con.allowance(buffer, currentContract); + mathint gem1BalanceOfBuffer = gem1Con.balanceOf(buffer); + mathint due0Updated = to_mathint(e.block.timestamp) >= endGem0Gem1Fee ? cap0Gem0Gem1Fee : due0Gem0Gem1Fee; + mathint due1Updated = to_mathint(e.block.timestamp) >= endGem0Gem1Fee ? cap1Gem0Gem1Fee : due1Gem0Gem1Fee; + + deposit@withrevert(e, p); + + bool revert1 = e.msg.value > 0; + bool revert2 = !canCall && wardsSender != 1; + bool revert3 = p.gem0 >= p.gem1; + bool revert4 = to_mathint(e.block.timestamp) >= endGem0Gem1Fee && e.block.timestamp + eraGem0Gem1Fee > max_uint32; + bool revert5 = gem0AllowanceBufferDepositor < amt0; + bool revert6 = gem0BalanceOfBuffer < amt0; + bool revert7 = gem1AllowanceBufferDepositor < amt1; + bool revert8 = gem1BalanceOfBuffer < amt1; + bool revert9 = amt0 < to_mathint(p.amt0Min) || amt1 < to_mathint(p.amt1Min); + bool revert10 = amt0 > due0Updated || amt1 > due1Updated; + + assert lastReverted <=> revert1 || revert2 || revert3 || + revert4 || revert5 || revert6 || + revert7 || revert8 || revert9 || + revert10, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting withdraw +rule withdraw(DepositorUniV3.LiquidityParams p, bool takeFees) { + env e; + + require p.gem0 == gem0Con; + require p.gem1 == gem1Con; + require p.gem0 == poolCon.gem0(); + require p.gem1 == poolCon.gem1(); + require p.fee == poolCon.fee(); + + require poolCon.random2() >= poolCon.random0(); + require poolCon.random3() >= poolCon.random1(); + + address otherAddr; + address otherAddr_2; + uint24 otherUint24; + require otherAddr != p.gem0 || otherAddr_2 != p.gem1 || otherUint24 != p.fee; + + require e.block.timestamp <= max_uint32; + + address buffer = buffer(); + require buffer != poolCon; + + mathint a; mathint b; mathint c; + + mathint cap0Gem0Gem1Fee; mathint cap1Gem0Gem1Fee; mathint eraGem0Gem1Fee; mathint due0Gem0Gem1FeeBefore; mathint due1Gem0Gem1FeeBefore; mathint endGem0Gem1FeeBefore; + cap0Gem0Gem1Fee, cap1Gem0Gem1Fee, eraGem0Gem1Fee, due0Gem0Gem1FeeBefore, due1Gem0Gem1FeeBefore, endGem0Gem1FeeBefore = limits(p.gem0, p.gem1, p.fee); + mathint cap0OtherBefore; mathint cap1OtherBefore; mathint eraOtherBefore; mathint due0OtherBefore; mathint due1OtherBefore; mathint endOtherBefore; + a, b, c, due0OtherBefore, due1OtherBefore, endOtherBefore = limits(otherAddr, otherAddr_2, otherUint24); + mathint gem0BalanceOfBufferBefore = gem0Con.balanceOf(buffer); + mathint gem1BalanceOfBufferBefore = gem1Con.balanceOf(buffer); + mathint gem0BalanceOfPoolBefore = gem0Con.balanceOf(poolCon); + mathint gem1BalanceOfPoolBefore = gem1Con.balanceOf(poolCon); + + require gem0BalanceOfBufferBefore + gem0BalanceOfPoolBefore <= max_uint256; + require gem1BalanceOfBufferBefore + gem1BalanceOfPoolBefore <= max_uint256; + + mathint amt0 = poolCon.random0(); + mathint amt1 = poolCon.random1(); + mathint col0 = takeFees ? poolCon.random2() : amt0; + mathint col1 = takeFees ? poolCon.random3() : amt1; + + mathint liquidity = p.liquidity > 0 ? p.liquidity : getLiquidityForAmtsSummary(poolCon, p.tickLower, p.tickUpper, p.amt0Desired, p.amt1Desired); + + mathint retLiq; mathint retAmt0; mathint retAmt1; mathint retFees0; mathint retFees1; + retLiq, retAmt0, retAmt1, retFees0, retFees1 = withdraw(e, p, takeFees); + + mathint due0Gem0Gem1FeeAfter; mathint due1Gem0Gem1FeeAfter; mathint endGem0Gem1FeeAfter; + a, b, c, due0Gem0Gem1FeeAfter, due1Gem0Gem1FeeAfter, endGem0Gem1FeeAfter = limits(p.gem0, p.gem1, p.fee); + mathint due0OtherAfter; mathint due1OtherAfter; mathint endOtherAfter; + a, b, c, due0OtherAfter, due1OtherAfter, endOtherAfter = limits(otherAddr, otherAddr_2, otherUint24); + mathint gem0BalanceOfBufferAfter = gem0Con.balanceOf(buffer); + mathint gem1BalanceOfBufferAfter = gem1Con.balanceOf(buffer); + mathint gem0BalanceOfPoolAfter = gem0Con.balanceOf(poolCon); + mathint gem1BalanceOfPoolAfter = gem1Con.balanceOf(poolCon); + + mathint expectedDue0 = (to_mathint(e.block.timestamp) >= endGem0Gem1FeeBefore ? cap0Gem0Gem1Fee : due0Gem0Gem1FeeBefore) - amt0; + mathint expectedDue1 = (to_mathint(e.block.timestamp) >= endGem0Gem1FeeBefore ? cap1Gem0Gem1Fee : due1Gem0Gem1FeeBefore) - amt1; + mathint expectedEnd = to_mathint(e.block.timestamp) >= endGem0Gem1FeeBefore ? e.block.timestamp + eraGem0Gem1Fee : endGem0Gem1FeeBefore; + + assert due0Gem0Gem1FeeAfter == expectedDue0, "withdraw did not set limits[gem0][gem1][fee].due0 to the expected value"; + assert due1Gem0Gem1FeeAfter == expectedDue1, "withdraw did not set limits[gem0][gem1][fee].due1 to the expected value"; + assert endGem0Gem1FeeAfter == expectedEnd, "withdraw did not set limits[gem0][gem1][fee].end to the expected value"; + assert due0OtherAfter == due0OtherBefore, "withdraw did not keep unchanged the rest of limits[x][y][z].due0"; + assert due1OtherAfter == due1OtherBefore, "withdraw did not keep unchanged the rest of limits[x][y][z].due1"; + assert endOtherAfter == endOtherBefore, "withdraw did not keep unchanged the rest of limits[x][y][z].end"; + assert gem0BalanceOfBufferAfter == gem0BalanceOfBufferBefore + col0, "withdraw did not increase gem0.balanceOf(buffer) by col0"; + assert gem1BalanceOfBufferAfter == gem1BalanceOfBufferBefore + col1, "withdraw did not increase gem1.balanceOf(buffer) by col1"; + assert gem0BalanceOfPoolAfter == gem0BalanceOfPoolBefore - col0, "withdraw did not decrease gem0.balanceOf(pool) by col0"; + assert gem1BalanceOfPoolAfter == gem1BalanceOfPoolBefore - col1, "withdraw did not decrease gem1.balanceOf(pool) by col1"; + assert retLiq == liquidity, "withdraw did not return the expected liquidity"; + assert retAmt0 == amt0, "withdraw did not return the expected amt0"; + assert retAmt1 == amt1, "withdraw did not return the expected amt1"; + assert retFees0 == col0 - amt0, "withdraw did not return the expected col0 - amt0"; + assert retFees1 == col1 - amt1, "withdraw did not return the expected col1 - amt1"; +} + +// Verify revert rules on withdraw +rule withdraw_revert(DepositorUniV3.LiquidityParams p, bool takeFees) { + env e; + + require p.gem0 == gem0Con; + require p.gem1 == gem1Con; + require p.gem0 == poolCon.gem0(); + require p.gem1 == poolCon.gem1(); + require p.fee == poolCon.fee(); + + require poolCon.random2() >= poolCon.random0(); + require poolCon.random3() >= poolCon.random1(); + + require e.block.timestamp <= max_uint32; + + address buffer = buffer(); + require buffer != currentContract; + require buffer != poolCon; + + bool canCall = roles.canCall(ilk(), e.msg.sender, currentContract, to_bytes4(0xcd8e305c)); + mathint wardsSender = wards(e.msg.sender); + mathint cap0Gem0Gem1Fee; mathint cap1Gem0Gem1Fee; mathint eraGem0Gem1Fee; mathint due0Gem0Gem1Fee; mathint due1Gem0Gem1Fee; mathint endGem0Gem1Fee; + cap0Gem0Gem1Fee, cap1Gem0Gem1Fee, eraGem0Gem1Fee, due0Gem0Gem1Fee, due1Gem0Gem1Fee, endGem0Gem1Fee = limits(p.gem0, p.gem1, p.fee); + mathint amt0 = poolCon.random0(); + mathint amt1 = poolCon.random1(); + mathint col0 = takeFees ? poolCon.random2() : amt0; + mathint col1 = takeFees ? poolCon.random3() : amt1; + mathint gem0BalanceOfPool = gem0Con.balanceOf(poolCon); + mathint gem1BalanceOfPool = gem1Con.balanceOf(poolCon); + require gem0BalanceOfPool >= col0; + require gem1BalanceOfPool >= col1; + mathint due0Updated = to_mathint(e.block.timestamp) >= endGem0Gem1Fee ? cap0Gem0Gem1Fee : due0Gem0Gem1Fee; + mathint due1Updated = to_mathint(e.block.timestamp) >= endGem0Gem1Fee ? cap1Gem0Gem1Fee : due1Gem0Gem1Fee; + + withdraw@withrevert(e, p, takeFees); + + bool revert1 = e.msg.value > 0; + bool revert2 = !canCall && wardsSender != 1; + bool revert3 = p.gem0 >= p.gem1; + bool revert4 = to_mathint(e.block.timestamp) >= endGem0Gem1Fee && e.block.timestamp + eraGem0Gem1Fee > max_uint32; + bool revert5 = amt0 < to_mathint(p.amt0Min) || amt1 < to_mathint(p.amt1Min); + bool revert6 = amt0 > due0Updated || amt1 > due1Updated; + + assert lastReverted <=> revert1 || revert2 || revert3 || + revert4 || revert5 || revert6, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting collect +rule collect(DepositorUniV3.CollectParams p) { + env e; + + require p.gem0 == gem0Con; + require p.gem1 == gem1Con; + require p.gem0 == poolCon.gem0(); + require p.gem1 == poolCon.gem1(); + require p.fee == poolCon.fee(); + + require poolCon.random2() >= poolCon.random0(); + require poolCon.random3() >= poolCon.random1(); + + require e.block.timestamp <= max_uint32; + + address buffer = buffer(); + require buffer != poolCon; + + mathint gem0BalanceOfBufferBefore = gem0Con.balanceOf(buffer); + mathint gem1BalanceOfBufferBefore = gem1Con.balanceOf(buffer); + mathint gem0BalanceOfPoolBefore = gem0Con.balanceOf(poolCon); + mathint gem1BalanceOfPoolBefore = gem1Con.balanceOf(poolCon); + + require gem0BalanceOfBufferBefore + gem0BalanceOfPoolBefore <= max_uint256; + require gem1BalanceOfBufferBefore + gem1BalanceOfPoolBefore <= max_uint256; + + mathint fees0 = poolCon.random2(); + mathint fees1 = poolCon.random3(); + + mathint retFees0; mathint retFees1; + retFees0, retFees1 = collect(e, p); + + mathint gem0BalanceOfBufferAfter = gem0Con.balanceOf(buffer); + mathint gem1BalanceOfBufferAfter = gem1Con.balanceOf(buffer); + mathint gem0BalanceOfPoolAfter = gem0Con.balanceOf(poolCon); + mathint gem1BalanceOfPoolAfter = gem1Con.balanceOf(poolCon); + + assert gem0BalanceOfBufferAfter == gem0BalanceOfBufferBefore + fees0, "collect did not increase gem0.balanceOf(buffer) by fees0"; + assert gem1BalanceOfBufferAfter == gem1BalanceOfBufferBefore + fees1, "collect did not increase gem1.balanceOf(buffer) by fees1"; + assert gem0BalanceOfPoolAfter == gem0BalanceOfPoolBefore - fees0, "collect did not decrease gem0.balanceOf(pool) by fees0"; + assert gem1BalanceOfPoolAfter == gem1BalanceOfPoolBefore - fees1, "collect did not decrease gem1.balanceOf(pool) by fees1"; + assert retFees0 == fees0, "collect did not return the expected fees0"; + assert retFees1 == fees1, "collect did not return the expected fees1"; +} + +// Verify revert rules on collect +rule collect_revert(DepositorUniV3.CollectParams p) { + env e; + + require p.gem0 == gem0Con; + require p.gem1 == gem1Con; + require p.gem0 == poolCon.gem0(); + require p.gem1 == poolCon.gem1(); + require p.fee == poolCon.fee(); + + require poolCon.random2() >= poolCon.random0(); + require poolCon.random3() >= poolCon.random1(); + + require e.block.timestamp <= max_uint32; + + address buffer = buffer(); + require buffer != currentContract; + require buffer != poolCon; + + bool canCall = roles.canCall(ilk(), e.msg.sender, currentContract, to_bytes4(0x4ead5ba3)); + mathint wardsSender = wards(e.msg.sender); + mathint fees0 = poolCon.random2(); + mathint fees1 = poolCon.random3(); + mathint gem0BalanceOfPool = gem0Con.balanceOf(poolCon); + mathint gem1BalanceOfPool = gem1Con.balanceOf(poolCon); + require gem0BalanceOfPool >= fees0; + require gem1BalanceOfPool >= fees1; + + collect@withrevert(e, p); + + bool revert1 = e.msg.value > 0; + bool revert2 = !canCall && wardsSender != 1; + bool revert3 = p.gem0 >= p.gem1; + + assert lastReverted <=> revert1 || revert2 || revert3, "Revert rules failed"; +} diff --git a/certora/funnels/Swapper.conf b/certora/funnels/Swapper.conf new file mode 100644 index 00000000..5af6980f --- /dev/null +++ b/certora/funnels/Swapper.conf @@ -0,0 +1,26 @@ +{ + "files": [ + "src/funnels/Swapper.sol", + "src/AllocatorRoles.sol", + "test/mocks/Gem0Mock.sol", + "test/mocks/Gem1Mock.sol", + "test/mocks/CalleeMock.sol" + ], + "link": [ + "Swapper:roles=AllocatorRoles" + ], + "rule_sanity": "basic", + "solc": "solc-0.8.16", + "solc_optimize_map": { + "Swapper": "200", + "AllocatorRoles": "200", + "Gem0Mock": "0", + "Gem1Mock": "0", + "CalleeMock": "0" + }, + "verify": "Swapper:certora/funnels/Swapper.spec", + "parametric_contracts": [ + "Swapper" + ], + "wait_for_results": "all" +} diff --git a/certora/funnels/Swapper.spec b/certora/funnels/Swapper.spec new file mode 100644 index 00000000..8eeda42c --- /dev/null +++ b/certora/funnels/Swapper.spec @@ -0,0 +1,243 @@ +// Swapper.spec + +using AllocatorRoles as roles; +using Gem0Mock as srcCon; +using Gem1Mock as dstCon; +using CalleeMock as calleeCon; + +methods { + function ilk() external returns (bytes32) envfree; + function buffer() external returns (address) envfree; + function wards(address) external returns (uint256) envfree; + function limits(address, address) external returns (uint96, uint32, uint96, uint32) envfree; + function roles.canCall(bytes32, address, address, bytes4) external returns (bool) envfree; + function _.swapCallback(address, address, uint256, uint256, address, bytes) external => DISPATCHER(true) UNRESOLVED; + function _.allowance(address, address) external => DISPATCHER(true) UNRESOLVED; + function _.balanceOf(address) external => DISPATCHER(true) UNRESOLVED; + function _.transfer(address, uint256) external => DISPATCHER(true) UNRESOLVED; + function _.transferFrom(address, address, uint256) external => DISPATCHER(true) UNRESOLVED; +} + +// Verify that each storage layout is only modified in the corresponding functions +rule storageAffected(method f) { + env e; + + address anyAddr; + address anyAddr_2; + + mathint wardsBefore = wards(anyAddr); + mathint capBefore; mathint eraBefore; mathint dueBefore; mathint endBefore; + capBefore, eraBefore, dueBefore, endBefore = limits(anyAddr, anyAddr_2); + + calldataarg args; + f(e, args); + + mathint wardsAfter = wards(anyAddr); + mathint capAfter; mathint eraAfter; mathint dueAfter; mathint endAfter; + capAfter, eraAfter, dueAfter, endAfter = limits(anyAddr, anyAddr_2); + + assert wardsAfter != wardsBefore => f.selector == sig:rely(address).selector || f.selector == sig:deny(address).selector, "wards[x] changed in an unexpected function"; + assert capAfter != capBefore => f.selector == sig:setLimits(address,address,uint96,uint32).selector, "limits[x][y].cap changed in an unexpected function"; + assert eraAfter != eraBefore => f.selector == sig:setLimits(address,address,uint96,uint32).selector, "limits[x][y].era changed in an unexpected function"; + assert dueAfter != dueBefore => f.selector == sig:setLimits(address,address,uint96,uint32).selector || f.selector == sig:swap(address,address,uint256,uint256,address,bytes).selector, "limits[x][y].due changed in an unexpected function"; + assert endAfter != endBefore => f.selector == sig:setLimits(address,address,uint96,uint32).selector || f.selector == sig:swap(address,address,uint256,uint256,address,bytes).selector, "limits[x][y].end changed in an unexpected function"; +} + +// Verify correct storage changes for non reverting rely +rule rely(address usr) { + env e; + + address other; + require other != usr; + + mathint wardsOtherBefore = wards(other); + + rely(e, usr); + + mathint wardsUsrAfter = wards(usr); + mathint wardsOtherAfter = wards(other); + + assert wardsUsrAfter == 1, "rely did not set the wards"; + assert wardsOtherAfter == wardsOtherBefore, "rely did not keep unchanged the rest of wards[x]"; +} + +// Verify revert rules on rely +rule rely_revert(address usr) { + env e; + + bool canCall = roles.canCall(ilk(), e.msg.sender, currentContract, to_bytes4(0x65fae35e)); + mathint wardsSender = wards(e.msg.sender); + + rely@withrevert(e, usr); + + bool revert1 = e.msg.value > 0; + bool revert2 = !canCall && wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting deny +rule deny(address usr) { + env e; + + address other; + require other != usr; + + mathint wardsOtherBefore = wards(other); + + deny(e, usr); + + mathint wardsUsrAfter = wards(usr); + mathint wardsOtherAfter = wards(other); + + assert wardsUsrAfter == 0, "deny did not set the wards"; + assert wardsOtherAfter == wardsOtherBefore, "deny did not keep unchanged the rest of wards[x]"; +} + +// Verify revert rules on deny +rule deny_revert(address usr) { + env e; + + bool canCall = roles.canCall(ilk(), e.msg.sender, currentContract, to_bytes4(0x9c52a7f1)); + mathint wardsSender = wards(e.msg.sender); + + deny@withrevert(e, usr); + + bool revert1 = e.msg.value > 0; + bool revert2 = !canCall && wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting setLimits +rule setLimits(address src, address dst, uint96 cap, uint32 era) { + env e; + + address otherAddr; + address otherAddr_2; + require otherAddr != src || otherAddr_2 != dst; + + mathint capOtherBefore; mathint eraOtherBefore; mathint dueOtherBefore; mathint endOtherBefore; + capOtherBefore, eraOtherBefore, dueOtherBefore, endOtherBefore = limits(otherAddr, otherAddr_2); + + setLimits(e, src, dst, cap, era); + + mathint capSrcDstAfter; mathint eraSrcDstAfter; mathint dueSrcDstAfter; mathint endSrcDstAfter; + capSrcDstAfter, eraSrcDstAfter, dueSrcDstAfter, endSrcDstAfter = limits(src, dst); + mathint capOtherAfter; mathint eraOtherAfter; mathint dueOtherAfter; mathint endOtherAfter; + capOtherAfter, eraOtherAfter, dueOtherAfter, endOtherAfter = limits(otherAddr, otherAddr_2); + + assert capSrcDstAfter == to_mathint(cap), "setLimits did not set limits[src][dst].cap to cap"; + assert eraSrcDstAfter == to_mathint(era), "setLimits did not set limits[src][dst].era to era"; + assert dueSrcDstAfter == 0, "setLimits did not set limits[src][dst].due to 0"; + assert endSrcDstAfter == 0, "setLimits did not set limits[src][dst].end to 0"; + assert capOtherAfter == capOtherBefore, "setLimits did not keep unchanged the rest of limits[x][y].cap"; + assert eraOtherAfter == eraOtherBefore, "setLimits did not keep unchanged the rest of limits[x][y].era"; + assert dueOtherAfter == dueOtherBefore, "setLimits did not keep unchanged the rest of limits[x][y].due"; + assert endOtherAfter == endOtherBefore, "setLimits did not keep unchanged the rest of limits[x][y].end"; +} + +// Verify revert rules on setLimits +rule setLimits_revert(address src, address dst, uint96 cap, uint32 era) { + env e; + + bool canCall = roles.canCall(ilk(), e.msg.sender, currentContract, to_bytes4(0xf1b8ac2e)); + mathint wardsSender = wards(e.msg.sender); + + setLimits@withrevert(e, src, dst, cap, era); + + bool revert1 = e.msg.value > 0; + bool revert2 = !canCall && wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting swap +rule swap(address src, address dst, uint256 amt, uint256 minOut, address callee, bytes data) { + env e; + + require src == srcCon; + require dst == dstCon; + require callee == calleeCon; + + address otherAddr; + address otherAddr_2; + require otherAddr != src || otherAddr_2 != dst; + + require e.block.timestamp <= max_uint32; + + address buffer = buffer(); + require buffer != currentContract; + require buffer != callee; + + mathint a; mathint b; + + mathint cap; mathint era; mathint dueBefore; mathint endBefore; + cap, era, dueBefore, endBefore = limits(src, dst); + mathint dueOtherBefore; mathint endOtherBefore; + a, b, dueOtherBefore, endOtherBefore = limits(otherAddr, otherAddr_2); + mathint srcBalanceOfBufferBefore = srcCon.balanceOf(e, buffer); + mathint dstBalanceOfBufferBefore = dstCon.balanceOf(e, buffer); + + require dstBalanceOfBufferBefore + dstCon.balanceOf(e, currentContract) + dstCon.balanceOf(e, callee) <= max_uint256; + + swap(e, src, dst, amt, minOut, callee, data); + + mathint dueAfter; mathint endAfter; + a, b, dueAfter, endAfter = limits(src, dst); + mathint dueOtherAfter; mathint endOtherAfter; + a, b, dueOtherAfter, endOtherAfter = limits(otherAddr, otherAddr_2); + + mathint expectedDue = (to_mathint(e.block.timestamp) >= endBefore ? cap : dueBefore) - amt; + mathint expectedEnd = to_mathint(e.block.timestamp) >= endBefore ? e.block.timestamp + era : endBefore; + mathint srcBalanceOfBufferAfter = srcCon.balanceOf(e, buffer); + mathint dstBalanceOfBufferAfter = dstCon.balanceOf(e, buffer); + + assert dueAfter == expectedDue, "swap did not set limits[src][dst].due to expected value"; + assert endAfter == expectedEnd, "swap did not set limits[src][dst].end to expected value"; + assert dueOtherAfter == dueOtherBefore, "swap did not keep unchanged the rest of limits[x][y].due"; + assert endOtherAfter == endOtherBefore, "swap did not keep unchanged the rest of limits[x][y].end"; + assert srcBalanceOfBufferAfter == srcBalanceOfBufferBefore - amt, "swap did not decrease src.balanceOf(buffer) by amt"; + assert dstBalanceOfBufferAfter >= dstBalanceOfBufferBefore + minOut, "swap did not increase dst.balanceOf(buffer) by at least minOut"; +} + +// Verify revert rules on swap +rule swap_revert(address src, address dst, uint256 amt, uint256 minOut, address callee, bytes data) { + env e; + + require src == srcCon; + require dst == dstCon; + require callee == calleeCon; + + require data.length < max_uint32; + require e.block.timestamp <= max_uint32; + + address buffer = buffer(); + require buffer != currentContract; + + bool canCall = roles.canCall(ilk(), e.msg.sender, currentContract, to_bytes4(0xb69cbf9f)); + mathint wardsSender = wards(e.msg.sender); + mathint cap; mathint era; mathint due; mathint end; + cap, era, due, end = limits(src, dst); + mathint dueUpdated = to_mathint(e.block.timestamp) >= end ? cap : due; + mathint srcBalanceOfBuffer = srcCon.balanceOf(e, buffer); + mathint srcAllowanceBufferSwapper = srcCon.allowance(e, buffer, currentContract); + mathint dstBalanceOfBuffer = dstCon.balanceOf(e, buffer); + mathint dstBalanceOfSwapper = dstCon.balanceOf(e, currentContract); + mathint dstBalanceOfCallee = dstCon.balanceOf(e, callee); + require dstBalanceOfBuffer + dstBalanceOfSwapper + dstBalanceOfCallee <= max_uint256; + + swap@withrevert(e, src, dst, amt, minOut, callee, data); + + bool revert1 = e.msg.value > 0; + bool revert2 = !canCall && wardsSender != 1; + bool revert3 = to_mathint(e.block.timestamp) >= end && e.block.timestamp + era > max_uint32; + bool revert4 = to_mathint(amt) > dueUpdated; + bool revert5 = srcBalanceOfBuffer < to_mathint(amt); + bool revert6 = srcAllowanceBufferSwapper < to_mathint(amt); + bool revert7 = dstBalanceOfSwapper + dstBalanceOfCallee < to_mathint(minOut); + + assert lastReverted <=> revert1 || revert2 || revert3 || + revert4 || revert5 || revert6 || + revert7, "Revert rules failed"; +} diff --git a/certora/funnels/automation/ConduitMover.conf b/certora/funnels/automation/ConduitMover.conf new file mode 100644 index 00000000..7456aece --- /dev/null +++ b/certora/funnels/automation/ConduitMover.conf @@ -0,0 +1,10 @@ +{ + "files": [ + "src/funnels/automation/ConduitMover.sol" + ], + "rule_sanity": "basic", + "solc": "solc-0.8.16", + "solc_optimize": "200", + "verify": "ConduitMover:certora/funnels/automation/ConduitMover.spec", + "wait_for_results": "all" +} diff --git a/certora/funnels/automation/ConduitMover.spec b/certora/funnels/automation/ConduitMover.spec new file mode 100644 index 00000000..a9315a27 --- /dev/null +++ b/certora/funnels/automation/ConduitMover.spec @@ -0,0 +1,334 @@ +// ConduitMover.spec + +methods { + function wards(address) external returns (uint256) envfree; + function buds(address) external returns (uint256) envfree; + function configs(address, address, address) external returns (uint64, uint32, uint32, uint128) envfree; + function ilk() external returns (bytes32) envfree; + function buffer() external returns (address) envfree; + function _.withdraw(bytes32 ilk, address gem, uint256 amount) external => withdrawSummary(calledContract, ilk, gem, amount) expect uint256; + function _.deposit(bytes32 ilk, address gem, uint256 amount) external => depositSummary(calledContract, ilk, gem, amount) expect bool; // Forcing to have a return value as otherwise Certora will throw a compiler error +} + +ghost mapping(address => bool) nonZeroExtcodesize; +hook EXTCODESIZE(address addr) uint v { + nonZeroExtcodesize[addr] = (v != 0); +} + +ghost mathint withdrawCounter; +ghost address withdrawAddr; +ghost bytes32 withdrawIlk; +ghost address withdrawGem; +ghost uint256 withdrawAmount; +ghost uint256 withdrawReturn; +function withdrawSummary(address addr, bytes32 ilk, address gem, uint256 amount) returns uint256 { + withdrawCounter = withdrawCounter + 1; + withdrawAddr = addr; + withdrawIlk = ilk; + withdrawGem = gem; + withdrawAmount = amount; + return withdrawReturn; +} + +ghost mathint depositCounter; +ghost address depositAddr; +ghost bytes32 depositIlk; +ghost address depositGem; +ghost uint256 depositAmount; +function depositSummary(address addr, bytes32 ilk, address gem, uint256 amount) returns bool { + depositCounter = depositCounter + 1; + depositAddr = addr; + depositIlk = ilk; + depositGem = gem; + depositAmount = amount; + return true; +} + +// Verify that each storage layout is only modified in the corresponding functions +rule storageAffected(method f) { + env e; + + address anyAddr; + address anyAddr_2; + address anyAddr_3; + + mathint wardsBefore = wards(anyAddr); + mathint budsBefore = buds(anyAddr); + mathint numBefore; mathint hopBefore; mathint zzzBefore; mathint lotBefore; + numBefore, hopBefore, zzzBefore, lotBefore = configs(anyAddr, anyAddr_2, anyAddr_3); + + calldataarg args; + f(e, args); + + mathint wardsAfter = wards(anyAddr); + mathint budsAfter = buds(anyAddr); + mathint numAfter; mathint hopAfter; mathint zzzAfter; mathint lotAfter; + numAfter, hopAfter, zzzAfter, lotAfter = configs(anyAddr, anyAddr_2, anyAddr_3); + + assert wardsAfter != wardsBefore => f.selector == sig:rely(address).selector || f.selector == sig:deny(address).selector, "wards[x] changed in an unexpected function"; + assert budsAfter != budsBefore => f.selector == sig:kiss(address).selector || f.selector == sig:diss(address).selector, "buds[x] changed in an unexpected function"; + assert numAfter != numBefore => f.selector == sig:setConfig(address,address,address,uint64,uint32,uint128).selector || f.selector == sig:move(address,address,address).selector, "configs[x][y][z].num changed in an unexpected function"; + assert hopAfter != hopBefore => f.selector == sig:setConfig(address,address,address,uint64,uint32,uint128).selector, "configs[x][y][z].hop changed in an unexpected function"; + assert zzzAfter != zzzBefore => f.selector == sig:setConfig(address,address,address,uint64,uint32,uint128).selector || f.selector == sig:move(address,address,address).selector, "configs[x][y][z].zzz changed in an unexpected function"; + assert lotAfter != lotBefore => f.selector == sig:setConfig(address,address,address,uint64,uint32,uint128).selector, "configs[x][y][z].lot changed in an unexpected function"; +} + +// Verify correct storage changes for non reverting rely +rule rely(address usr) { + env e; + + address other; + require other != usr; + + mathint wardsOtherBefore = wards(other); + + rely(e, usr); + + mathint wardsUsrAfter = wards(usr); + mathint wardsOtherAfter = wards(other); + + assert wardsUsrAfter == 1, "rely did not set the wards"; + assert wardsOtherAfter == wardsOtherBefore, "rely did not keep unchanged the rest of wards[x]"; +} + +// Verify revert rules on rely +rule rely_revert(address usr) { + env e; + + mathint wardsSender = wards(e.msg.sender); + + rely@withrevert(e, usr); + + bool revert1 = e.msg.value > 0; + bool revert2 = wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting deny +rule deny(address usr) { + env e; + + address other; + require other != usr; + + mathint wardsOtherBefore = wards(other); + + deny(e, usr); + + mathint wardsUsrAfter = wards(usr); + mathint wardsOtherAfter = wards(other); + + assert wardsUsrAfter == 0, "deny did not set the wards"; + assert wardsOtherAfter == wardsOtherBefore, "deny did not keep unchanged the rest of wards[x]"; +} + +// Verify revert rules on deny +rule deny_revert(address usr) { + env e; + + mathint wardsSender = wards(e.msg.sender); + + deny@withrevert(e, usr); + + bool revert1 = e.msg.value > 0; + bool revert2 = wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting kiss +rule kiss(address usr) { + env e; + + address other; + require other != usr; + + mathint budsOtherBefore = buds(other); + + kiss(e, usr); + + mathint budsUsrAfter = buds(usr); + mathint budsOtherAfter = buds(other); + + assert budsUsrAfter == 1, "kiss did not set the buds"; + assert budsOtherAfter == budsOtherBefore, "kiss did not keep unchanged the rest of buds[x]"; +} + +// Verify revert rules on kiss +rule kiss_revert(address usr) { + env e; + + mathint wardsSender = wards(e.msg.sender); + + kiss@withrevert(e, usr); + + bool revert1 = e.msg.value > 0; + bool revert2 = wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting diss +rule diss(address usr) { + env e; + + address other; + require other != usr; + + mathint budsOtherBefore = buds(other); + + diss(e, usr); + + mathint budsUsrAfter = buds(usr); + mathint budsOtherAfter = buds(other); + + assert budsUsrAfter == 0, "diss did not set the buds"; + assert budsOtherAfter == budsOtherBefore, "diss did not keep unchanged the rest of buds[x]"; +} + +// Verify revert rules on diss +rule diss_revert(address usr) { + env e; + + mathint wardsSender = wards(e.msg.sender); + + diss@withrevert(e, usr); + + bool revert1 = e.msg.value > 0; + bool revert2 = wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting setConfig +rule setConfig(address from, address to, address gem, uint64 num, uint32 hop, uint128 lot) { + env e; + + address otherAddr; + address otherAddr_2; + address otherAddr_3; + require otherAddr != from || otherAddr_2 != to || otherAddr_3 != gem; + + mathint numOtherBefore; mathint hopOtherBefore; mathint zzzOtherBefore; mathint lotOtherBefore; + numOtherBefore, hopOtherBefore, zzzOtherBefore, lotOtherBefore = configs(otherAddr, otherAddr_2, otherAddr_3); + + setConfig(e, from, to, gem, num, hop, lot); + + mathint numFromToGemAfter; mathint hopFromToGemAfter; mathint zzzFromToGemAfter; mathint lotFromToGemAfter; + numFromToGemAfter, hopFromToGemAfter, zzzFromToGemAfter, lotFromToGemAfter = configs(from, to, gem); + mathint numOtherAfter; mathint hopOtherAfter; mathint zzzOtherAfter; mathint lotOtherAfter; + numOtherAfter, hopOtherAfter, zzzOtherAfter, lotOtherAfter = configs(otherAddr, otherAddr_2, otherAddr_3); + + assert numFromToGemAfter == to_mathint(num), "setConfig did not set configs[from][to][gem].num to num"; + assert hopFromToGemAfter == to_mathint(hop), "setConfig did not set configs[from][to][gem].hop to hop"; + assert zzzFromToGemAfter == 0, "setConfig did not set configs[from][to][gem].zzz to 0"; + assert lotFromToGemAfter == to_mathint(lot), "setConfig did not set configs[from][to][gem].lot to lot"; + assert numOtherAfter == numOtherBefore, "setConfig did not keep unchanged the rest of configs[x][y][z].num"; + assert hopOtherAfter == hopOtherBefore, "setConfig did not keep unchanged the rest of configs[x][y][z].hop"; + assert zzzOtherAfter == zzzOtherBefore, "setConfig did not keep unchanged the rest of configs[x][y][z].zzz"; + assert lotOtherAfter == lotOtherBefore, "setConfig did not keep unchanged the rest of configs[x][y][z].lot"; +} + +// Verify revert rules on setConfig +rule setConfig_revert(address from, address to, address gem, uint64 num, uint32 hop, uint128 lot) { + env e; + + mathint wardsSender = wards(e.msg.sender); + + setConfig@withrevert(e, from, to, gem, num, hop, lot); + + bool revert1 = e.msg.value > 0; + bool revert2 = wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting move +rule move(address from, address to, address gem) { + env e; + + address otherAddr; + address otherAddr_2; + address otherAddr_3; + require otherAddr != from || otherAddr_2 != to || otherAddr_3 != gem; + + require e.block.timestamp <= max_uint32; + + address buffer = buffer(); + + mathint a; mathint b; + + mathint numFromToGemBefore; mathint lotFromToGem; + numFromToGemBefore, a, b, lotFromToGem = configs(from, to, gem); + mathint numOtherBefore; mathint zzzOtherBefore; + numOtherBefore, a, zzzOtherBefore, b = configs(otherAddr, otherAddr_2, otherAddr_3); + + bytes32 withdrawIlkBefore = withdrawIlk; + address withdrawGemBefore = withdrawGem; + mathint withdrawAmountBefore = withdrawAmount; + bytes32 depositIlkBefore = depositIlk; + address depositGemBefore = depositGem; + mathint depositAmountBefore = depositAmount; + + mathint withdrawCounterBefore = withdrawCounter; + mathint depositCounterBefore = depositCounter; + + move(e, from, to, gem); + + mathint numFromToGemAfter; mathint zzzFromToGemAfter; + numFromToGemAfter, a, zzzFromToGemAfter, b = configs(from, to, gem); + mathint numOtherAfter; mathint zzzOtherAfter; + numOtherAfter, a, zzzOtherAfter, b = configs(otherAddr, otherAddr_2, otherAddr_3); + + assert numFromToGemAfter == numFromToGemBefore - 1, "move did not decrease configs[from][to][gem].num by 1"; + assert zzzFromToGemAfter == to_mathint(e.block.timestamp), "move did not set configs[from][to][gem].zzz to block.timestamp"; + assert numOtherAfter == numOtherBefore, "move did not keep unchanged the rest of configs[x][y][z].num"; + assert zzzOtherAfter == zzzOtherBefore, "move did not keep unchanged the rest of configs[x][y][z].zzz"; + assert from != buffer => withdrawCounter == withdrawCounterBefore + 1, "move did not execute exactly one withdraw external call"; + assert from != buffer => withdrawAddr == from, "move did not execute the withdraw external call to the correct 'from' contract"; + assert from != buffer => withdrawIlk == ilk(), "move did not pass the correct ilk to the withdraw external call"; + assert from != buffer => withdrawGem == gem, "move did not pass the correct gen to the withdraw external call"; + assert from != buffer => to_mathint(withdrawAmount) == lotFromToGem, "move did not pass the correct amount to the withdraw external call"; + assert from == buffer => withdrawCounter == withdrawCounterBefore, "move did execute one or more withdraw external call when it did not correspond"; + assert from == buffer => withdrawIlk == withdrawIlkBefore, "move did execute the withdraw external call when it did not correspond"; + assert from == buffer => withdrawGem == withdrawGemBefore, "move did execute the withdraw external call when it did not correspond 2"; + assert from == buffer => to_mathint(withdrawAmount) == withdrawAmountBefore, "move did execute the withdraw external call when it did not correspond 3"; + assert to != buffer => depositCounter == depositCounterBefore + 1, "move did not execute exactly one deposit external call"; + assert to != buffer => depositAddr == to, "move did not execute the deposit external call to the correct 'to' contract"; + assert to != buffer => depositIlk == ilk(), "move did not pass the correct ilk to the deposit external call"; + assert to != buffer => depositGem == gem, "move did not pass the correct gen to the deposit external call"; + assert to != buffer => to_mathint(depositAmount) == lotFromToGem, "move did not pass the correct amount to the deposit external call"; + assert to == buffer => depositCounter == depositCounterBefore, "move did execute one or more deposit external call when it did not correspond"; + assert to == buffer => depositIlk == depositIlkBefore, "move did execute the deposit external call when it did not correspond"; + assert to == buffer => depositGem == depositGemBefore, "move did execute the deposit external call when it did not correspond 2"; + assert to == buffer => to_mathint(depositAmount) == depositAmountBefore, "move did execute the deposit external call when it did not correspond 3"; +} + +// Verify revert rules on move +rule move_revert(address from, address to, address gem) { + env e; + + require e.block.timestamp <= max_uint32; + require !nonZeroExtcodesize[to]; + + address buffer = buffer(); + + mathint budsSender = buds(e.msg.sender); + mathint numFromToGem; mathint hopFromToGem; mathint zzzFromToGem; mathint lotFromToGem; + numFromToGem, hopFromToGem, zzzFromToGem, lotFromToGem = configs(from, to, gem); + + require to_mathint(withdrawReturn) == lotFromToGem; + + move@withrevert(e, from, to, gem); + + bool revert1 = e.msg.value > 0; + bool revert2 = budsSender != 1; + bool revert3 = numFromToGem == 0; + bool revert4 = to_mathint(e.block.timestamp) < zzzFromToGem + hopFromToGem; + bool revert5 = to_mathint(withdrawReturn) != lotFromToGem; + bool revert6 = to != buffer && !nonZeroExtcodesize[to]; + + assert lastReverted <=> revert1 || revert2 || revert3 || + revert4 || revert5 || revert6, "Revert rules failed"; +} diff --git a/certora/funnels/automation/StableDepositorUniV3.conf b/certora/funnels/automation/StableDepositorUniV3.conf new file mode 100644 index 00000000..0a60d833 --- /dev/null +++ b/certora/funnels/automation/StableDepositorUniV3.conf @@ -0,0 +1,10 @@ +{ + "files": [ + "src/funnels/automation/StableDepositorUniV3.sol", + ], + "rule_sanity": "basic", + "solc": "solc-0.8.16", + "solc_optimize": "200", + "verify": "StableDepositorUniV3:certora/funnels/automation/StableDepositorUniV3.spec", + "wait_for_results": "all" +} diff --git a/certora/funnels/automation/StableDepositorUniV3.spec b/certora/funnels/automation/StableDepositorUniV3.spec new file mode 100644 index 00000000..f2813356 --- /dev/null +++ b/certora/funnels/automation/StableDepositorUniV3.spec @@ -0,0 +1,479 @@ +// StableDepositorUniV3.spec + +methods { + function wards(address) external returns (uint256) envfree; + function buds(address) external returns (uint256) envfree; + function configs(address, address, uint24, int24, int24) external returns (int32, uint32, uint96, uint96, uint96, uint96, uint32) envfree; + function depositor() external returns (address) envfree; + function _.deposit(DepositorUniV3Like.LiquidityParams p) external => depositSummary(calledContract, p) expect uint128, uint256, uint256; + function _.withdraw(DepositorUniV3Like.LiquidityParams p, bool takeFees) external => withdrawSummary(calledContract, p, takeFees) expect uint128, uint256, uint256, uint256, uint256; + function _.collect(DepositorUniV3Like.CollectParams p) external => collectSummary(calledContract, p) expect uint256, uint256; +} + +ghost uint128 retValue; +ghost uint256 retValue2; +ghost uint256 retValue3; +ghost uint256 retValue4; +ghost uint256 retValue5; + +ghost mathint depositCounter; +ghost address depositAddr; +ghost address depositGem0; +ghost address depositGem1; +ghost uint24 depositFee; +ghost int24 depositTickLower; +ghost int24 depositTickUpper; +ghost uint128 depositLiquidity; +ghost uint256 depositAmt0Desired; +ghost uint256 depositAmt1Desired; +ghost uint256 depositAmt0Min; +ghost uint256 depositAmt1Min; +function depositSummary(address addr, DepositorUniV3Like.LiquidityParams p) returns (uint128, uint256, uint256) { + depositCounter = depositCounter + 1; + depositAddr = addr; + depositGem0 = p.gem0; + depositGem1 = p.gem1; + depositFee = p.fee; + depositTickLower = p.tickLower; + depositTickUpper = p.tickUpper; + depositLiquidity = p.liquidity; + depositAmt0Desired = p.amt0Desired; + depositAmt1Desired = p.amt1Desired; + depositAmt0Min = p.amt0Min; + depositAmt1Min = p.amt1Min; + return (retValue, retValue2, retValue3); +} + +ghost mathint withdrawCounter; +ghost address withdrawAddr; +ghost address withdrawGem0; +ghost address withdrawGem1; +ghost uint24 withdrawFee; +ghost int24 withdrawTickLower; +ghost int24 withdrawTickUpper; +ghost uint128 withdrawLiquidity; +ghost uint256 withdrawAmt0Desired; +ghost uint256 withdrawAmt1Desired; +ghost uint256 withdrawAmt0Min; +ghost uint256 withdrawAmt1Min; +ghost bool withdrawTakeFees; +function withdrawSummary(address addr, DepositorUniV3Like.LiquidityParams p, bool takeFees) returns (uint128, uint256, uint256, uint256, uint256) { + withdrawCounter = withdrawCounter + 1; + withdrawAddr = addr; + withdrawGem0 = p.gem0; + withdrawGem1 = p.gem1; + withdrawFee = p.fee; + withdrawTickLower = p.tickLower; + withdrawTickUpper = p.tickUpper; + withdrawLiquidity = p.liquidity; + withdrawAmt0Desired = p.amt0Desired; + withdrawAmt1Desired = p.amt1Desired; + withdrawAmt0Min = p.amt0Min; + withdrawAmt1Min = p.amt1Min; + withdrawTakeFees = takeFees; + return (retValue, retValue2, retValue3, retValue4, retValue5); +} + +ghost mathint collectCounter; +ghost address collectAddr; +ghost address collectGem0; +ghost address collectGem1; +ghost uint24 collectFee; +ghost int24 collectTickLower; +ghost int24 collectTickUpper; +function collectSummary(address addr, DepositorUniV3Like.CollectParams p) returns (uint256, uint256) { + collectCounter = collectCounter + 1; + collectAddr = addr; + collectGem0 = p.gem0; + collectGem1 = p.gem1; + collectFee = p.fee; + collectTickLower = p.tickLower; + collectTickUpper = p.tickUpper; + return (retValue2, retValue3); +} + +// Verify that each storage layout is only modified in the corresponding functions +rule storageAffected(method f) { + env e; + + address anyAddr; + address anyAddr_2; + uint24 anyUint24; + int24 anyInt24; + int24 anyInt24_2; + + mathint wardsBefore = wards(anyAddr); + mathint budsBefore = buds(anyAddr); + mathint numBefore; mathint zzzBefore; mathint amt0Before; mathint amt1Before; mathint req0Before; mathint req1Before; mathint hopBefore; + numBefore, zzzBefore, amt0Before, amt1Before, req0Before, req1Before, hopBefore = configs(anyAddr, anyAddr_2, anyUint24, anyInt24, anyInt24_2); + + calldataarg args; + f(e, args); + + mathint wardsAfter = wards(anyAddr); + mathint budsAfter = buds(anyAddr); + mathint numAfter; mathint zzzAfter; mathint amt0After; mathint amt1After; mathint req0After; mathint req1After; mathint hopAfter; + numAfter, zzzAfter, amt0After, amt1After, req0After, req1After, hopAfter = configs(anyAddr, anyAddr_2, anyUint24, anyInt24, anyInt24_2); + + assert wardsAfter != wardsBefore => f.selector == sig:rely(address).selector || f.selector == sig:deny(address).selector, "wards[x] changed in an unexpected function"; + assert budsAfter != budsBefore => f.selector == sig:kiss(address).selector || f.selector == sig:diss(address).selector, "buds[x] changed in an unexpected function"; + assert numAfter != numBefore => f.selector == sig:setConfig(address,address,uint24,int24,int24,int32,uint32,uint96,uint96,uint96,uint96).selector || f.selector == sig:deposit(address,address,uint24,int24,int24,uint128,uint128).selector || f.selector == sig:withdraw(address,address,uint24,int24,int24,uint128,uint128).selector, "configs[x][y][z][a][b].num changed in an unexpected function"; + assert zzzAfter != zzzBefore => f.selector == sig:setConfig(address,address,uint24,int24,int24,int32,uint32,uint96,uint96,uint96,uint96).selector || f.selector == sig:deposit(address,address,uint24,int24,int24,uint128,uint128).selector || f.selector == sig:withdraw(address,address,uint24,int24,int24,uint128,uint128).selector, "configs[x][y][z][a][b].zzz changed in an unexpected function"; + assert amt0After != amt0Before => f.selector == sig:setConfig(address,address,uint24,int24,int24,int32,uint32,uint96,uint96,uint96,uint96).selector, "configs[x][y][z][a][b].amt0 changed in an unexpected function"; + assert amt1After != amt1Before => f.selector == sig:setConfig(address,address,uint24,int24,int24,int32,uint32,uint96,uint96,uint96,uint96).selector, "configs[x][y][z][a][b].amt1 changed in an unexpected function"; + assert req0After != req0Before => f.selector == sig:setConfig(address,address,uint24,int24,int24,int32,uint32,uint96,uint96,uint96,uint96).selector, "configs[x][y][z][a][b].req0 changed in an unexpected function"; + assert req1After != req1Before => f.selector == sig:setConfig(address,address,uint24,int24,int24,int32,uint32,uint96,uint96,uint96,uint96).selector, "configs[x][y][z][a][b].req1 changed in an unexpected function"; + assert hopAfter != hopBefore => f.selector == sig:setConfig(address,address,uint24,int24,int24,int32,uint32,uint96,uint96,uint96,uint96).selector, "configs[x][y][z][a][b].hop changed in an unexpected function"; +} + +// Verify correct storage changes for non reverting rely +rule rely(address usr) { + env e; + + address other; + require other != usr; + + mathint wardsOtherBefore = wards(other); + + rely(e, usr); + + mathint wardsUsrAfter = wards(usr); + mathint wardsOtherAfter = wards(other); + + assert wardsUsrAfter == 1, "rely did not set the wards"; + assert wardsOtherAfter == wardsOtherBefore, "rely did not keep unchanged the rest of wards[x]"; +} + +// Verify revert rules on rely +rule rely_revert(address usr) { + env e; + + mathint wardsSender = wards(e.msg.sender); + + rely@withrevert(e, usr); + + bool revert1 = e.msg.value > 0; + bool revert2 = wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting deny +rule deny(address usr) { + env e; + + address other; + require other != usr; + + mathint wardsOtherBefore = wards(other); + + deny(e, usr); + + mathint wardsUsrAfter = wards(usr); + mathint wardsOtherAfter = wards(other); + + assert wardsUsrAfter == 0, "deny did not set the wards"; + assert wardsOtherAfter == wardsOtherBefore, "deny did not keep unchanged the rest of wards[x]"; +} + +// Verify revert rules on deny +rule deny_revert(address usr) { + env e; + + mathint wardsSender = wards(e.msg.sender); + + deny@withrevert(e, usr); + + bool revert1 = e.msg.value > 0; + bool revert2 = wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting kiss +rule kiss(address usr) { + env e; + + address other; + require other != usr; + + mathint budsOtherBefore = buds(other); + + kiss(e, usr); + + mathint budsUsrAfter = buds(usr); + mathint budsOtherAfter = buds(other); + + assert budsUsrAfter == 1, "kiss did not set the buds"; + assert budsOtherAfter == budsOtherBefore, "kiss did not keep unchanged the rest of buds[x]"; +} + +// Verify revert rules on kiss +rule kiss_revert(address usr) { + env e; + + mathint wardsSender = wards(e.msg.sender); + + kiss@withrevert(e, usr); + + bool revert1 = e.msg.value > 0; + bool revert2 = wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting diss +rule diss(address usr) { + env e; + + address other; + require other != usr; + + mathint budsOtherBefore = buds(other); + + diss(e, usr); + + mathint budsUsrAfter = buds(usr); + mathint budsOtherAfter = buds(other); + + assert budsUsrAfter == 0, "diss did not set the buds"; + assert budsOtherAfter == budsOtherBefore, "diss did not keep unchanged the rest of buds[x]"; +} + +// Verify revert rules on diss +rule diss_revert(address usr) { + env e; + + mathint wardsSender = wards(e.msg.sender); + + diss@withrevert(e, usr); + + bool revert1 = e.msg.value > 0; + bool revert2 = wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting setConfig +rule setConfig(address gem0, address gem1, uint24 fee, int24 tickLower, int24 tickUpper, int32 num, uint32 hop, uint96 amt0, uint96 amt1, uint96 req0, uint96 req1) { + env e; + + address otherAddr; + address otherAddr_2; + uint24 otherUint24; + int24 otherInt24; + int24 otherInt24_2; + require otherAddr != gem0 || otherAddr_2 != gem1 || fee != otherUint24 || tickLower != otherInt24 || tickUpper != otherInt24_2; + + mathint numOtherBefore; mathint zzzOtherBefore; mathint amt0OtherBefore; mathint amt1OtherBefore; mathint req0OtherBefore; mathint req1OtherBefore; mathint hopOtherBefore; + numOtherBefore, zzzOtherBefore, amt0OtherBefore, amt1OtherBefore, req0OtherBefore, req1OtherBefore, hopOtherBefore = configs(otherAddr, otherAddr_2, otherUint24, otherInt24, otherInt24_2); + + setConfig(e, gem0, gem1, fee, tickLower, tickUpper, num, hop, amt0, amt1, req0, req1); + + mathint numGem0Gem1After; mathint zzzGem0Gem1After; mathint amt0Gem0Gem1After; mathint amt1Gem0Gem1After; mathint req0Gem0Gem1After; mathint req1Gem0Gem1After; mathint hopGem0Gem1After; + numGem0Gem1After, zzzGem0Gem1After, amt0Gem0Gem1After, amt1Gem0Gem1After, req0Gem0Gem1After, req1Gem0Gem1After, hopGem0Gem1After = configs(gem0, gem1, fee, tickLower, tickUpper); + mathint numOtherAfter; mathint zzzOtherAfter; mathint amt0OtherAfter; mathint amt1OtherAfter; mathint req0OtherAfter; mathint req1OtherAfter; mathint hopOtherAfter; + numOtherAfter, zzzOtherAfter, amt0OtherAfter, amt1OtherAfter, req0OtherAfter, req1OtherAfter, hopOtherAfter = configs(otherAddr, otherAddr_2, otherUint24, otherInt24, otherInt24_2); + + assert numGem0Gem1After == to_mathint(num), "setConfig did not set configs[gem0][gem1][fee][tickLower][tickUpper].num to num"; + assert zzzGem0Gem1After == 0, "setConfig did not set configs[gem0][gem1][fee][tickLower][tickUpper].zzz to 0"; + assert amt0Gem0Gem1After == to_mathint(amt0), "setConfig did not set configs[gem0][gem1][fee][tickLower][tickUpper].amt0 to amt0"; + assert amt1Gem0Gem1After == to_mathint(amt1), "setConfig did not set configs[gem0][gem1][fee][tickLower][tickUpper].amt1 to amt1"; + assert req0Gem0Gem1After == to_mathint(req0), "setConfig did not set configs[gem0][gem1][fee][tickLower][tickUpper].req0 to req0"; + assert req1Gem0Gem1After == to_mathint(req1), "setConfig did not set configs[gem0][gem1][fee][tickLower][tickUpper].req1 to req1"; + assert hopGem0Gem1After == to_mathint(hop), "setConfig did not set configs[gem0][gem1][fee][tickLower][tickUpper].hop to hop"; + assert numOtherAfter == numOtherBefore, "setConfig did not keep the rest of configs[x][y][z][a][b].num"; + assert zzzOtherAfter == zzzOtherBefore, "setConfig did not keep the rest of configs[x][y][z][a][b].zzz"; + assert amt0OtherAfter == amt0OtherBefore, "setConfig did not keep the rest of configs[x][y][z][a][b].amt0"; + assert amt1OtherAfter == amt1OtherBefore, "setConfig did not keep the rest of configs[x][y][z][a][b].amt1"; + assert req0OtherAfter == req0OtherBefore, "setConfig did not keep the rest of configs[x][y][z][a][b].req0"; + assert req1OtherAfter == req1OtherBefore, "setConfig did not keep the rest of configs[x][y][z][a][b].req1"; + assert hopOtherAfter == hopOtherBefore, "setConfig did not keep the rest of configs[x][y][z][a][b].hop"; +} + +// Verify revert rules on setConfig +rule setConfig_revert(address gem0, address gem1, uint24 fee, int24 tickLower, int24 tickUpper, int32 num, uint32 hop, uint96 amt0, uint96 amt1, uint96 req0, uint96 req1) { + env e; + + mathint wardsSender = wards(e.msg.sender); + + setConfig@withrevert(e, gem0, gem1, fee, tickLower, tickUpper, num, hop, amt0, amt1, req0, req1); + + bool revert1 = e.msg.value > 0; + bool revert2 = wardsSender != 1; + bool revert3 = gem0 >= gem1; + + assert lastReverted <=> revert1 || revert2 || revert3, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting deposit +rule deposit(address gem0, address gem1, uint24 fee, int24 tickLower, int24 tickUpper, uint128 amt0Min, uint128 amt1Min) { + env e; + + address otherAddr; + address otherAddr_2; + uint24 otherUint24; + int24 otherInt24; + int24 otherInt24_2; + require otherAddr != gem0 || otherAddr_2 != gem1 || fee != otherUint24 || tickLower != otherInt24 || tickUpper != otherInt24_2; + + require e.block.timestamp <= max_uint32; + + mathint a; mathint b; mathint c; mathint d; mathint f; + + mathint numGem0Gem1Before; mathint zzzGem0Gem1Before; mathint amt0Gem0Gem1; mathint amt1Gem0Gem1; mathint req0Gem0Gem1; mathint req1Gem0Gem1; + numGem0Gem1Before, zzzGem0Gem1Before, amt0Gem0Gem1, amt1Gem0Gem1, req0Gem0Gem1, req1Gem0Gem1, a = configs(gem0, gem1, fee, tickLower, tickUpper); + mathint numOtherBefore; mathint zzzOtherBefore; + numOtherBefore, zzzOtherBefore, a, b, c, d, f = configs(otherAddr, otherAddr_2, otherUint24, otherInt24, otherInt24_2); + + mathint depositCounterBefore = depositCounter; + + deposit(e, gem0, gem1, fee, tickLower, tickUpper, amt0Min, amt1Min); + + mathint numGem0Gem1After; mathint zzzGem0Gem1After; + numGem0Gem1After, zzzGem0Gem1After, a, b, c, d, f = configs(gem0, gem1, fee, tickLower, tickUpper); + mathint numOtherAfter; mathint zzzOtherAfter; + numOtherAfter, zzzOtherAfter, a, b, c, d, f = configs(otherAddr, otherAddr_2, otherUint24, otherInt24, otherInt24_2); + + assert numGem0Gem1After == numGem0Gem1Before - 1, "deposit did not decrease configs[gem0][gem1][fee][tickLower][tickUpper].num by 1"; + assert zzzGem0Gem1After == to_mathint(e.block.timestamp), "deposit did not set configs[gem0][gem1][fee][tickLower][tickUpper].zzz to block.timestamp"; + assert numOtherAfter == numOtherBefore, "deposit did not keep unchanged the rest of configs[x][y][z][a][b].num"; + assert zzzOtherAfter == zzzOtherBefore, "deposit did not keep unchanged the rest of configs[x][y][z][a][b].zzz"; + assert depositCounter == depositCounterBefore + 1, "deposit did not execute exactly one deposit external call"; + assert depositAddr == depositor(), "deposit did not execute the deposit external call to the correct 'depositor()' contract"; + assert depositGem0 == gem0, "deposit did not pass the correct gem0 to the external call"; + assert depositGem1 == gem1, "deposit did not pass the correct gem1 to the external call"; + assert depositFee == fee, "deposit did not pass the correct fee to the external call"; + assert depositTickLower == tickLower, "deposit did not pass the correct tickLower to the external call"; + assert depositTickUpper == tickUpper, "deposit did not pass the correct tickUpper to the external call"; + assert depositLiquidity == 0, "deposit did not pass the correct liquidity to the external call"; + assert to_mathint(depositAmt0Desired) == amt0Gem0Gem1, "deposit did not pass the correct amt0Desired to the external call"; + assert to_mathint(depositAmt1Desired) == amt1Gem0Gem1, "deposit did not pass the correct amt1Desired to the external call"; + assert to_mathint(depositAmt0Min) == (amt0Min == 0 ? req0Gem0Gem1 : to_mathint(amt0Min)), "deposit did not pass the correct amt0Min to the external call"; + assert to_mathint(depositAmt1Min) == (amt1Min == 0 ? req1Gem0Gem1 : to_mathint(amt1Min)), "deposit did not pass the correct amt1Min to the external call"; +} + +// Verify revert rules on deposit +rule deposit_revert(address gem0, address gem1, uint24 fee, int24 tickLower, int24 tickUpper, uint128 amt0Min, uint128 amt1Min) { + env e; + + require e.block.timestamp <= max_uint32; + + mathint budsSender = buds(e.msg.sender); + mathint numGem0Gem1; mathint zzzGem0Gem1; mathint amt0Gem0Gem1; mathint amt1Gem0Gem1; mathint req0Gem0Gem1; mathint req1Gem0Gem1; mathint hopGem0Gem1; + numGem0Gem1, zzzGem0Gem1, amt0Gem0Gem1, amt1Gem0Gem1, req0Gem0Gem1, req1Gem0Gem1, hopGem0Gem1 = configs(gem0, gem1, fee, tickLower, tickUpper); + + deposit@withrevert(e, gem0, gem1, fee, tickLower, tickUpper, amt0Min, amt1Min); + + bool revert1 = e.msg.value > 0; + bool revert2 = budsSender != 1; + bool revert3 = numGem0Gem1 <= 0; + bool revert4 = to_mathint(e.block.timestamp) < zzzGem0Gem1 + hopGem0Gem1; + bool revert5 = to_mathint(amt0Min) > 0 && to_mathint(amt0Min) < req0Gem0Gem1; + bool revert6 = to_mathint(amt1Min) > 0 && to_mathint(amt1Min) < req1Gem0Gem1; + + assert lastReverted <=> revert1 || revert2 || revert3 || + revert4 || revert5 || revert6, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting withdraw +rule withdraw(address gem0, address gem1, uint24 fee, int24 tickLower, int24 tickUpper, uint128 amt0Min, uint128 amt1Min) { + env e; + + address otherAddr; + address otherAddr_2; + uint24 otherUint24; + int24 otherInt24; + int24 otherInt24_2; + require otherAddr != gem0 || otherAddr_2 != gem1 || fee != otherUint24 || tickLower != otherInt24 || tickUpper != otherInt24_2; + + require e.block.timestamp <= max_uint32; + + mathint a; mathint b; mathint c; mathint d; mathint f; + + mathint numGem0Gem1Before; mathint zzzGem0Gem1Before; mathint amt0Gem0Gem1; mathint amt1Gem0Gem1; mathint req0Gem0Gem1; mathint req1Gem0Gem1; + numGem0Gem1Before, zzzGem0Gem1Before, amt0Gem0Gem1, amt1Gem0Gem1, req0Gem0Gem1, req1Gem0Gem1, a = configs(gem0, gem1, fee, tickLower, tickUpper); + mathint numOtherBefore; mathint zzzOtherBefore; + numOtherBefore, zzzOtherBefore, a, b, c, d, f = configs(otherAddr, otherAddr_2, otherUint24, otherInt24, otherInt24_2); + + mathint withdrawCounterBefore = withdrawCounter; + + withdraw(e, gem0, gem1, fee, tickLower, tickUpper, amt0Min, amt1Min); + + mathint numGem0Gem1After; mathint zzzGem0Gem1After; mathint amt0Gem0Gem1After; mathint amt1Gem0Gem1After; mathint req0Gem0Gem1After; mathint req1Gem0Gem1After; mathint hopGem0Gem1After; + numGem0Gem1After, zzzGem0Gem1After, a, b, c, d, f = configs(gem0, gem1, fee, tickLower, tickUpper); + mathint numOtherAfter; mathint zzzOtherAfter; + numOtherAfter, zzzOtherAfter, a, b, c, d, f = configs(otherAddr, otherAddr_2, otherUint24, otherInt24, otherInt24_2); + + assert numGem0Gem1After == numGem0Gem1Before + 1, "withdraw did not increase configs[gem0][gem1][fee][tickLower][tickUpper].num by 1"; + assert zzzGem0Gem1After == to_mathint(e.block.timestamp), "withdraw did not set configs[gem0][gem1][fee][tickLower][tickUpper].zzz to block.timestamp"; + assert numOtherAfter == numOtherBefore, "withdraw did not keep unchanged the rest of configs[x][y][z][a][b].num"; + assert zzzOtherAfter == zzzOtherBefore, "withdraw did not keep unchanged the rest of configs[x][y][z][a][b].zzz"; + assert withdrawCounter == withdrawCounterBefore + 1, "withdraw did not execute exactly one withdraw external call"; + assert withdrawAddr == depositor(), "withdraw did not execute the withdraw external call to the correct 'depositor()' contract"; + assert withdrawGem0 == gem0, "withdraw did not pass the correct gem0 to the external call"; + assert withdrawGem1 == gem1, "withdraw did not pass the correct gem1 to the external call"; + assert withdrawFee == fee, "withdraw did not pass the correct fee to the external call"; + assert withdrawTickLower == tickLower, "withdraw did not pass the correct tickLower to the external call"; + assert withdrawTickUpper == tickUpper, "withdraw did not pass the correct tickUpper to the external call"; + assert withdrawLiquidity == 0, "withdraw did not pass the correct liquidity to the external call"; + assert to_mathint(withdrawAmt0Desired) == amt0Gem0Gem1, "withdraw did not pass the correct amt0Desired to the external call"; + assert to_mathint(withdrawAmt1Desired) == amt1Gem0Gem1, "withdraw did not pass the correct amt1Desired to the external call"; + assert to_mathint(withdrawAmt0Min) == (amt0Min == 0 ? req0Gem0Gem1 : to_mathint(amt0Min)), "withdraw did not pass the correct amt0Min to the external call"; + assert to_mathint(withdrawAmt1Min) == (amt1Min == 0 ? req1Gem0Gem1 : to_mathint(amt1Min)), "withdraw did not pass the correct amt1Min to the external call"; + assert withdrawTakeFees, "withdraw did not pass the correct takeFees to the external call"; +} + +// Verify revert rules on withdraw +rule withdraw_revert(address gem0, address gem1, uint24 fee, int24 tickLower, int24 tickUpper, uint128 amt0Min, uint128 amt1Min) { + env e; + + require e.block.timestamp <= max_uint32; + + mathint budsSender = buds(e.msg.sender); + mathint numGem0Gem1; mathint zzzGem0Gem1; mathint amt0Gem0Gem1; mathint amt1Gem0Gem1; mathint req0Gem0Gem1; mathint req1Gem0Gem1; mathint hopGem0Gem1; + numGem0Gem1, zzzGem0Gem1, amt0Gem0Gem1, amt1Gem0Gem1, req0Gem0Gem1, req1Gem0Gem1, hopGem0Gem1 = configs(gem0, gem1, fee, tickLower, tickUpper); + + withdraw@withrevert(e, gem0, gem1, fee, tickLower, tickUpper, amt0Min, amt1Min); + + bool revert1 = e.msg.value > 0; + bool revert2 = budsSender != 1; + bool revert3 = numGem0Gem1 >= 0; + bool revert4 = to_mathint(e.block.timestamp) < zzzGem0Gem1 + hopGem0Gem1; + bool revert5 = to_mathint(amt0Min) > 0 && to_mathint(amt0Min) < req0Gem0Gem1; + bool revert6 = to_mathint(amt1Min) > 0 && to_mathint(amt1Min) < req1Gem0Gem1; + + assert lastReverted <=> revert1 || revert2 || revert3 || + revert4 || revert5 || revert6, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting collect +rule collect(address gem0, address gem1, uint24 fee, int24 tickLower, int24 tickUpper) { + env e; + + mathint collectCounterBefore = collectCounter; + + collect(e, gem0, gem1, fee, tickLower, tickUpper); + + assert collectCounter == collectCounterBefore + 1, "collect did not execute exactly one collect external call"; + assert collectAddr == depositor(), "collect did not execute the collect external call to the correct 'depositor()' contract"; + assert collectGem0 == gem0, "collect did not pass the correct gem0 to the external call"; + assert collectGem1 == gem1, "collect did not pass the correct gem1 to the external call"; + assert collectFee == fee, "collect did not pass the correct fee to the external call"; + assert collectTickLower == tickLower, "collect did not pass the correct tickLower to the external call"; + assert collectTickUpper == tickUpper, "collect did not pass the correct tickUpper to the external call"; +} + +// Verify revert rules on collect +rule collect_revert(address gem0, address gem1, uint24 fee, int24 tickLower, int24 tickUpper) { + env e; + + mathint budsSender = buds(e.msg.sender); + + collect@withrevert(e, gem0, gem1, fee, tickLower, tickUpper); + + bool revert1 = e.msg.value > 0; + bool revert2 = budsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} diff --git a/certora/funnels/automation/StableSwapper.conf b/certora/funnels/automation/StableSwapper.conf new file mode 100644 index 00000000..6977f741 --- /dev/null +++ b/certora/funnels/automation/StableSwapper.conf @@ -0,0 +1,10 @@ +{ + "files": [ + "src/funnels/automation/StableSwapper.sol", + ], + "rule_sanity": "basic", + "solc": "solc-0.8.16", + "solc_optimize": "200", + "verify": "StableSwapper:certora/funnels/automation/StableSwapper.spec", + "wait_for_results": "all" +} diff --git a/certora/funnels/automation/StableSwapper.spec b/certora/funnels/automation/StableSwapper.spec new file mode 100644 index 00000000..1e42ac9a --- /dev/null +++ b/certora/funnels/automation/StableSwapper.spec @@ -0,0 +1,294 @@ +// StableSwapper.spec + +methods { + function wards(address) external returns (uint256) envfree; + function buds(address) external returns (uint256) envfree; + function configs(address, address) external returns (uint128, uint32, uint32, uint96, uint96) envfree; + function swapper() external returns (address) envfree; + function _.swap(address src, address dst, uint256 lot, uint256 minOut, address callee, bytes data) external => swapSummary(calledContract, src, dst, lot, minOut, callee, data) expect uint256; +} + +ghost mathint swapCounter; +ghost address swapAddr; +ghost uint256 swapRetValue; +ghost address swapSrc; +ghost address swapDst; +ghost uint256 swapLot; +ghost uint256 swapMinOut; +ghost address swapCallee; +ghost uint256 swapDataLength; +function swapSummary(address addr, address src, address dst, uint256 lot, uint256 minOut, address callee, bytes data) returns uint256 { + swapCounter = swapCounter + 1; + swapAddr = addr; + swapSrc = src; + swapDst = dst; + swapLot = lot; + swapMinOut = minOut; + swapCallee = callee; + swapDataLength = data.length; + return swapRetValue; +} + +// Verify that each storage layout is only modified in the corresponding functions +rule storageAffected(method f) { + env e; + + address anyAddr; + address anyAddr_2; + + mathint wardsBefore = wards(anyAddr); + mathint budsBefore = buds(anyAddr); + mathint numBefore; mathint hopBefore; mathint zzzBefore; mathint lotBefore; mathint reqBefore; + numBefore, hopBefore, zzzBefore, lotBefore, reqBefore = configs(anyAddr, anyAddr_2); + + calldataarg args; + f(e, args); + + mathint wardsAfter = wards(anyAddr); + mathint budsAfter = buds(anyAddr); + mathint numAfter; mathint hopAfter; mathint zzzAfter; mathint lotAfter; mathint reqAfter; + numAfter, hopAfter, zzzAfter, lotAfter, reqAfter = configs(anyAddr, anyAddr_2); + + assert wardsAfter != wardsBefore => f.selector == sig:rely(address).selector || f.selector == sig:deny(address).selector, "wards[x] changed in an unexpected function"; + assert budsAfter != budsBefore => f.selector == sig:kiss(address).selector || f.selector == sig:diss(address).selector, "buds[x] changed in an unexpected function"; + assert numAfter != numBefore => f.selector == sig:setConfig(address,address,uint128,uint32,uint96,uint96).selector || f.selector == sig:swap(address,address,uint256,address,bytes).selector, "configs[x][y].num changed in an unexpected function"; + assert hopAfter != hopBefore => f.selector == sig:setConfig(address,address,uint128,uint32,uint96,uint96).selector, "configs[x][y].hop changed in an unexpected function"; + assert zzzAfter != zzzBefore => f.selector == sig:setConfig(address,address,uint128,uint32,uint96,uint96).selector || f.selector == sig:swap(address,address,uint256,address,bytes).selector, "configs[x][y].zzz changed in an unexpected function"; + assert lotAfter != lotBefore => f.selector == sig:setConfig(address,address,uint128,uint32,uint96,uint96).selector, "configs[x][y].lot changed in an unexpected function"; + assert reqAfter != reqBefore => f.selector == sig:setConfig(address,address,uint128,uint32,uint96,uint96).selector, "configs[x][y].req changed in an unexpected function"; +} + +// Verify correct storage changes for non reverting rely +rule rely(address usr) { + env e; + + address other; + require other != usr; + + mathint wardsOtherBefore = wards(other); + + rely(e, usr); + + mathint wardsUsrAfter = wards(usr); + mathint wardsOtherAfter = wards(other); + + assert wardsUsrAfter == 1, "rely did not set the wards"; + assert wardsOtherAfter == wardsOtherBefore, "rely did not keep unchanged the rest of wards[x]"; +} + +// Verify revert rules on rely +rule rely_revert(address usr) { + env e; + + mathint wardsSender = wards(e.msg.sender); + + rely@withrevert(e, usr); + + bool revert1 = e.msg.value > 0; + bool revert2 = wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting deny +rule deny(address usr) { + env e; + + address other; + require other != usr; + + mathint wardsOtherBefore = wards(other); + + deny(e, usr); + + mathint wardsUsrAfter = wards(usr); + mathint wardsOtherAfter = wards(other); + + assert wardsUsrAfter == 0, "deny did not set the wards"; + assert wardsOtherAfter == wardsOtherBefore, "deny did not keep unchanged the rest of wards[x]"; +} + +// Verify revert rules on deny +rule deny_revert(address usr) { + env e; + + mathint wardsSender = wards(e.msg.sender); + + deny@withrevert(e, usr); + + bool revert1 = e.msg.value > 0; + bool revert2 = wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting kiss +rule kiss(address usr) { + env e; + + address other; + require other != usr; + + mathint budsOtherBefore = buds(other); + + kiss(e, usr); + + mathint budsUsrAfter = buds(usr); + mathint budsOtherAfter = buds(other); + + assert budsUsrAfter == 1, "kiss did not set the buds"; + assert budsOtherAfter == budsOtherBefore, "kiss did not keep unchanged the rest of buds[x]"; +} + +// Verify revert rules on kiss +rule kiss_revert(address usr) { + env e; + + mathint wardsSender = wards(e.msg.sender); + + kiss@withrevert(e, usr); + + bool revert1 = e.msg.value > 0; + bool revert2 = wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting diss +rule diss(address usr) { + env e; + + address other; + require other != usr; + + mathint budsOtherBefore = buds(other); + + diss(e, usr); + + mathint budsUsrAfter = buds(usr); + mathint budsOtherAfter = buds(other); + + assert budsUsrAfter == 0, "diss did not set the buds"; + assert budsOtherAfter == budsOtherBefore, "diss did not keep unchanged the rest of buds[x]"; +} + +// Verify revert rules on diss +rule diss_revert(address usr) { + env e; + + mathint wardsSender = wards(e.msg.sender); + + diss@withrevert(e, usr); + + bool revert1 = e.msg.value > 0; + bool revert2 = wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting setConfig +rule setConfig(address src, address dst, uint128 num, uint32 hop, uint96 lot, uint96 req) { + env e; + + address otherAddr; + address otherAddr_2; + require otherAddr != src || otherAddr_2 != dst; + + mathint numOtherBefore; mathint hopOtherBefore; mathint zzzOtherBefore; mathint lotOtherBefore; mathint reqOtherBefore; + numOtherBefore, hopOtherBefore, zzzOtherBefore, lotOtherBefore, reqOtherBefore = configs(otherAddr, otherAddr_2); + + setConfig(e, src, dst, num, hop, lot, req); + + mathint numSrcDstAfter; mathint hopSrcDstAfter; mathint zzzSrcDstAfter; mathint lotSrcDstAfter; mathint reqSrcDstAfter; + numSrcDstAfter, hopSrcDstAfter, zzzSrcDstAfter, lotSrcDstAfter, reqSrcDstAfter = configs(src, dst); + mathint numOtherAfter; mathint hopOtherAfter; mathint zzzOtherAfter; mathint lotOtherAfter; mathint reqOtherAfter; + numOtherAfter, hopOtherAfter, zzzOtherAfter, lotOtherAfter, reqOtherAfter = configs(otherAddr, otherAddr_2); + + assert numSrcDstAfter == to_mathint(num), "setConfig did not set configs[src][dst].num to num"; + assert hopSrcDstAfter == to_mathint(hop), "setConfig did not set configs[src][dst].hop to hop"; + assert zzzSrcDstAfter == 0, "setConfig did not set configs[src][dst].zzz to 0"; + assert lotSrcDstAfter == to_mathint(lot), "setConfig did not set configs[src][dst].lot to lot"; + assert reqSrcDstAfter == to_mathint(req), "setConfig did not set configs[src][dst].req to req"; + assert numOtherAfter == numOtherBefore, "setConfig did not keep unchanged the rest of configs[x][y].num"; + assert hopOtherAfter == hopOtherBefore, "setConfig did not keep unchanged the rest of configs[x][y].hop"; + assert zzzOtherAfter == zzzOtherBefore, "setConfig did not keep unchanged the rest of configs[x][y].zzz"; + assert lotOtherAfter == lotOtherBefore, "setConfig did not keep unchanged the rest of configs[x][y].lot"; + assert reqOtherAfter == reqOtherBefore, "setConfig did not keep unchanged the rest of configs[x][y].req"; +} + +// Verify revert rules on setConfig +rule setConfig_revert(address src, address dst, uint128 num, uint32 hop, uint96 lot, uint96 req) { + env e; + + mathint wardsSender = wards(e.msg.sender); + + setConfig@withrevert(e, src, dst, num, hop, lot, req); + + bool revert1 = e.msg.value > 0; + bool revert2 = wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting swap +rule swap(address src, address dst, uint256 minOut, address callee, bytes data) { + env e; + + address otherAddr; + address otherAddr_2; + require otherAddr != src || otherAddr_2 != dst; + + require e.block.timestamp <= max_uint32; + + mathint a; mathint b; mathint c; + + mathint numSrcDstBefore; mathint lotSrcDst; mathint reqSrcDst; + numSrcDstBefore, a, b, lotSrcDst, reqSrcDst = configs(src, dst); + mathint numOtherBefore; mathint zzzOtherBefore; + numOtherBefore, a, zzzOtherBefore, b, c = configs(otherAddr, otherAddr_2); + + mathint swapCounterBefore = swapCounter; + + swap(e, src, dst, minOut, callee, data); + + mathint numSrcDstAfter; mathint zzzSrcDstAfter; + numSrcDstAfter, a, zzzSrcDstAfter, b, c = configs(src, dst); + mathint numOtherAfter; mathint zzzOtherAfter; + numOtherAfter, a, zzzOtherAfter, b, c = configs(otherAddr, otherAddr_2); + + assert numSrcDstAfter == numSrcDstBefore - 1, "swap did not decrease configs[src][dst].num by 1"; + assert zzzSrcDstAfter == to_mathint(e.block.timestamp), "swap did not set configs[src][dst].zzz to block.timestamp"; + assert numOtherAfter == numOtherBefore, "swap did not keep unchanged the rest of configs[x][y].num"; + assert zzzOtherAfter == zzzOtherBefore, "swap did not keep unchanged the rest of configs[x][y].zzz"; + assert swapCounter == swapCounterBefore + 1, "swap did not execute exactly one swap external call"; + assert swapAddr == swapper(), "swap did not execute the swap external call to the correct 'swapper()' contract"; + assert swapSrc == src, "swap did not not pass the correct src to the external call"; + assert swapDst == dst, "swap did not not pass the correct dst to the external call"; + assert to_mathint(swapLot) == lotSrcDst, "swap did not not pass the correct lot to the external call"; + assert to_mathint(swapMinOut) == (minOut == 0 ? reqSrcDst : to_mathint(minOut)), "swap did not not pass the correct minOut to the external call"; + assert swapCallee == callee, "swap did not not pass the correct callee to the external call"; + assert swapDataLength == data.length, "swap did not not pass the correct data to the external call"; +} + +// Verify revert rules on swap +rule swap_revert(address src, address dst, uint256 minOut, address callee, bytes data) { + env e; + + require data.length < max_uint32; + require e.block.timestamp <= max_uint32; + + mathint budsSender = buds(e.msg.sender); + mathint numSrcDst; mathint hopSrcDst; mathint zzzSrcDst; mathint lotSrcDst; mathint reqSrcDst; + numSrcDst, hopSrcDst, zzzSrcDst, lotSrcDst, reqSrcDst = configs(src, dst); + + swap@withrevert(e, src, dst, minOut, callee, data); + + bool revert1 = e.msg.value > 0; + bool revert2 = budsSender != 1; + bool revert3 = numSrcDst == 0; + bool revert4 = to_mathint(e.block.timestamp) < zzzSrcDst + hopSrcDst; + bool revert5 = to_mathint(minOut) > 0 && to_mathint(minOut) < reqSrcDst; + + assert lastReverted <=> revert1 || revert2 || revert3 || + revert4 || revert5, "Revert rules failed"; +} diff --git a/certora/funnels/automation/VaultMinter.conf b/certora/funnels/automation/VaultMinter.conf new file mode 100644 index 00000000..56c7f076 --- /dev/null +++ b/certora/funnels/automation/VaultMinter.conf @@ -0,0 +1,10 @@ +{ + "files": [ + "src/funnels/automation/VaultMinter.sol" + ], + "rule_sanity": "basic", + "solc": "solc-0.8.16", + "solc_optimize": "200", + "verify": "VaultMinter:certora/funnels/automation/VaultMinter.spec", + "wait_for_results": "all" +} diff --git a/certora/funnels/automation/VaultMinter.spec b/certora/funnels/automation/VaultMinter.spec new file mode 100644 index 00000000..3991738e --- /dev/null +++ b/certora/funnels/automation/VaultMinter.spec @@ -0,0 +1,325 @@ +// VaultMinter.spec + +methods { + function wards(address) external returns (uint256) envfree; + function buds(address) external returns (uint256) envfree; + function config() external returns (int64, uint32, uint32, uint128) envfree; + function vault() external returns (address) envfree; + function _.draw(uint256 wad) external => drawSummary(calledContract, wad) expect bool; // Forcing to have a return value as otherwise Certora will throw a compiler error + function _.wipe(uint256 wad) external => wipeSummary(calledContract, wad) expect bool; // Forcing to have a return value as otherwise Certora will throw a compiler error +} + +ghost mapping(address => bool) nonZeroExtcodesize; +hook EXTCODESIZE(address addr) uint v { + nonZeroExtcodesize[addr] = (v != 0); +} + +ghost mathint drawCounter; +ghost address drawAddr; +ghost uint256 drawAmount; +function drawSummary(address addr, uint256 amount) returns bool { + drawCounter = drawCounter + 1; + drawAddr = addr; + drawAmount = amount; + return true; +} + +ghost mathint wipeCounter; +ghost address wipeAddr; +ghost uint256 wipeAmount; +function wipeSummary(address addr, uint256 amount) returns bool { + wipeCounter = wipeCounter + 1; + wipeAddr = addr; + wipeAmount = amount; + return true; +} + +// Verify that each storage layout is only modified in the corresponding functions +rule storageAffected(method f) { + env e; + + address anyAddr; + + mathint wardsBefore = wards(anyAddr); + mathint budsBefore = buds(anyAddr); + mathint numBefore; mathint hopBefore; mathint zzzBefore; mathint lotBefore; + numBefore, hopBefore, zzzBefore, lotBefore = config(); + + calldataarg args; + f(e, args); + + mathint wardsAfter = wards(anyAddr); + mathint budsAfter = buds(anyAddr); + mathint numAfter; mathint hopAfter; mathint zzzAfter; mathint lotAfter; + numAfter, hopAfter, zzzAfter, lotAfter = config(); + + assert wardsAfter != wardsBefore => f.selector == sig:rely(address).selector || f.selector == sig:deny(address).selector, "wards[x] changed in an unexpected function"; + assert budsAfter != budsBefore => f.selector == sig:kiss(address).selector || f.selector == sig:diss(address).selector, "buds[x] changed in an unexpected function"; + assert numAfter != numBefore => f.selector == sig:setConfig(int64,uint32,uint128).selector || f.selector == sig:draw().selector || f.selector == sig:wipe().selector, "config.num changed in an unexpected function"; + assert hopAfter != hopBefore => f.selector == sig:setConfig(int64,uint32,uint128).selector, "config.hop changed in an unexpected function"; + assert zzzAfter != zzzBefore => f.selector == sig:setConfig(int64,uint32,uint128).selector || f.selector == sig:draw().selector || f.selector == sig:wipe().selector, "config.zzz changed in an unexpected function"; + assert lotAfter != lotBefore => f.selector == sig:setConfig(int64,uint32,uint128).selector, "config.lot changed in an unexpected function"; +} + +// Verify correct storage changes for non reverting rely +rule rely(address usr) { + env e; + + address other; + require other != usr; + + mathint wardsOtherBefore = wards(other); + + rely(e, usr); + + mathint wardsUsrAfter = wards(usr); + mathint wardsOtherAfter = wards(other); + + assert wardsUsrAfter == 1, "rely did not set the wards"; + assert wardsOtherAfter == wardsOtherBefore, "rely did not keep unchanged the rest of wards[x]"; +} + +// Verify revert rules on rely +rule rely_revert(address usr) { + env e; + + mathint wardsSender = wards(e.msg.sender); + + rely@withrevert(e, usr); + + bool revert1 = e.msg.value > 0; + bool revert2 = wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting deny +rule deny(address usr) { + env e; + + address other; + require other != usr; + + mathint wardsOtherBefore = wards(other); + + deny(e, usr); + + mathint wardsUsrAfter = wards(usr); + mathint wardsOtherAfter = wards(other); + + assert wardsUsrAfter == 0, "deny did not set the wards"; + assert wardsOtherAfter == wardsOtherBefore, "deny did not keep unchanged the rest of wards[x]"; +} + +// Verify revert rules on deny +rule deny_revert(address usr) { + env e; + + mathint wardsSender = wards(e.msg.sender); + + deny@withrevert(e, usr); + + bool revert1 = e.msg.value > 0; + bool revert2 = wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting kiss +rule kiss(address usr) { + env e; + + address other; + require other != usr; + + mathint budsOtherBefore = buds(other); + + kiss(e, usr); + + mathint budsUsrAfter = buds(usr); + mathint budsOtherAfter = buds(other); + + assert budsUsrAfter == 1, "kiss did not set the buds"; + assert budsOtherAfter == budsOtherBefore, "kiss did not keep unchanged the rest of buds[x]"; +} + +// Verify revert rules on kiss +rule kiss_revert(address usr) { + env e; + + mathint wardsSender = wards(e.msg.sender); + + kiss@withrevert(e, usr); + + bool revert1 = e.msg.value > 0; + bool revert2 = wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting diss +rule diss(address usr) { + env e; + + address other; + require other != usr; + + mathint budsOtherBefore = buds(other); + + diss(e, usr); + + mathint budsUsrAfter = buds(usr); + mathint budsOtherAfter = buds(other); + + assert budsUsrAfter == 0, "diss did not set the buds"; + assert budsOtherAfter == budsOtherBefore, "diss did not keep unchanged the rest of buds[x]"; +} + +// Verify revert rules on diss +rule diss_revert(address usr) { + env e; + + mathint wardsSender = wards(e.msg.sender); + + diss@withrevert(e, usr); + + bool revert1 = e.msg.value > 0; + bool revert2 = wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting setConfig +rule setConfig(int64 num, uint32 hop, uint128 lot) { + env e; + + setConfig(e, num, hop, lot); + + mathint numAfter; mathint hopAfter; mathint zzzAfter; mathint lotAfter; + numAfter, hopAfter, zzzAfter, lotAfter = config(); + + assert numAfter == to_mathint(num), "setConfig did not set config.num to num"; + assert hopAfter == to_mathint(hop), "setConfig did not set config.hop to hop"; + assert zzzAfter == 0, "setConfig did not set config.zzz to 0"; + assert lotAfter == to_mathint(lot), "setConfig did not set config.lot to lot"; +} + +// Verify revert rules on setConfig +rule setConfig_revert(int64 num, uint32 hop, uint128 lot) { + env e; + + mathint wardsSender = wards(e.msg.sender); + + setConfig@withrevert(e, num, hop, lot); + + bool revert1 = e.msg.value > 0; + bool revert2 = wardsSender != 1; + + assert lastReverted <=> revert1 || revert2, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting draw +rule draw() { + env e; + + require e.block.timestamp <= max_uint32; + + address vault = vault(); + + mathint a; mathint b; + + mathint numBefore; mathint lot; + numBefore, a, b, lot = config(); + + mathint drawCounterBefore = drawCounter; + + draw(e); + + mathint numAfter; mathint zzzAfter; + numAfter, a, zzzAfter, a = config(); + + assert numAfter == numBefore - 1, "draw did not decrease config.num by 1"; + assert zzzAfter == to_mathint(e.block.timestamp), "draw did not set config.zzz to block.timestamp"; + assert drawCounter == drawCounterBefore + 1, "draw did not execute exactly one draw external call"; + assert drawAddr == vault, "draw did not execute the draw external call to the correct vault contract"; + assert to_mathint(drawAmount) == lot, "draw did not pass the correct amount to the draw external call"; +} + +// Verify revert rules on draw +rule draw_revert() { + env e; + + address vault = vault(); + + require e.block.timestamp <= max_uint32; + require !nonZeroExtcodesize[vault]; + + mathint budsSender = buds(e.msg.sender); + mathint a; + mathint num; mathint hop; mathint zzz; + num, hop, zzz, a = config(); + + draw@withrevert(e); + + bool revert1 = e.msg.value > 0; + bool revert2 = budsSender != 1; + bool revert3 = num == 0; + bool revert4 = to_mathint(e.block.timestamp) < zzz + hop; + bool revert5 = !nonZeroExtcodesize[vault]; + + assert lastReverted <=> revert1 || revert2 || revert3 || + revert4 || revert5, "Revert rules failed"; +} + +// Verify correct storage changes for non reverting wipe +rule wipe() { + env e; + + require e.block.timestamp <= max_uint32; + + address vault = vault(); + + mathint a; mathint b; + + mathint numBefore; mathint lot; + numBefore, a, b, lot = config(); + + mathint wipeCounterBefore = wipeCounter; + + wipe(e); + + mathint numAfter; mathint zzzAfter; + numAfter, a, zzzAfter, a = config(); + + assert numAfter == numBefore + 1, "wipe did not decrease config.num by 1"; + assert zzzAfter == to_mathint(e.block.timestamp), "wipe did not set config.zzz to block.timestamp"; + assert wipeCounter == wipeCounterBefore + 1, "wipe did not execute exactly one wipe external call"; + assert wipeAddr == vault, "wipe did not execute the wipe external call to the correct vault contract"; + assert to_mathint(wipeAmount) == lot, "wipe did not pass the correct amount to the wipe external call"; +} + +// Verify revert rules on wipe +rule wipe_revert() { + env e; + + address vault = vault(); + + require e.block.timestamp <= max_uint32; + require !nonZeroExtcodesize[vault]; + + mathint budsSender = buds(e.msg.sender); + mathint a; + mathint num; mathint hop; mathint zzz; + num, hop, zzz, a = config(); + + wipe@withrevert(e); + + bool revert1 = e.msg.value > 0; + bool revert2 = budsSender != 1; + bool revert3 = num == 0; + bool revert4 = to_mathint(e.block.timestamp) < zzz + hop; + bool revert5 = !nonZeroExtcodesize[vault]; + + assert lastReverted <=> revert1 || revert2 || revert3 || + revert4 || revert5, "Revert rules failed"; +} diff --git a/test/mocks/CalleeMock.sol b/test/mocks/CalleeMock.sol new file mode 100644 index 00000000..d414fa7d --- /dev/null +++ b/test/mocks/CalleeMock.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.8.16; + +interface GemLike { + function balanceOf(address) external view returns (uint256); + function transfer(address, uint256) external; +} + +contract CalleeMock { + uint256 random; + + function swapCallback(address, address dst, uint256, uint256, address, bytes calldata) external { + GemLike(dst).transfer(msg.sender, GemLike(dst).balanceOf(address(this))); + } +} diff --git a/test/mocks/Gem0Mock.sol b/test/mocks/Gem0Mock.sol new file mode 100644 index 00000000..1c64022f --- /dev/null +++ b/test/mocks/Gem0Mock.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.8.16; + +import { GemMock } from "test/mocks/GemMock.sol"; + +contract Gem0Mock is GemMock(1_000_000*10**18) { +} diff --git a/test/mocks/Gem1Mock.sol b/test/mocks/Gem1Mock.sol new file mode 100644 index 00000000..2f437acc --- /dev/null +++ b/test/mocks/Gem1Mock.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.8.16; + +import { GemMock } from "test/mocks/GemMock.sol"; + +contract Gem1Mock is GemMock(1_000_000*10**18) { +} diff --git a/test/mocks/JugMock.sol b/test/mocks/JugMock.sol index c5c430f4..33c2f080 100644 --- a/test/mocks/JugMock.sol +++ b/test/mocks/JugMock.sol @@ -7,8 +7,8 @@ import { VatMock } from "test/mocks/VatMock.sol"; contract JugMock { VatMock vat; - uint256 duty = 1001 * 10**27 / 1000; - uint256 rho = block.timestamp; + uint256 public duty = 1001 * 10**27 / 1000; + uint256 public rho = block.timestamp; constructor(VatMock vat_) { vat = vat_; diff --git a/test/mocks/NstMock.sol b/test/mocks/NstMock.sol new file mode 100644 index 00000000..555736f1 --- /dev/null +++ b/test/mocks/NstMock.sol @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.8.16; + +contract NstMock { + mapping (address => uint256) public balanceOf; + mapping (address => mapping (address => uint256)) public allowance; + + uint256 public totalSupply; + + constructor(uint256 initialSupply) { + mint(msg.sender, initialSupply); + } + + function approve(address spender, uint256 value) external returns (bool) { + allowance[msg.sender][spender] = value; + return true; + } + + function transfer(address to, uint256 value) external returns (bool) { + uint256 balance = balanceOf[msg.sender]; + require(balance >= value, "Nst/insufficient-balance"); + + unchecked { + balanceOf[msg.sender] = balance - value; + balanceOf[to] += value; + } + return true; + } + + function transferFrom(address from, address to, uint256 value) external returns (bool) { + uint256 balance = balanceOf[from]; + require(balance >= value, "Nst/insufficient-balance"); + + if (from != msg.sender) { + uint256 allowed = allowance[from][msg.sender]; + if (allowed != type(uint256).max) { + require(allowed >= value, "Nst/insufficient-allowance"); + + unchecked { + allowance[from][msg.sender] = allowed - value; + } + } + } + + unchecked { + balanceOf[from] = balance - value; + balanceOf[to] += value; + } + return true; + } + + function mint(address to, uint256 value) public { + unchecked { + balanceOf[to] = balanceOf[to] + value; + } + totalSupply = totalSupply + value; + } + + function burn(address from, uint256 value) external { + uint256 balance = balanceOf[from]; + require(balance >= value, "Nst/insufficient-balance"); + + if (from != msg.sender) { + uint256 allowed = allowance[from][msg.sender]; + if (allowed != type(uint256).max) { + require(allowed >= value, "Nst/insufficient-allowance"); + + unchecked { + allowance[from][msg.sender] = allowed - value; + } + } + } + + unchecked { + balanceOf[from] = balance - value; + totalSupply = totalSupply - value; + } + } +} diff --git a/test/mocks/PoolUniV3Mock.sol b/test/mocks/PoolUniV3Mock.sol new file mode 100644 index 00000000..8c3bce8f --- /dev/null +++ b/test/mocks/PoolUniV3Mock.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.8.16; + +interface DepositorLike { + function uniswapV3MintCallback(uint256, uint256, bytes calldata) external; +} + +interface GemLike { + function transfer(address, uint256) external; +} + +contract PoolUniV3Mock { + address public gem0; + address public gem1; + uint24 public fee; + + uint128 public random0; + uint128 public random1; + uint128 public random2; + uint128 public random3; + + mapping (bytes32 => Position) public positions; + + struct Position { + uint128 liquidity; + uint256 feeGrowthInside0LastX128; + uint256 feeGrowthInside1LastX128; + uint128 tokensOwed0; + uint128 tokensOwed1; + } + + function mint(address, int24, int24, uint128, bytes calldata) external returns (uint128, uint128) { + DepositorLike(msg.sender).uniswapV3MintCallback(random0, random1, abi.encode(gem0, gem1, fee)); + + return (random0, random1); + } + + function burn(int24, int24, uint128) external view returns (uint128, uint128) { + return (random0, random1); + } + + function collect(address recipient, int24, int24, uint128 amt0R, uint128 amt1R) external returns (uint128, uint128) { + uint128 col0 = amt0R > random2 ? random2 : amt0R; + uint128 col1 = amt1R > random3 ? random3 : amt1R; + GemLike(gem0).transfer(recipient, col0); + GemLike(gem1).transfer(recipient, col1); + return (col0, col1); + } +} diff --git a/test/mocks/VatMock.sol b/test/mocks/VatMock.sol index 4d25af28..6298560f 100644 --- a/test/mocks/VatMock.sol +++ b/test/mocks/VatMock.sol @@ -12,23 +12,28 @@ contract VatMock { uint256 art; } - mapping (bytes32 => mapping (address => Urn )) public urns; - mapping (bytes32 => mapping (address => uint)) public gem; - mapping (address => uint256) public dai; + mapping (address => mapping (address => uint256)) public can; + mapping (bytes32 => mapping (address => Urn )) public urns; + mapping (bytes32 => mapping (address => uint)) public gem; + mapping (address => uint256) public dai; function ilks(bytes32) external view returns (uint256, uint256, uint256, uint256, uint256) { return (Art, rate, 0, line, 0); } - function hope(address) external {} + function hope(address usr) external { + can[msg.sender][usr] = 1; + } function frob(bytes32 i, address u, address v, address w, int256 dink, int256 dart) external { + require(u == msg.sender || can[u][msg.sender] == 1); Urn memory urn = urns[i][u]; urn.ink = dink >= 0 ? urn.ink + uint256(dink) : urn.ink - uint256(-dink); Art = urn.art = dart >= 0 ? urn.art + uint256(dart) : urn.art - uint256(-dart); gem[i][v] = dink >= 0 ? gem[i][v] - uint256(dink) : gem[i][v] + uint256(-dink); + require(dart == 0 || rate <= uint256(type(int256).max)); int256 dtab = int256(rate) * dart; dai[w] = dtab >= 0 ? dai[w] + uint256(dtab) : dai[w] - uint256(-dtab); @@ -36,6 +41,7 @@ contract VatMock { } function move(address src, address dst, uint256 rad) external { + require(src == msg.sender || can[src][msg.sender] == 1); dai[src] = dai[src] - rad; dai[dst] = dai[dst] + rad; } From 9318d514dfdd52c6181adbbd1ab9ed2139806737 Mon Sep 17 00:00:00 2001 From: telome <130504305+telome@users.noreply.github.com> Date: Tue, 21 Nov 2023 14:14:15 +0000 Subject: [PATCH 65/74] SwapperCalleePsm: Add note regarding dust accumulation (#72) * SwapperCalleePsm: Prevent swap amts not multiple of to18ConversionFactor * Remove requirement on SwapperCalleePsm amt --------- Co-authored-by: telome <> --- src/funnels/callees/SwapperCalleePsm.sol | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/funnels/callees/SwapperCalleePsm.sol b/src/funnels/callees/SwapperCalleePsm.sol index a6956fc2..cadec1e9 100644 --- a/src/funnels/callees/SwapperCalleePsm.sol +++ b/src/funnels/callees/SwapperCalleePsm.sol @@ -64,6 +64,8 @@ contract SwapperCalleePsm { emit Deny(usr); } + // Note: To avoid accumulating dust in this contract, `amt` should be a multiple of `to18ConversionFactor` when `src != gem`. + // This constraint is intentionally not enforced in this contract. function swapCallback(address src, address /* dst */, uint256 amt, uint256 /* minOut */, address to, bytes calldata /* data */) external auth { if (src == gem) PsmLike(psm).sellGemNoFee(to, amt); else PsmLike(psm).buyGemNoFee (to, amt / to18ConversionFactor); From 021fe8955ddafd1fac16cff18b0d3efd7d82b1c7 Mon Sep 17 00:00:00 2001 From: oldchili <130549691+oldchili@users.noreply.github.com> Date: Thu, 30 Nov 2023 13:44:42 +0200 Subject: [PATCH 66/74] Update audit report to version 4 (#73) --- ...hainSecurity_Maker_DSS_Allocator_audit.pdf | Bin 537709 -> 549327 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/audit/ChainSecurity_Maker_DSS_Allocator_audit.pdf b/audit/ChainSecurity_Maker_DSS_Allocator_audit.pdf index eff50f81337935f55211ecfc6d7cda73bd4ab753..beb511d17a49f2d7f3d501dbd439699928e0a1f1 100644 GIT binary patch delta 17342 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 delta 7789 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 From 584dab103749ab6be3005b27fb2468440ab62e68 Mon Sep 17 00:00:00 2001 From: oldchili <130549691+oldchili@users.noreply.github.com> Date: Mon, 4 Dec 2023 15:13:29 +0200 Subject: [PATCH 67/74] add cantina report (#74) --- ...ina-report-review-makerdao-dssallocator.pdf | Bin 0 -> 518086 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 audit/cantina-report-review-makerdao-dssallocator.pdf diff --git a/audit/cantina-report-review-makerdao-dssallocator.pdf b/audit/cantina-report-review-makerdao-dssallocator.pdf new file mode 100644 index 0000000000000000000000000000000000000000..eeddbdadd21afb0482a63ae8a584c31e5893d7d0 GIT binary patch literal 518086 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

    jY57c9Z< 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≷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

      S}@rUel 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 z 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%0AP#Mc38G>pQEH{b;3^}bYaQt*wt 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 literal 0 HcmV?d00001 From 8bcb7246af20d13984af6a944feffcd6d488a693 Mon Sep 17 00:00:00 2001 From: oldchili <130549691+oldchili@users.noreply.github.com> Date: Tue, 5 Dec 2023 18:11:30 +0200 Subject: [PATCH 68/74] Update CS audit report to version 5 (#75) --- ...hainSecurity_Maker_DSS_Allocator_audit.pdf | Bin 549327 -> 571990 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/audit/ChainSecurity_Maker_DSS_Allocator_audit.pdf b/audit/ChainSecurity_Maker_DSS_Allocator_audit.pdf index beb511d17a49f2d7f3d501dbd439699928e0a1f1..24901352035d493115fa50fd61906993c1de49f8 100644 GIT binary patch delta 28802 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 bQ&OQhaB{LVLI>#Q2>CkQx_J*Bp!5F##5)#M delta 14415 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 From de55fbae72145785f342b9180818d9ff3c25b319 Mon Sep 17 00:00:00 2001 From: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> Date: Mon, 8 Jan 2024 08:16:44 -0300 Subject: [PATCH 69/74] Update CS audit report to version 6 (#76) --- ...hainSecurity_Maker_DSS_Allocator_audit.pdf | Bin 571990 -> 596767 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/audit/ChainSecurity_Maker_DSS_Allocator_audit.pdf b/audit/ChainSecurity_Maker_DSS_Allocator_audit.pdf index 24901352035d493115fa50fd61906993c1de49f8..20b25a1f84d7356cad81d8d0f8e9e1d1badbd5f0 100644 GIT binary patch delta 34215 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 Date: Mon, 1 Jul 2024 16:58:16 +0300 Subject: [PATCH 70/74] README - mark funnels as obsolete (#77) --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 2554c4f1..1e2599a9 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,12 @@ Part of this code was inspired by https://github.com/makerdao/rwa-toolkit/blob/master/src/urns/RwaUrn.sol mainly authored by livnev and https://github.com/dapphub/ds-roles/blob/master/src/roles.sol authored by DappHub. Since it should belong to the MakerDAO community the Copyright from our additions has been transferred to Dai Foundation. +## Important Update: + +**The funnels in this repository and their automation contracts should now be regarded as included for illustrative purposes only. In practice, other use-case specialized funnels are expected to be built.** + +**The deployment libraries, tests and the documentation below still use the specific included funnels (e.g DepositorUniV3, Swapper). Those parts should be considered as obsolete.** + ## Overview Implementation of the allocation system, based on the [technical specification forum post](https://forum.makerdao.com/t/preliminary-technical-specification-of-the-allocation-system/20921). The conduits are implemented separately. See for example [dss-conduits](https://github.com/makerdao/dss-conduits). From d941baef928921009ce030facaa06df59f6eca92 Mon Sep 17 00:00:00 2001 From: Sam MacPherson Date: Fri, 23 Aug 2024 00:02:03 +0900 Subject: [PATCH 71/74] Split deploy/init scripts into core components and default funnels (#78) * split deploy/init scripts into core components and default funnels * review fixes --- deploy/AllocatorDeploy.sol | 40 ++++--- deploy/AllocatorInit.sol | 169 ++++++++++++++-------------- deploy/AllocatorInstances.sol | 4 + test/integration/Deployment.t.sol | 177 ++++++++++++++++-------------- 4 files changed, 215 insertions(+), 175 deletions(-) diff --git a/deploy/AllocatorDeploy.sol b/deploy/AllocatorDeploy.sol index a3c2cf56..eff32680 100644 --- a/deploy/AllocatorDeploy.sol +++ b/deploy/AllocatorDeploy.sol @@ -30,7 +30,7 @@ import { StableSwapper } from "src/funnels/automation/StableSwapper.sol"; import { StableDepositorUniV3 } from "src/funnels/automation/StableDepositorUniV3.sol"; import { ConduitMover } from "src/funnels/automation/ConduitMover.sol"; -import { AllocatorSharedInstance, AllocatorIlkInstance } from "./AllocatorInstances.sol"; +import { AllocatorSharedInstance, AllocatorIlkInstance, AllocatorIlkFunnelInstance } from "./AllocatorInstances.sol"; library AllocatorDeploy { @@ -59,8 +59,7 @@ library AllocatorDeploy { address owner, address roles, bytes32 ilk, - address nstJoin, - address uniV3Factory + address nstJoin ) internal returns (AllocatorIlkInstance memory ilkInstance) { address _buffer = address(new AllocatorBuffer()); ScriptTools.switchOwner(_buffer, deployer, owner); @@ -70,38 +69,51 @@ library AllocatorDeploy { ScriptTools.switchOwner(_vault, deployer, owner); ilkInstance.vault = _vault; - address _swapper = address(new Swapper(roles, ilk, _buffer)); + ilkInstance.owner = owner; + } + + // Note: owner is assumed to be the allocator proxy + function deployIlkFunnel( + address deployer, + address owner, + address roles, + bytes32 ilk, + address uniV3Factory, + address vault, + address buffer + ) internal returns (AllocatorIlkFunnelInstance memory ilkFunnelInstance) { + address _swapper = address(new Swapper(roles, ilk, buffer)); ScriptTools.switchOwner(_swapper, deployer, owner); - ilkInstance.swapper = _swapper; + ilkFunnelInstance.swapper = _swapper; - address _depositorUniV3 = address(new DepositorUniV3(roles, ilk, uniV3Factory, _buffer)); + address _depositorUniV3 = address(new DepositorUniV3(roles, ilk, uniV3Factory, buffer)); ScriptTools.switchOwner(_depositorUniV3, deployer, owner); - ilkInstance.depositorUniV3 = _depositorUniV3; + ilkFunnelInstance.depositorUniV3 = _depositorUniV3; { - address _vaultMinter = address(new VaultMinter(_vault)); + address _vaultMinter = address(new VaultMinter(vault)); ScriptTools.switchOwner(_vaultMinter, deployer, owner); - ilkInstance.vaultMinter = _vaultMinter; + ilkFunnelInstance.vaultMinter = _vaultMinter; } { address _stableSwapper = address(new StableSwapper(_swapper)); ScriptTools.switchOwner(_stableSwapper, deployer, owner); - ilkInstance.stableSwapper = _stableSwapper; + ilkFunnelInstance.stableSwapper = _stableSwapper; } { address _stableDepositorUniV3 = address(new StableDepositorUniV3(_depositorUniV3)); ScriptTools.switchOwner(_stableDepositorUniV3, deployer, owner); - ilkInstance.stableDepositorUniV3 = _stableDepositorUniV3; + ilkFunnelInstance.stableDepositorUniV3 = _stableDepositorUniV3; } { - address _conduitMover = address(new ConduitMover(ilk, _buffer)); + address _conduitMover = address(new ConduitMover(ilk, buffer)); ScriptTools.switchOwner(_conduitMover, deployer, owner); - ilkInstance.conduitMover = _conduitMover; + ilkFunnelInstance.conduitMover = _conduitMover; } - ilkInstance.owner = owner; + ilkFunnelInstance.owner = owner; } } diff --git a/deploy/AllocatorInit.sol b/deploy/AllocatorInit.sol index 6d056b1b..08c3d8d7 100644 --- a/deploy/AllocatorInit.sol +++ b/deploy/AllocatorInit.sol @@ -18,7 +18,7 @@ pragma solidity >=0.8.0; import { ScriptTools } from "dss-test/ScriptTools.sol"; import { DssInstance } from "dss-test/MCD.sol"; -import { AllocatorSharedInstance, AllocatorIlkInstance } from "./AllocatorInstances.sol"; +import { AllocatorSharedInstance, AllocatorIlkInstance, AllocatorIlkFunnelInstance } from "./AllocatorInstances.sol"; interface WardsLike { function rely(address) external; @@ -134,6 +134,12 @@ struct AllocatorIlkConfig { uint256 maxLine; uint256 ttl; address allocatorProxy; + address ilkRegistry; +} + +struct AllocatorIlkFunnelConfig { + bytes32 ilk; + address allocatorProxy; uint8 facilitatorRole; uint8 automationRole; address[] facilitators; @@ -143,7 +149,6 @@ struct AllocatorIlkConfig { address[] conduitMoverKeepers; address[] swapTokens; address[] depositTokens; - address ilkRegistry; address uniV3Factory; } @@ -172,6 +177,7 @@ library AllocatorInit { dss.chainlog.setAddress("ALLOCATOR_REGISTRY", sharedInstance.registry); } + // Please note this should be executed by the pause proxy function initIlk( DssInstance memory dss, AllocatorSharedInstance memory sharedInstance, @@ -187,23 +193,6 @@ library AllocatorInit { require(VaultLike(ilkInstance.vault).vat() == address(dss.vat), "AllocatorInit/vault-vat-mismatch"); // Once nstJoin is in the chainlog and adapted to dss-test should also check against it - require(SwapperLike(ilkInstance.swapper).roles() == sharedInstance.roles, "AllocatorInit/swapper-roles-mismatch"); - require(SwapperLike(ilkInstance.swapper).ilk() == ilk, "AllocatorInit/swapper-ilk-mismatch"); - require(SwapperLike(ilkInstance.swapper).buffer() == ilkInstance.buffer, "AllocatorInit/swapper-buffer-mismatch"); - - require(DepositorUniV3Like(ilkInstance.depositorUniV3).roles() == sharedInstance.roles, "AllocatorInit/depositorUniV3-roles-mismatch"); - require(DepositorUniV3Like(ilkInstance.depositorUniV3).ilk() == ilk, "AllocatorInit/depositorUniV3-ilk-mismatch"); - require(DepositorUniV3Like(ilkInstance.depositorUniV3).uniV3Factory() == cfg.uniV3Factory, "AllocatorInit/depositorUniV3-uniV3Factory-mismatch"); - require(DepositorUniV3Like(ilkInstance.depositorUniV3).buffer() == ilkInstance.buffer, "AllocatorInit/depositorUniV3-buffer-mismatch"); - - require(VaultMinterLike(ilkInstance.vaultMinter).vault() == ilkInstance.vault, "AllocatorInit/vaultMinter-vault-mismatch"); - - require(StableSwapperLike(ilkInstance.stableSwapper).swapper() == ilkInstance.swapper, "AllocatorInit/stableSwapper-swapper-mismatch"); - require(StableDepositorUniV3Like(ilkInstance.stableDepositorUniV3).depositor() == ilkInstance.depositorUniV3, "AllocatorInit/stableDepositorUniV3-depositorUniV3-mismatch"); - - require(ConduitMoverLike(ilkInstance.conduitMover).ilk() == ilk, "AllocatorInit/conduitMover-ilk-mismatch"); - require(ConduitMoverLike(ilkInstance.conduitMover).buffer() == ilkInstance.buffer, "AllocatorInit/conduitMover-buffer-mismatch"); - // Onboard the ilk dss.vat.init(ilk); dss.jug.init(ilk); @@ -228,94 +217,114 @@ library AllocatorInit { VaultLike(ilkInstance.vault).file("jug", address(dss.jug)); - // Allow vault and funnels to pull funds from the buffer + // Allow vault to pull funds from the buffer BufferLike(ilkInstance.buffer).approve(VaultLike(ilkInstance.vault).nst(), ilkInstance.vault, type(uint256).max); + + // Set the allocator proxy as the ilk admin instead of the Pause Proxy + RolesLike(sharedInstance.roles).setIlkAdmin(ilk, cfg.allocatorProxy); + + // Move ownership of the ilk contracts to the allocator proxy + ScriptTools.switchOwner(ilkInstance.vault, ilkInstance.owner, cfg.allocatorProxy); + ScriptTools.switchOwner(ilkInstance.buffer, ilkInstance.owner, cfg.allocatorProxy); + + // Add allocator-specific contracts to changelog + string memory ilkString = ScriptTools.ilkToChainlogFormat(ilk); + dss.chainlog.setAddress(ScriptTools.stringToBytes32(string(abi.encodePacked(ilkString, "_VAULT"))), ilkInstance.vault); + dss.chainlog.setAddress(ScriptTools.stringToBytes32(string(abi.encodePacked(ilkString, "_BUFFER"))), ilkInstance.buffer); + dss.chainlog.setAddress(ScriptTools.stringToBytes32(string(abi.encodePacked("PIP_", ilkString))), sharedInstance.oracle); + + // Add to ilk registry + IlkRegistryLike(cfg.ilkRegistry).put({ + _ilk : ilk, + _join : address(0), + _gem : address(0), + _dec : 0, + _class : 5, // RWAs are class 3, D3Ms and Teleport are class 4 + _pip : sharedInstance.oracle, + _xlip : address(0), + _name : bytes32ToStr(ilk), + _symbol : bytes32ToStr(ilk) + }); + } + + // Please note this should be executed by the allocator proxy + function initIlkFunnel( + AllocatorSharedInstance memory sharedInstance, + AllocatorIlkInstance memory ilkInstance, + AllocatorIlkFunnelInstance memory ilkFunnelInstance, + AllocatorIlkFunnelConfig memory cfg + ) internal { + bytes32 ilk = cfg.ilk; + + require(SwapperLike(ilkFunnelInstance.swapper).roles() == sharedInstance.roles, "AllocatorInit/swapper-roles-mismatch"); + require(SwapperLike(ilkFunnelInstance.swapper).ilk() == ilk, "AllocatorInit/swapper-ilk-mismatch"); + require(SwapperLike(ilkFunnelInstance.swapper).buffer() == ilkInstance.buffer, "AllocatorInit/swapper-buffer-mismatch"); + + require(DepositorUniV3Like(ilkFunnelInstance.depositorUniV3).roles() == sharedInstance.roles, "AllocatorInit/depositorUniV3-roles-mismatch"); + require(DepositorUniV3Like(ilkFunnelInstance.depositorUniV3).ilk() == ilk, "AllocatorInit/depositorUniV3-ilk-mismatch"); + require(DepositorUniV3Like(ilkFunnelInstance.depositorUniV3).uniV3Factory() == cfg.uniV3Factory, "AllocatorInit/depositorUniV3-uniV3Factory-mismatch"); + require(DepositorUniV3Like(ilkFunnelInstance.depositorUniV3).buffer() == ilkInstance.buffer, "AllocatorInit/depositorUniV3-buffer-mismatch"); + + require(VaultMinterLike(ilkFunnelInstance.vaultMinter).vault() == ilkInstance.vault, "AllocatorInit/vaultMinter-vault-mismatch"); + + require(StableSwapperLike(ilkFunnelInstance.stableSwapper).swapper() == ilkFunnelInstance.swapper, "AllocatorInit/stableSwapper-swapper-mismatch"); + require(StableDepositorUniV3Like(ilkFunnelInstance.stableDepositorUniV3).depositor() == ilkFunnelInstance.depositorUniV3, "AllocatorInit/stableDepositorUniV3-depositorUniV3-mismatch"); + + require(ConduitMoverLike(ilkFunnelInstance.conduitMover).ilk() == ilk, "AllocatorInit/conduitMover-ilk-mismatch"); + require(ConduitMoverLike(ilkFunnelInstance.conduitMover).buffer() == ilkInstance.buffer, "AllocatorInit/conduitMover-buffer-mismatch"); + + // Allow vault and funnels to pull funds from the buffer for(uint256 i = 0; i < cfg.swapTokens.length; i++) { - BufferLike(ilkInstance.buffer).approve(cfg.swapTokens[i], ilkInstance.swapper, type(uint256).max); + BufferLike(ilkInstance.buffer).approve(cfg.swapTokens[i], ilkFunnelInstance.swapper, type(uint256).max); } for(uint256 i = 0; i < cfg.depositTokens.length; i++) { - BufferLike(ilkInstance.buffer).approve(cfg.depositTokens[i], ilkInstance.depositorUniV3, type(uint256).max); + BufferLike(ilkInstance.buffer).approve(cfg.depositTokens[i], ilkFunnelInstance.depositorUniV3, type(uint256).max); } - // Set the pause proxy temporarily as ilk admin so we can set all the roles below - RolesLike(sharedInstance.roles).setIlkAdmin(ilk, ilkInstance.owner); - // Allow the facilitators to operate on the vault and funnels directly for(uint256 i = 0; i < cfg.facilitators.length; i++) { RolesLike(sharedInstance.roles).setUserRole(ilk, cfg.facilitators[i], cfg.facilitatorRole, true); } - RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.facilitatorRole, ilkInstance.vault, VaultLike.draw.selector, true); - RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.facilitatorRole, ilkInstance.vault, VaultLike.wipe.selector, true); - RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.facilitatorRole, ilkInstance.swapper, SwapperLike.swap.selector, true); - RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.facilitatorRole, ilkInstance.depositorUniV3, DepositorUniV3Like.deposit.selector, true); - RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.facilitatorRole, ilkInstance.depositorUniV3, DepositorUniV3Like.withdraw.selector, true); - RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.facilitatorRole, ilkInstance.depositorUniV3, DepositorUniV3Like.collect.selector, true); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.facilitatorRole, ilkInstance.vault, VaultLike.draw.selector, true); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.facilitatorRole, ilkInstance.vault, VaultLike.wipe.selector, true); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.facilitatorRole, ilkFunnelInstance.swapper, SwapperLike.swap.selector, true); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.facilitatorRole, ilkFunnelInstance.depositorUniV3, DepositorUniV3Like.deposit.selector, true); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.facilitatorRole, ilkFunnelInstance.depositorUniV3, DepositorUniV3Like.withdraw.selector, true); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.facilitatorRole, ilkFunnelInstance.depositorUniV3, DepositorUniV3Like.collect.selector, true); // Allow the automation contracts to operate on the funnels - RolesLike(sharedInstance.roles).setUserRole(ilk, ilkInstance.vaultMinter, cfg.automationRole, true); - RolesLike(sharedInstance.roles).setUserRole(ilk, ilkInstance.stableSwapper, cfg.automationRole, true); - RolesLike(sharedInstance.roles).setUserRole(ilk, ilkInstance.stableDepositorUniV3, cfg.automationRole, true); + RolesLike(sharedInstance.roles).setUserRole(ilk, ilkFunnelInstance.vaultMinter, cfg.automationRole, true); + RolesLike(sharedInstance.roles).setUserRole(ilk, ilkFunnelInstance.stableSwapper, cfg.automationRole, true); + RolesLike(sharedInstance.roles).setUserRole(ilk, ilkFunnelInstance.stableDepositorUniV3, cfg.automationRole, true); - RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkInstance.vault, VaultLike.draw.selector, true); - RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkInstance.vault, VaultLike.wipe.selector, true); - RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkInstance.swapper, SwapperLike.swap.selector, true); - RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkInstance.depositorUniV3, DepositorUniV3Like.deposit.selector, true); - RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkInstance.depositorUniV3, DepositorUniV3Like.withdraw.selector, true); - RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkInstance.depositorUniV3, DepositorUniV3Like.collect.selector, true); - - // Set the allocator proxy as the ilk admin instead of the Pause Proxy - RolesLike(sharedInstance.roles).setIlkAdmin(ilk, cfg.allocatorProxy); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkInstance.vault, VaultLike.draw.selector, true); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkInstance.vault, VaultLike.wipe.selector, true); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkFunnelInstance.swapper, SwapperLike.swap.selector, true); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkFunnelInstance.depositorUniV3, DepositorUniV3Like.deposit.selector, true); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkFunnelInstance.depositorUniV3, DepositorUniV3Like.withdraw.selector, true); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkFunnelInstance.depositorUniV3, DepositorUniV3Like.collect.selector, true); // Allow facilitator to set configurations in the automation contracts for(uint256 i = 0; i < cfg.facilitators.length; i++) { - WardsLike(ilkInstance.vaultMinter).rely(cfg.facilitators[i]); - WardsLike(ilkInstance.stableSwapper).rely(cfg.facilitators[i]); - WardsLike(ilkInstance.stableDepositorUniV3).rely(cfg.facilitators[i]); - WardsLike(ilkInstance.conduitMover).rely(cfg.facilitators[i]); + WardsLike(ilkFunnelInstance.vaultMinter).rely(cfg.facilitators[i]); + WardsLike(ilkFunnelInstance.stableSwapper).rely(cfg.facilitators[i]); + WardsLike(ilkFunnelInstance.stableDepositorUniV3).rely(cfg.facilitators[i]); + WardsLike(ilkFunnelInstance.conduitMover).rely(cfg.facilitators[i]); } // Add keepers to the automation contracts for(uint256 i = 0; i < cfg.vaultMinterKeepers.length; i++) { - KissLike(ilkInstance.vaultMinter).kiss(cfg.vaultMinterKeepers[i]); + KissLike(ilkFunnelInstance.vaultMinter).kiss(cfg.vaultMinterKeepers[i]); } for(uint256 i = 0; i < cfg.stableSwapperKeepers.length; i++) { - KissLike(ilkInstance.stableSwapper).kiss(cfg.stableSwapperKeepers[i]); + KissLike(ilkFunnelInstance.stableSwapper).kiss(cfg.stableSwapperKeepers[i]); } for(uint256 i = 0; i < cfg.stableDepositorUniV3Keepers.length; i++) { - KissLike(ilkInstance.stableDepositorUniV3).kiss(cfg.stableDepositorUniV3Keepers[i]); + KissLike(ilkFunnelInstance.stableDepositorUniV3).kiss(cfg.stableDepositorUniV3Keepers[i]); } for(uint256 i = 0; i < cfg.conduitMoverKeepers.length; i++) { - KissLike(ilkInstance.conduitMover).kiss(cfg.conduitMoverKeepers[i]); + KissLike(ilkFunnelInstance.conduitMover).kiss(cfg.conduitMoverKeepers[i]); } - - // Move ownership of the ilk contracts to the allocator proxy - ScriptTools.switchOwner(ilkInstance.vault, ilkInstance.owner, cfg.allocatorProxy); - ScriptTools.switchOwner(ilkInstance.buffer, ilkInstance.owner, cfg.allocatorProxy); - ScriptTools.switchOwner(ilkInstance.swapper, ilkInstance.owner, cfg.allocatorProxy); - ScriptTools.switchOwner(ilkInstance.depositorUniV3, ilkInstance.owner, cfg.allocatorProxy); - ScriptTools.switchOwner(ilkInstance.vaultMinter, ilkInstance.owner, cfg.allocatorProxy); - ScriptTools.switchOwner(ilkInstance.stableSwapper, ilkInstance.owner, cfg.allocatorProxy); - ScriptTools.switchOwner(ilkInstance.stableDepositorUniV3, ilkInstance.owner, cfg.allocatorProxy); - ScriptTools.switchOwner(ilkInstance.conduitMover, ilkInstance.owner, cfg.allocatorProxy); - - // Add allocator-specific contracts to changelog - string memory ilkString = ScriptTools.ilkToChainlogFormat(ilk); - dss.chainlog.setAddress(ScriptTools.stringToBytes32(string(abi.encodePacked(ilkString, "_VAULT"))), ilkInstance.vault); - dss.chainlog.setAddress(ScriptTools.stringToBytes32(string(abi.encodePacked(ilkString, "_BUFFER"))), ilkInstance.buffer); - dss.chainlog.setAddress(ScriptTools.stringToBytes32(string(abi.encodePacked("PIP_", ilkString))), sharedInstance.oracle); - - // Add to ilk registry - IlkRegistryLike(cfg.ilkRegistry).put({ - _ilk : ilk, - _join : address(0), - _gem : address(0), - _dec : 0, - _class : 5, // RWAs are class 3, D3Ms and Teleport are class 4 - _pip : sharedInstance.oracle, - _xlip : address(0), - _name : bytes32ToStr(ilk), - _symbol : bytes32ToStr(ilk) - }); } } diff --git a/deploy/AllocatorInstances.sol b/deploy/AllocatorInstances.sol index c3bd633e..092db88c 100644 --- a/deploy/AllocatorInstances.sol +++ b/deploy/AllocatorInstances.sol @@ -26,6 +26,10 @@ struct AllocatorIlkInstance { address owner; address vault; address buffer; +} + +struct AllocatorIlkFunnelInstance { + address owner; address swapper; address depositorUniV3; address vaultMinter; diff --git a/test/integration/Deployment.t.sol b/test/integration/Deployment.t.sol index 5770e1a1..35379b84 100644 --- a/test/integration/Deployment.t.sol +++ b/test/integration/Deployment.t.sol @@ -18,9 +18,9 @@ pragma solidity ^0.8.16; import "dss-test/DssTest.sol"; -import { AllocatorSharedInstance, AllocatorIlkInstance } from "deploy/AllocatorInstances.sol"; +import { AllocatorSharedInstance, AllocatorIlkInstance, AllocatorIlkFunnelInstance } from "deploy/AllocatorInstances.sol"; import { AllocatorDeploy } from "deploy/AllocatorDeploy.sol"; -import { AllocatorInit, AllocatorIlkConfig } from "deploy/AllocatorInit.sol"; +import { AllocatorInit, AllocatorIlkConfig, AllocatorIlkFunnelConfig } from "deploy/AllocatorInit.sol"; import { SwapperCalleeUniV3 } from "src/funnels/callees/SwapperCalleeUniV3.sol"; @@ -111,6 +111,7 @@ contract DeploymentTest is DssTest { // storage to be initiated on setup AllocatorSharedInstance sharedInst; AllocatorIlkInstance ilkInst; + AllocatorIlkFunnelInstance ilkFunnelInst; bytes usdcDaiPath; bytes daiUsdcPath; @@ -139,8 +140,16 @@ contract DeploymentTest is DssTest { owner : PAUSE_PROXY, roles : sharedInst.roles, ilk : ILK, - nstJoin : nstJoin, - uniV3Factory : UNIV3_FACTORY + nstJoin : nstJoin + }); + ilkFunnelInst = AllocatorDeploy.deployIlkFunnel({ + deployer : address(this), + owner : allocatorProxy, + roles : sharedInst.roles, + ilk : ILK, + uniV3Factory : UNIV3_FACTORY, + vault : ilkInst.vault, + buffer : ilkInst.buffer }); // Deploy conduits (assumed to be done separately than the current allocator ilkInst deploy) @@ -186,6 +195,17 @@ contract DeploymentTest is DssTest { gap : 10_000_000 * RAD, ttl : 1 days, allocatorProxy : allocatorProxy, + ilkRegistry : ILK_REGISTRY + }); + + AllocatorInit.initIlk(dss, sharedInst, ilkInst, cfg); + vm.stopPrank(); + + // Init conduits (assumed to be done separately than the current allocator ilkInst init) + vm.startPrank(allocatorProxy); + AllocatorIlkFunnelConfig memory funnelCfg = AllocatorIlkFunnelConfig({ + ilk : ILK, + allocatorProxy : allocatorProxy, facilitatorRole : facilitatorRole, automationRole : automationRole, facilitators : facilitators, @@ -195,16 +215,11 @@ contract DeploymentTest is DssTest { conduitMoverKeepers : conduitMoverKeepers, swapTokens : swapTokens, depositTokens : depositTokens, - ilkRegistry : ILK_REGISTRY, uniV3Factory : UNIV3_FACTORY }); + AllocatorInit.initIlkFunnel(sharedInst, ilkInst, ilkFunnelInst, funnelCfg); - AllocatorInit.initIlk(dss, sharedInst, ilkInst, cfg); - vm.stopPrank(); - - // Init conduits (assumed to be done separately than the current allocator ilkInst init) - vm.startPrank(allocatorProxy); - AllocatorRoles(sharedInst.roles).setUserRole(ILK, address(ilkInst.conduitMover), automationRole, true); + AllocatorRoles(sharedInst.roles).setUserRole(ILK, address(ilkFunnelInst.conduitMover), automationRole, true); AllocatorRoles(sharedInst.roles).setRoleAction(ILK, automationRole, conduit1, AllocatorConduitMock.deposit.selector, true); AllocatorRoles(sharedInst.roles).setRoleAction(ILK, automationRole, conduit1, AllocatorConduitMock.withdraw.selector, true); @@ -261,48 +276,48 @@ contract DeploymentTest is DssTest { assertEq(AllocatorRegistry(sharedInst.registry).buffers(ILK), ilkInst.buffer); assertEq(address(AllocatorVault(ilkInst.vault).jug()), address(dss.jug)); - assertEq(GemLike(nst).allowance(ilkInst.buffer, ilkInst.vault), type(uint256).max); - assertEq(GemLike(address(dss.dai)).allowance(ilkInst.buffer, ilkInst.swapper), type(uint256).max); - assertEq(GemLike(address(dss.dai)).allowance(ilkInst.buffer, ilkInst.depositorUniV3), type(uint256).max); - assertEq(GemLike(USDC).allowance(ilkInst.buffer, ilkInst.depositorUniV3), type(uint256).max); + assertEq(GemLike(nst).allowance(ilkInst.buffer, ilkInst.vault), type(uint256).max); + assertEq(GemLike(address(dss.dai)).allowance(ilkInst.buffer, ilkFunnelInst.swapper), type(uint256).max); + assertEq(GemLike(address(dss.dai)).allowance(ilkInst.buffer, ilkFunnelInst.depositorUniV3), type(uint256).max); + assertEq(GemLike(USDC).allowance(ilkInst.buffer, ilkFunnelInst.depositorUniV3), type(uint256).max); assertEq(AllocatorRoles(sharedInst.roles).ilkAdmins(ILK), allocatorProxy); assertEq(AllocatorRoles(sharedInst.roles).hasUserRole(ILK, facilitator1, facilitatorRole), true); assertEq(AllocatorRoles(sharedInst.roles).hasUserRole(ILK, facilitator2, facilitatorRole), true); - assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkInst.vault, AllocatorVault.draw.selector, facilitatorRole), true); - assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkInst.vault, AllocatorVault.wipe.selector, facilitatorRole), true); - assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkInst.swapper, Swapper.swap.selector, facilitatorRole), true); - assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkInst.depositorUniV3, DepositorUniV3.deposit.selector, facilitatorRole), true); - assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkInst.depositorUniV3, DepositorUniV3.withdraw.selector, facilitatorRole), true); - assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkInst.depositorUniV3, DepositorUniV3.collect.selector, facilitatorRole), true); - - assertEq(AllocatorRoles(sharedInst.roles).hasUserRole(ILK, ilkInst.stableSwapper, automationRole), true); - assertEq(AllocatorRoles(sharedInst.roles).hasUserRole(ILK, ilkInst.stableDepositorUniV3, automationRole), true); - - assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkInst.swapper, Swapper.swap.selector, automationRole), true); - assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkInst.depositorUniV3, DepositorUniV3.deposit.selector, automationRole), true); - assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkInst.depositorUniV3, DepositorUniV3.withdraw.selector, automationRole), true); - assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkInst.depositorUniV3, DepositorUniV3.collect.selector, automationRole), true); - - assertEq(WardsLike(ilkInst.vaultMinter).wards(facilitator1), 1); - assertEq(WardsLike(ilkInst.vaultMinter).wards(facilitator2), 1); - assertEq(WardsLike(ilkInst.stableSwapper).wards(facilitator1), 1); - assertEq(WardsLike(ilkInst.stableSwapper).wards(facilitator2), 1); - assertEq(WardsLike(ilkInst.stableDepositorUniV3).wards(facilitator1), 1); - assertEq(WardsLike(ilkInst.stableDepositorUniV3).wards(facilitator2), 1); - assertEq(WardsLike(ilkInst.conduitMover).wards(facilitator1), 1); - assertEq(WardsLike(ilkInst.conduitMover).wards(facilitator2), 1); - - assertEq(VaultMinter(ilkInst.vaultMinter).buds(vaultMinterKeeper1), 1); - assertEq(VaultMinter(ilkInst.vaultMinter).buds(vaultMinterKeeper2), 1); - assertEq(StableSwapper(ilkInst.stableSwapper).buds(stableSwapperKeeper1), 1); - assertEq(StableSwapper(ilkInst.stableSwapper).buds(stableSwapperKeeper2), 1); - assertEq(StableDepositorUniV3(ilkInst.stableDepositorUniV3).buds(stableDepositorUniV3Keeper1), 1); - assertEq(StableDepositorUniV3(ilkInst.stableDepositorUniV3).buds(stableDepositorUniV3Keeper2), 1); - assertEq(ConduitMover(ilkInst.conduitMover).buds(conduitMoverKeeper1), 1); - assertEq(ConduitMover(ilkInst.conduitMover).buds(conduitMoverKeeper2), 1); + assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkInst.vault, AllocatorVault.draw.selector, facilitatorRole), true); + assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkInst.vault, AllocatorVault.wipe.selector, facilitatorRole), true); + assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkFunnelInst.swapper, Swapper.swap.selector, facilitatorRole), true); + assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkFunnelInst.depositorUniV3, DepositorUniV3.deposit.selector, facilitatorRole), true); + assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkFunnelInst.depositorUniV3, DepositorUniV3.withdraw.selector, facilitatorRole), true); + assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkFunnelInst.depositorUniV3, DepositorUniV3.collect.selector, facilitatorRole), true); + + assertEq(AllocatorRoles(sharedInst.roles).hasUserRole(ILK, ilkFunnelInst.stableSwapper, automationRole), true); + assertEq(AllocatorRoles(sharedInst.roles).hasUserRole(ILK, ilkFunnelInst.stableDepositorUniV3, automationRole), true); + + assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkFunnelInst.swapper, Swapper.swap.selector, automationRole), true); + assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkFunnelInst.depositorUniV3, DepositorUniV3.deposit.selector, automationRole), true); + assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkFunnelInst.depositorUniV3, DepositorUniV3.withdraw.selector, automationRole), true); + assertEq(AllocatorRoles(sharedInst.roles).hasActionRole(ILK, ilkFunnelInst.depositorUniV3, DepositorUniV3.collect.selector, automationRole), true); + + assertEq(WardsLike(ilkFunnelInst.vaultMinter).wards(facilitator1), 1); + assertEq(WardsLike(ilkFunnelInst.vaultMinter).wards(facilitator2), 1); + assertEq(WardsLike(ilkFunnelInst.stableSwapper).wards(facilitator1), 1); + assertEq(WardsLike(ilkFunnelInst.stableSwapper).wards(facilitator2), 1); + assertEq(WardsLike(ilkFunnelInst.stableDepositorUniV3).wards(facilitator1), 1); + assertEq(WardsLike(ilkFunnelInst.stableDepositorUniV3).wards(facilitator2), 1); + assertEq(WardsLike(ilkFunnelInst.conduitMover).wards(facilitator1), 1); + assertEq(WardsLike(ilkFunnelInst.conduitMover).wards(facilitator2), 1); + + assertEq(VaultMinter(ilkFunnelInst.vaultMinter).buds(vaultMinterKeeper1), 1); + assertEq(VaultMinter(ilkFunnelInst.vaultMinter).buds(vaultMinterKeeper2), 1); + assertEq(StableSwapper(ilkFunnelInst.stableSwapper).buds(stableSwapperKeeper1), 1); + assertEq(StableSwapper(ilkFunnelInst.stableSwapper).buds(stableSwapperKeeper2), 1); + assertEq(StableDepositorUniV3(ilkFunnelInst.stableDepositorUniV3).buds(stableDepositorUniV3Keeper1), 1); + assertEq(StableDepositorUniV3(ilkFunnelInst.stableDepositorUniV3).buds(stableDepositorUniV3Keeper2), 1); + assertEq(ConduitMover(ilkFunnelInst.conduitMover).buds(conduitMoverKeeper1), 1); + assertEq(ConduitMover(ilkFunnelInst.conduitMover).buds(conduitMoverKeeper2), 1); assertEq(WardsLike(ilkInst.vault).wards(PAUSE_PROXY), 0); assertEq(WardsLike(ilkInst.vault).wards(allocatorProxy), 1); @@ -310,23 +325,23 @@ contract DeploymentTest is DssTest { assertEq(WardsLike(ilkInst.buffer).wards(PAUSE_PROXY), 0); assertEq(WardsLike(ilkInst.buffer).wards(allocatorProxy), 1); - assertEq(WardsLike(ilkInst.swapper).wards(PAUSE_PROXY), 0); - assertEq(WardsLike(ilkInst.swapper).wards(allocatorProxy), 1); + assertEq(WardsLike(ilkFunnelInst.swapper).wards(PAUSE_PROXY), 0); + assertEq(WardsLike(ilkFunnelInst.swapper).wards(allocatorProxy), 1); - assertEq(WardsLike(ilkInst.depositorUniV3).wards(PAUSE_PROXY), 0); - assertEq(WardsLike(ilkInst.depositorUniV3).wards(allocatorProxy), 1); + assertEq(WardsLike(ilkFunnelInst.depositorUniV3).wards(PAUSE_PROXY), 0); + assertEq(WardsLike(ilkFunnelInst.depositorUniV3).wards(allocatorProxy), 1); - assertEq(WardsLike(ilkInst.vaultMinter).wards(PAUSE_PROXY), 0); - assertEq(WardsLike(ilkInst.vaultMinter).wards(allocatorProxy), 1); + assertEq(WardsLike(ilkFunnelInst.vaultMinter).wards(PAUSE_PROXY), 0); + assertEq(WardsLike(ilkFunnelInst.vaultMinter).wards(allocatorProxy), 1); - assertEq(WardsLike(ilkInst.stableSwapper).wards(PAUSE_PROXY), 0); - assertEq(WardsLike(ilkInst.stableSwapper).wards(allocatorProxy), 1); + assertEq(WardsLike(ilkFunnelInst.stableSwapper).wards(PAUSE_PROXY), 0); + assertEq(WardsLike(ilkFunnelInst.stableSwapper).wards(allocatorProxy), 1); - assertEq(WardsLike(ilkInst.stableDepositorUniV3).wards(PAUSE_PROXY), 0); - assertEq(WardsLike(ilkInst.stableDepositorUniV3).wards(allocatorProxy), 1); + assertEq(WardsLike(ilkFunnelInst.stableDepositorUniV3).wards(PAUSE_PROXY), 0); + assertEq(WardsLike(ilkFunnelInst.stableDepositorUniV3).wards(allocatorProxy), 1); - assertEq(WardsLike(ilkInst.conduitMover).wards(PAUSE_PROXY), 0); - assertEq(WardsLike(ilkInst.conduitMover).wards(allocatorProxy), 1); + assertEq(WardsLike(ilkFunnelInst.conduitMover).wards(PAUSE_PROXY), 0); + assertEq(WardsLike(ilkFunnelInst.conduitMover).wards(allocatorProxy), 1); assertEq(ChainlogLike(LOG).getAddress("ILK_A_VAULT"), ilkInst.vault); assertEq(ChainlogLike(LOG).getAddress("ILK_A_BUFFER"), ilkInst.buffer); @@ -354,11 +369,11 @@ contract DeploymentTest is DssTest { function testVaultDrawWipeFromFromKeeper() public { emulateSpell(); - vm.prank(facilitator1); VaultMinter(ilkInst.vaultMinter).setConfig(1, 1 hours, uint96(1_000 * WAD)); - vm.prank(vaultMinterKeeper1); VaultMinter(ilkInst.vaultMinter).draw(); + vm.prank(facilitator1); VaultMinter(ilkFunnelInst.vaultMinter).setConfig(1, 1 hours, uint96(1_000 * WAD)); + vm.prank(vaultMinterKeeper1); VaultMinter(ilkFunnelInst.vaultMinter).draw(); - vm.prank(facilitator1); VaultMinter(ilkInst.vaultMinter).setConfig(-1, 1 hours, uint96(1_000 * WAD)); - vm.prank(vaultMinterKeeper1); VaultMinter(ilkInst.vaultMinter).wipe(); + vm.prank(facilitator1); VaultMinter(ilkFunnelInst.vaultMinter).setConfig(-1, 1 hours, uint96(1_000 * WAD)); + vm.prank(vaultMinterKeeper1); VaultMinter(ilkFunnelInst.vaultMinter).wipe(); } function testSwapFromFacilitator() public { @@ -366,8 +381,8 @@ contract DeploymentTest is DssTest { deal(address(dss.dai), ilkInst.buffer, 1_000 * WAD); - vm.prank(allocatorProxy); Swapper(ilkInst.swapper).setLimits(address(dss.dai), USDC, uint96(1_000 * WAD), 1 hours); - vm.prank(facilitator1); Swapper(ilkInst.swapper).swap(address(dss.dai), USDC, 1_000 * WAD, 990 * 10**6 , uniV3Callee, daiUsdcPath); + vm.prank(allocatorProxy); Swapper(ilkFunnelInst.swapper).setLimits(address(dss.dai), USDC, uint96(1_000 * WAD), 1 hours); + vm.prank(facilitator1); Swapper(ilkFunnelInst.swapper).swap(address(dss.dai), USDC, 1_000 * WAD, 990 * 10**6 , uniV3Callee, daiUsdcPath); } function testSwapFromKeeper() public { @@ -375,9 +390,9 @@ contract DeploymentTest is DssTest { deal(address(dss.dai), ilkInst.buffer, 1_000 * WAD); - vm.prank(allocatorProxy); Swapper(ilkInst.swapper).setLimits(address(dss.dai), USDC, uint96(1_000 * WAD), 1 hours); - vm.prank(facilitator1); StableSwapper(ilkInst.stableSwapper).setConfig(address(dss.dai), USDC, 1, 1 hours, uint96(1_000 * WAD), uint96(990 * 10**6)); - vm.prank(stableSwapperKeeper1); StableSwapper(ilkInst.stableSwapper).swap(address(dss.dai), USDC, 990 * 10**6, uniV3Callee, daiUsdcPath); + vm.prank(allocatorProxy); Swapper(ilkFunnelInst.swapper).setLimits(address(dss.dai), USDC, uint96(1_000 * WAD), 1 hours); + vm.prank(facilitator1); StableSwapper(ilkFunnelInst.stableSwapper).setConfig(address(dss.dai), USDC, 1, 1 hours, uint96(1_000 * WAD), uint96(990 * 10**6)); + vm.prank(stableSwapperKeeper1); StableSwapper(ilkFunnelInst.stableSwapper).swap(address(dss.dai), USDC, 990 * 10**6, uniV3Callee, daiUsdcPath); } function testDepositWithdrawCollectFromFacilitator() public { @@ -386,7 +401,7 @@ contract DeploymentTest is DssTest { deal(address(dss.dai), ilkInst.buffer, 1_000 * WAD); deal(USDC, ilkInst.buffer, 1_000 * 10**6); - vm.prank(allocatorProxy); DepositorUniV3(ilkInst.depositorUniV3).setLimits(address(dss.dai), USDC, uint24(100), uint96(2_000 * WAD), uint96(2_000 * 10**6), 1 hours); + vm.prank(allocatorProxy); DepositorUniV3(ilkFunnelInst.depositorUniV3).setLimits(address(dss.dai), USDC, uint24(100), uint96(2_000 * WAD), uint96(2_000 * 10**6), 1 hours); DepositorUniV3.LiquidityParams memory dp = DepositorUniV3.LiquidityParams({ gem0 : address(dss.dai), gem1 : USDC, @@ -400,8 +415,8 @@ contract DeploymentTest is DssTest { amt1Min : 900 * 10**6 }); - vm.prank(facilitator1); DepositorUniV3(ilkInst.depositorUniV3).deposit(dp); - vm.prank(facilitator1); DepositorUniV3(ilkInst.depositorUniV3).withdraw(dp, false); + vm.prank(facilitator1); DepositorUniV3(ilkFunnelInst.depositorUniV3).deposit(dp); + vm.prank(facilitator1); DepositorUniV3(ilkFunnelInst.depositorUniV3).withdraw(dp, false); DepositorUniV3.CollectParams memory cp = DepositorUniV3.CollectParams({ gem0 : address(dss.dai), @@ -412,7 +427,7 @@ contract DeploymentTest is DssTest { }); vm.expectRevert(bytes("NP")); // we make sure it reverts since no fees to collect and not because the call is unauthorized - vm.prank(facilitator1); DepositorUniV3(ilkInst.depositorUniV3).collect(cp); + vm.prank(facilitator1); DepositorUniV3(ilkFunnelInst.depositorUniV3).collect(cp); } function testDepositWithdrawCollectFromKeeper() public { @@ -421,16 +436,16 @@ contract DeploymentTest is DssTest { deal(address(dss.dai), ilkInst.buffer, 1_000 * WAD); deal(USDC, ilkInst.buffer, 1_000 * 10**6); - vm.prank(allocatorProxy); DepositorUniV3(ilkInst.depositorUniV3).setLimits(address(dss.dai), USDC, uint24(100), uint96(2_000 * WAD), uint96(2_000 * 10**6), 1 hours); + vm.prank(allocatorProxy); DepositorUniV3(ilkFunnelInst.depositorUniV3).setLimits(address(dss.dai), USDC, uint24(100), uint96(2_000 * WAD), uint96(2_000 * 10**6), 1 hours); - vm.prank(facilitator1); StableDepositorUniV3(ilkInst.stableDepositorUniV3).setConfig(address(dss.dai), USDC, uint24(100), REF_TICK - 100, REF_TICK + 100, 1, 1 hours, uint96(1_000 * WAD), uint96(1000 * 10**6), 0, 0); - vm.prank(stableDepositorUniV3Keeper1); StableDepositorUniV3(ilkInst.stableDepositorUniV3).deposit(address(dss.dai), USDC, uint24(100), REF_TICK - 100, REF_TICK + 100, 0, 0); + vm.prank(facilitator1); StableDepositorUniV3(ilkFunnelInst.stableDepositorUniV3).setConfig(address(dss.dai), USDC, uint24(100), REF_TICK - 100, REF_TICK + 100, 1, 1 hours, uint96(1_000 * WAD), uint96(1000 * 10**6), 0, 0); + vm.prank(stableDepositorUniV3Keeper1); StableDepositorUniV3(ilkFunnelInst.stableDepositorUniV3).deposit(address(dss.dai), USDC, uint24(100), REF_TICK - 100, REF_TICK + 100, 0, 0); - vm.prank(facilitator1); StableDepositorUniV3(ilkInst.stableDepositorUniV3).setConfig(address(dss.dai), USDC, uint24(100), REF_TICK - 100, REF_TICK + 100, -1, 1 hours, uint96(1_000 * WAD), uint96(1000 * 10**6), 0, 0); - vm.prank(stableDepositorUniV3Keeper1); StableDepositorUniV3(ilkInst.stableDepositorUniV3).withdraw(address(dss.dai), USDC, uint24(100), REF_TICK - 100, REF_TICK + 100, 0, 0); + vm.prank(facilitator1); StableDepositorUniV3(ilkFunnelInst.stableDepositorUniV3).setConfig(address(dss.dai), USDC, uint24(100), REF_TICK - 100, REF_TICK + 100, -1, 1 hours, uint96(1_000 * WAD), uint96(1000 * 10**6), 0, 0); + vm.prank(stableDepositorUniV3Keeper1); StableDepositorUniV3(ilkFunnelInst.stableDepositorUniV3).withdraw(address(dss.dai), USDC, uint24(100), REF_TICK - 100, REF_TICK + 100, 0, 0); vm.expectRevert(bytes("NP")); // Reverts since no fees to collect and not because the call is unauthorized - vm.prank(stableDepositorUniV3Keeper1); StableDepositorUniV3(ilkInst.stableDepositorUniV3).collect(address(dss.dai), USDC, uint24(100), REF_TICK - 100, REF_TICK + 100); + vm.prank(stableDepositorUniV3Keeper1); StableDepositorUniV3(ilkFunnelInst.stableDepositorUniV3).collect(address(dss.dai), USDC, uint24(100), REF_TICK - 100, REF_TICK + 100); } function testMoveFromKeeper() public { @@ -441,10 +456,10 @@ contract DeploymentTest is DssTest { // Give conduit1 some funds deal(USDC, ilkInst.buffer, 3_000 * 10**6, true); - vm.prank(ilkInst.conduitMover); AllocatorConduitMock(conduit1).deposit(ILK, USDC, 3_000 * 10**6); + vm.prank(ilkFunnelInst.conduitMover); AllocatorConduitMock(conduit1).deposit(ILK, USDC, 3_000 * 10**6); - vm.prank(facilitator1); ConduitMover(ilkInst.conduitMover).setConfig(conduit1, conduit2, USDC, 1, 1 hours, 3_000 * 10**6); - vm.prank(conduitMoverKeeper1); ConduitMover(ilkInst.conduitMover).move(conduit1, conduit2, USDC); + vm.prank(facilitator1); ConduitMover(ilkFunnelInst.conduitMover).setConfig(conduit1, conduit2, USDC, 1, 1 hours, 3_000 * 10**6); + vm.prank(conduitMoverKeeper1); ConduitMover(ilkFunnelInst.conduitMover).move(conduit1, conduit2, USDC); } function testEndCage() public { From d429f33bfedc9905e0a564f2ea4177d4182133a1 Mon Sep 17 00:00:00 2001 From: oldchili <130549691+oldchili@users.noreply.github.com> Date: Mon, 26 Aug 2024 18:13:25 +0300 Subject: [PATCH 72/74] Split funnel init libs to deploy/funnels (#79) --- deploy/AllocatorDeploy.sol | 64 +------ deploy/AllocatorInit.sol | 167 +----------------- deploy/AllocatorInstances.sol | 10 -- deploy/funnels/AllocatorFunnelDeploy.sol | 76 ++++++++ deploy/funnels/AllocatorFunnelInit.sol | 196 +++++++++++++++++++++ deploy/funnels/AllocatorFunnelInstance.sol | 27 +++ test/integration/Deployment.t.sol | 11 +- 7 files changed, 313 insertions(+), 238 deletions(-) create mode 100644 deploy/funnels/AllocatorFunnelDeploy.sol create mode 100644 deploy/funnels/AllocatorFunnelInit.sol create mode 100644 deploy/funnels/AllocatorFunnelInstance.sol diff --git a/deploy/AllocatorDeploy.sol b/deploy/AllocatorDeploy.sol index eff32680..b372cb66 100644 --- a/deploy/AllocatorDeploy.sol +++ b/deploy/AllocatorDeploy.sol @@ -18,20 +18,13 @@ pragma solidity ^0.8.16; import { ScriptTools } from "dss-test/ScriptTools.sol"; -import { AllocatorOracle } from "src/AllocatorOracle.sol"; -import { AllocatorRoles } from "src/AllocatorRoles.sol"; -import { AllocatorRegistry } from "src/AllocatorRegistry.sol"; -import { AllocatorBuffer } from "src/AllocatorBuffer.sol"; -import { AllocatorVault } from "src/AllocatorVault.sol"; -import { Swapper } from "src/funnels/Swapper.sol"; -import { DepositorUniV3 } from "src/funnels/DepositorUniV3.sol"; -import { VaultMinter } from "src/funnels/automation/VaultMinter.sol"; -import { StableSwapper } from "src/funnels/automation/StableSwapper.sol"; -import { StableDepositorUniV3 } from "src/funnels/automation/StableDepositorUniV3.sol"; -import { ConduitMover } from "src/funnels/automation/ConduitMover.sol"; - -import { AllocatorSharedInstance, AllocatorIlkInstance, AllocatorIlkFunnelInstance } from "./AllocatorInstances.sol"; +import { AllocatorOracle } from "src/AllocatorOracle.sol"; +import { AllocatorRoles } from "src/AllocatorRoles.sol"; +import { AllocatorRegistry } from "src/AllocatorRegistry.sol"; +import { AllocatorBuffer } from "src/AllocatorBuffer.sol"; +import { AllocatorVault } from "src/AllocatorVault.sol"; +import { AllocatorSharedInstance, AllocatorIlkInstance } from "./AllocatorInstances.sol"; library AllocatorDeploy { @@ -71,49 +64,4 @@ library AllocatorDeploy { ilkInstance.owner = owner; } - - // Note: owner is assumed to be the allocator proxy - function deployIlkFunnel( - address deployer, - address owner, - address roles, - bytes32 ilk, - address uniV3Factory, - address vault, - address buffer - ) internal returns (AllocatorIlkFunnelInstance memory ilkFunnelInstance) { - address _swapper = address(new Swapper(roles, ilk, buffer)); - ScriptTools.switchOwner(_swapper, deployer, owner); - ilkFunnelInstance.swapper = _swapper; - - address _depositorUniV3 = address(new DepositorUniV3(roles, ilk, uniV3Factory, buffer)); - ScriptTools.switchOwner(_depositorUniV3, deployer, owner); - ilkFunnelInstance.depositorUniV3 = _depositorUniV3; - - { - address _vaultMinter = address(new VaultMinter(vault)); - ScriptTools.switchOwner(_vaultMinter, deployer, owner); - ilkFunnelInstance.vaultMinter = _vaultMinter; - } - - { - address _stableSwapper = address(new StableSwapper(_swapper)); - ScriptTools.switchOwner(_stableSwapper, deployer, owner); - ilkFunnelInstance.stableSwapper = _stableSwapper; - } - - { - address _stableDepositorUniV3 = address(new StableDepositorUniV3(_depositorUniV3)); - ScriptTools.switchOwner(_stableDepositorUniV3, deployer, owner); - ilkFunnelInstance.stableDepositorUniV3 = _stableDepositorUniV3; - } - - { - address _conduitMover = address(new ConduitMover(ilk, buffer)); - ScriptTools.switchOwner(_conduitMover, deployer, owner); - ilkFunnelInstance.conduitMover = _conduitMover; - } - - ilkFunnelInstance.owner = owner; - } } diff --git a/deploy/AllocatorInit.sol b/deploy/AllocatorInit.sol index 08c3d8d7..47f6bfb1 100644 --- a/deploy/AllocatorInit.sol +++ b/deploy/AllocatorInit.sol @@ -18,12 +18,7 @@ pragma solidity >=0.8.0; import { ScriptTools } from "dss-test/ScriptTools.sol"; import { DssInstance } from "dss-test/MCD.sol"; -import { AllocatorSharedInstance, AllocatorIlkInstance, AllocatorIlkFunnelInstance } from "./AllocatorInstances.sol"; - -interface WardsLike { - function rely(address) external; - function deny(address) external; -} +import { AllocatorSharedInstance, AllocatorIlkInstance } from "./AllocatorInstances.sol"; interface IlkRegistryLike { function put( @@ -41,8 +36,6 @@ interface IlkRegistryLike { interface RolesLike { function setIlkAdmin(bytes32, address) external; - function setUserRole(bytes32, address, uint8, bool) external; - function setRoleAction(bytes32, uint8, address, bytes4, bool) external; } interface RegistryLike { @@ -56,73 +49,12 @@ interface VaultLike { function vat() external view returns (address); function nst() external view returns (address); function file(bytes32, address) external; - function draw(uint256) external; - function wipe(uint256) external; } interface BufferLike { function approve(address, address, uint256) external; } -interface SwapperLike { - function roles() external view returns (address); - function ilk() external view returns (bytes32); - function buffer() external view returns (address); - function swap(address, address, uint256, uint256, address, bytes calldata) external returns (uint256); -} - -interface DepositorUniV3Like { - struct LiquidityParams { - address gem0; - address gem1; - uint24 fee; - int24 tickLower; - int24 tickUpper; - uint128 liquidity; - uint256 amt0Desired; - uint256 amt1Desired; - uint256 amt0Min; - uint256 amt1Min; - } - - struct CollectParams { - address gem0; - address gem1; - uint24 fee; - int24 tickLower; - int24 tickUpper; - } - - function roles() external view returns (address); - function ilk() external view returns (bytes32); - function uniV3Factory() external view returns (address); - function buffer() external view returns (address); - function deposit(LiquidityParams memory) external returns (uint128, uint256, uint256); - function withdraw(LiquidityParams memory, bool) external returns (uint128, uint256, uint256, uint256, uint256); - function collect(CollectParams memory) external returns (uint256, uint256); -} - -interface VaultMinterLike { - function vault() external view returns (address); -} - -interface StableSwapperLike { - function swapper() external view returns (address); -} - -interface StableDepositorUniV3Like { - function depositor() external view returns (address); -} - -interface ConduitMoverLike { - function ilk() external view returns (bytes32); - function buffer() external view returns (address); -} - -interface KissLike { - function kiss(address) external; -} - interface AutoLineLike { function setIlk(bytes32, uint256, uint256, uint256) external; } @@ -137,21 +69,6 @@ struct AllocatorIlkConfig { address ilkRegistry; } -struct AllocatorIlkFunnelConfig { - bytes32 ilk; - address allocatorProxy; - uint8 facilitatorRole; - uint8 automationRole; - address[] facilitators; - address[] vaultMinterKeepers; - address[] stableSwapperKeepers; - address[] stableDepositorUniV3Keepers; - address[] conduitMoverKeepers; - address[] swapTokens; - address[] depositTokens; - address uniV3Factory; -} - function bytes32ToStr(bytes32 _bytes32) pure returns (string memory) { uint256 len; while(len < 32 && _bytes32[len] != 0) len++; @@ -165,7 +82,6 @@ function bytes32ToStr(bytes32 _bytes32) pure returns (string memory) { library AllocatorInit { uint256 constant WAD = 10 ** 18; uint256 constant RAY = 10 ** 27; - uint256 constant RAD = 10 ** 45; uint256 constant RATES_ONE_HUNDRED_PCT = 1000000021979553151239153027; @@ -246,85 +162,4 @@ library AllocatorInit { _symbol : bytes32ToStr(ilk) }); } - - // Please note this should be executed by the allocator proxy - function initIlkFunnel( - AllocatorSharedInstance memory sharedInstance, - AllocatorIlkInstance memory ilkInstance, - AllocatorIlkFunnelInstance memory ilkFunnelInstance, - AllocatorIlkFunnelConfig memory cfg - ) internal { - bytes32 ilk = cfg.ilk; - - require(SwapperLike(ilkFunnelInstance.swapper).roles() == sharedInstance.roles, "AllocatorInit/swapper-roles-mismatch"); - require(SwapperLike(ilkFunnelInstance.swapper).ilk() == ilk, "AllocatorInit/swapper-ilk-mismatch"); - require(SwapperLike(ilkFunnelInstance.swapper).buffer() == ilkInstance.buffer, "AllocatorInit/swapper-buffer-mismatch"); - - require(DepositorUniV3Like(ilkFunnelInstance.depositorUniV3).roles() == sharedInstance.roles, "AllocatorInit/depositorUniV3-roles-mismatch"); - require(DepositorUniV3Like(ilkFunnelInstance.depositorUniV3).ilk() == ilk, "AllocatorInit/depositorUniV3-ilk-mismatch"); - require(DepositorUniV3Like(ilkFunnelInstance.depositorUniV3).uniV3Factory() == cfg.uniV3Factory, "AllocatorInit/depositorUniV3-uniV3Factory-mismatch"); - require(DepositorUniV3Like(ilkFunnelInstance.depositorUniV3).buffer() == ilkInstance.buffer, "AllocatorInit/depositorUniV3-buffer-mismatch"); - - require(VaultMinterLike(ilkFunnelInstance.vaultMinter).vault() == ilkInstance.vault, "AllocatorInit/vaultMinter-vault-mismatch"); - - require(StableSwapperLike(ilkFunnelInstance.stableSwapper).swapper() == ilkFunnelInstance.swapper, "AllocatorInit/stableSwapper-swapper-mismatch"); - require(StableDepositorUniV3Like(ilkFunnelInstance.stableDepositorUniV3).depositor() == ilkFunnelInstance.depositorUniV3, "AllocatorInit/stableDepositorUniV3-depositorUniV3-mismatch"); - - require(ConduitMoverLike(ilkFunnelInstance.conduitMover).ilk() == ilk, "AllocatorInit/conduitMover-ilk-mismatch"); - require(ConduitMoverLike(ilkFunnelInstance.conduitMover).buffer() == ilkInstance.buffer, "AllocatorInit/conduitMover-buffer-mismatch"); - - // Allow vault and funnels to pull funds from the buffer - for(uint256 i = 0; i < cfg.swapTokens.length; i++) { - BufferLike(ilkInstance.buffer).approve(cfg.swapTokens[i], ilkFunnelInstance.swapper, type(uint256).max); - } - for(uint256 i = 0; i < cfg.depositTokens.length; i++) { - BufferLike(ilkInstance.buffer).approve(cfg.depositTokens[i], ilkFunnelInstance.depositorUniV3, type(uint256).max); - } - - // Allow the facilitators to operate on the vault and funnels directly - for(uint256 i = 0; i < cfg.facilitators.length; i++) { - RolesLike(sharedInstance.roles).setUserRole(ilk, cfg.facilitators[i], cfg.facilitatorRole, true); - } - - RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.facilitatorRole, ilkInstance.vault, VaultLike.draw.selector, true); - RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.facilitatorRole, ilkInstance.vault, VaultLike.wipe.selector, true); - RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.facilitatorRole, ilkFunnelInstance.swapper, SwapperLike.swap.selector, true); - RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.facilitatorRole, ilkFunnelInstance.depositorUniV3, DepositorUniV3Like.deposit.selector, true); - RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.facilitatorRole, ilkFunnelInstance.depositorUniV3, DepositorUniV3Like.withdraw.selector, true); - RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.facilitatorRole, ilkFunnelInstance.depositorUniV3, DepositorUniV3Like.collect.selector, true); - - // Allow the automation contracts to operate on the funnels - RolesLike(sharedInstance.roles).setUserRole(ilk, ilkFunnelInstance.vaultMinter, cfg.automationRole, true); - RolesLike(sharedInstance.roles).setUserRole(ilk, ilkFunnelInstance.stableSwapper, cfg.automationRole, true); - RolesLike(sharedInstance.roles).setUserRole(ilk, ilkFunnelInstance.stableDepositorUniV3, cfg.automationRole, true); - - RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkInstance.vault, VaultLike.draw.selector, true); - RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkInstance.vault, VaultLike.wipe.selector, true); - RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkFunnelInstance.swapper, SwapperLike.swap.selector, true); - RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkFunnelInstance.depositorUniV3, DepositorUniV3Like.deposit.selector, true); - RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkFunnelInstance.depositorUniV3, DepositorUniV3Like.withdraw.selector, true); - RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkFunnelInstance.depositorUniV3, DepositorUniV3Like.collect.selector, true); - - // Allow facilitator to set configurations in the automation contracts - for(uint256 i = 0; i < cfg.facilitators.length; i++) { - WardsLike(ilkFunnelInstance.vaultMinter).rely(cfg.facilitators[i]); - WardsLike(ilkFunnelInstance.stableSwapper).rely(cfg.facilitators[i]); - WardsLike(ilkFunnelInstance.stableDepositorUniV3).rely(cfg.facilitators[i]); - WardsLike(ilkFunnelInstance.conduitMover).rely(cfg.facilitators[i]); - } - - // Add keepers to the automation contracts - for(uint256 i = 0; i < cfg.vaultMinterKeepers.length; i++) { - KissLike(ilkFunnelInstance.vaultMinter).kiss(cfg.vaultMinterKeepers[i]); - } - for(uint256 i = 0; i < cfg.stableSwapperKeepers.length; i++) { - KissLike(ilkFunnelInstance.stableSwapper).kiss(cfg.stableSwapperKeepers[i]); - } - for(uint256 i = 0; i < cfg.stableDepositorUniV3Keepers.length; i++) { - KissLike(ilkFunnelInstance.stableDepositorUniV3).kiss(cfg.stableDepositorUniV3Keepers[i]); - } - for(uint256 i = 0; i < cfg.conduitMoverKeepers.length; i++) { - KissLike(ilkFunnelInstance.conduitMover).kiss(cfg.conduitMoverKeepers[i]); - } - } } diff --git a/deploy/AllocatorInstances.sol b/deploy/AllocatorInstances.sol index 092db88c..1fd2a4bc 100644 --- a/deploy/AllocatorInstances.sol +++ b/deploy/AllocatorInstances.sol @@ -27,13 +27,3 @@ struct AllocatorIlkInstance { address vault; address buffer; } - -struct AllocatorIlkFunnelInstance { - address owner; - address swapper; - address depositorUniV3; - address vaultMinter; - address stableSwapper; - address stableDepositorUniV3; - address conduitMover; -} diff --git a/deploy/funnels/AllocatorFunnelDeploy.sol b/deploy/funnels/AllocatorFunnelDeploy.sol new file mode 100644 index 00000000..f525906c --- /dev/null +++ b/deploy/funnels/AllocatorFunnelDeploy.sol @@ -0,0 +1,76 @@ +// SPDX-FileCopyrightText: © 2023 Dai Foundation +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +pragma solidity ^0.8.16; + +import { ScriptTools } from "dss-test/ScriptTools.sol"; + +import { Swapper } from "src/funnels/Swapper.sol"; +import { DepositorUniV3 } from "src/funnels/DepositorUniV3.sol"; +import { VaultMinter } from "src/funnels/automation/VaultMinter.sol"; +import { StableSwapper } from "src/funnels/automation/StableSwapper.sol"; +import { StableDepositorUniV3 } from "src/funnels/automation/StableDepositorUniV3.sol"; +import { ConduitMover } from "src/funnels/automation/ConduitMover.sol"; + +import { AllocatorIlkFunnelInstance } from "./AllocatorFunnelInstance.sol"; + +library AllocatorFunnelDeploy { + + // Note: owner is assumed to be the allocator proxy + function deployIlkFunnel( + address deployer, + address owner, + address roles, + bytes32 ilk, + address uniV3Factory, + address vault, + address buffer + ) internal returns (AllocatorIlkFunnelInstance memory ilkFunnelInstance) { + address _swapper = address(new Swapper(roles, ilk, buffer)); + ScriptTools.switchOwner(_swapper, deployer, owner); + ilkFunnelInstance.swapper = _swapper; + + address _depositorUniV3 = address(new DepositorUniV3(roles, ilk, uniV3Factory, buffer)); + ScriptTools.switchOwner(_depositorUniV3, deployer, owner); + ilkFunnelInstance.depositorUniV3 = _depositorUniV3; + + { + address _vaultMinter = address(new VaultMinter(vault)); + ScriptTools.switchOwner(_vaultMinter, deployer, owner); + ilkFunnelInstance.vaultMinter = _vaultMinter; + } + + { + address _stableSwapper = address(new StableSwapper(_swapper)); + ScriptTools.switchOwner(_stableSwapper, deployer, owner); + ilkFunnelInstance.stableSwapper = _stableSwapper; + } + + { + address _stableDepositorUniV3 = address(new StableDepositorUniV3(_depositorUniV3)); + ScriptTools.switchOwner(_stableDepositorUniV3, deployer, owner); + ilkFunnelInstance.stableDepositorUniV3 = _stableDepositorUniV3; + } + + { + address _conduitMover = address(new ConduitMover(ilk, buffer)); + ScriptTools.switchOwner(_conduitMover, deployer, owner); + ilkFunnelInstance.conduitMover = _conduitMover; + } + + ilkFunnelInstance.owner = owner; + } +} diff --git a/deploy/funnels/AllocatorFunnelInit.sol b/deploy/funnels/AllocatorFunnelInit.sol new file mode 100644 index 00000000..044fcbcc --- /dev/null +++ b/deploy/funnels/AllocatorFunnelInit.sol @@ -0,0 +1,196 @@ +// SPDX-FileCopyrightText: © 2023 Dai Foundation +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +pragma solidity >=0.8.0; + +import { AllocatorSharedInstance, AllocatorIlkInstance } from "deploy/AllocatorInstances.sol"; +import { AllocatorIlkFunnelInstance } from "./AllocatorFunnelInstance.sol"; + +interface WardsLike { + function rely(address) external; +} + +interface RolesLike { + function setUserRole(bytes32, address, uint8, bool) external; + function setRoleAction(bytes32, uint8, address, bytes4, bool) external; +} + +interface VaultLike { + function draw(uint256) external; + function wipe(uint256) external; +} + +interface BufferLike { + function approve(address, address, uint256) external; +} + +interface SwapperLike { + function roles() external view returns (address); + function ilk() external view returns (bytes32); + function buffer() external view returns (address); + function swap(address, address, uint256, uint256, address, bytes calldata) external returns (uint256); +} + +interface DepositorUniV3Like { + struct LiquidityParams { + address gem0; + address gem1; + uint24 fee; + int24 tickLower; + int24 tickUpper; + uint128 liquidity; + uint256 amt0Desired; + uint256 amt1Desired; + uint256 amt0Min; + uint256 amt1Min; + } + + struct CollectParams { + address gem0; + address gem1; + uint24 fee; + int24 tickLower; + int24 tickUpper; + } + + function roles() external view returns (address); + function ilk() external view returns (bytes32); + function uniV3Factory() external view returns (address); + function buffer() external view returns (address); + function deposit(LiquidityParams memory) external returns (uint128, uint256, uint256); + function withdraw(LiquidityParams memory, bool) external returns (uint128, uint256, uint256, uint256, uint256); + function collect(CollectParams memory) external returns (uint256, uint256); +} + +interface VaultMinterLike { + function vault() external view returns (address); +} + +interface StableSwapperLike { + function swapper() external view returns (address); +} + +interface StableDepositorUniV3Like { + function depositor() external view returns (address); +} + +interface ConduitMoverLike { + function ilk() external view returns (bytes32); + function buffer() external view returns (address); +} + +interface KissLike { + function kiss(address) external; +} + +struct AllocatorIlkFunnelConfig { + bytes32 ilk; + address allocatorProxy; + uint8 facilitatorRole; + uint8 automationRole; + address[] facilitators; + address[] vaultMinterKeepers; + address[] stableSwapperKeepers; + address[] stableDepositorUniV3Keepers; + address[] conduitMoverKeepers; + address[] swapTokens; + address[] depositTokens; + address uniV3Factory; +} + +library AllocatorFunnelInit { + + // Please note this should be executed by the allocator proxy + function initIlkFunnel( + AllocatorSharedInstance memory sharedInstance, + AllocatorIlkInstance memory ilkInstance, + AllocatorIlkFunnelInstance memory ilkFunnelInstance, + AllocatorIlkFunnelConfig memory cfg + ) internal { + bytes32 ilk = cfg.ilk; + + require(SwapperLike(ilkFunnelInstance.swapper).roles() == sharedInstance.roles, "AllocatorInit/swapper-roles-mismatch"); + require(SwapperLike(ilkFunnelInstance.swapper).ilk() == ilk, "AllocatorInit/swapper-ilk-mismatch"); + require(SwapperLike(ilkFunnelInstance.swapper).buffer() == ilkInstance.buffer, "AllocatorInit/swapper-buffer-mismatch"); + + require(DepositorUniV3Like(ilkFunnelInstance.depositorUniV3).roles() == sharedInstance.roles, "AllocatorInit/depositorUniV3-roles-mismatch"); + require(DepositorUniV3Like(ilkFunnelInstance.depositorUniV3).ilk() == ilk, "AllocatorInit/depositorUniV3-ilk-mismatch"); + require(DepositorUniV3Like(ilkFunnelInstance.depositorUniV3).uniV3Factory() == cfg.uniV3Factory, "AllocatorInit/depositorUniV3-uniV3Factory-mismatch"); + require(DepositorUniV3Like(ilkFunnelInstance.depositorUniV3).buffer() == ilkInstance.buffer, "AllocatorInit/depositorUniV3-buffer-mismatch"); + + require(VaultMinterLike(ilkFunnelInstance.vaultMinter).vault() == ilkInstance.vault, "AllocatorInit/vaultMinter-vault-mismatch"); + + require(StableSwapperLike(ilkFunnelInstance.stableSwapper).swapper() == ilkFunnelInstance.swapper, "AllocatorInit/stableSwapper-swapper-mismatch"); + require(StableDepositorUniV3Like(ilkFunnelInstance.stableDepositorUniV3).depositor() == ilkFunnelInstance.depositorUniV3, "AllocatorInit/stableDepositorUniV3-depositorUniV3-mismatch"); + + require(ConduitMoverLike(ilkFunnelInstance.conduitMover).ilk() == ilk, "AllocatorInit/conduitMover-ilk-mismatch"); + require(ConduitMoverLike(ilkFunnelInstance.conduitMover).buffer() == ilkInstance.buffer, "AllocatorInit/conduitMover-buffer-mismatch"); + + // Allow vault and funnels to pull funds from the buffer + for(uint256 i = 0; i < cfg.swapTokens.length; i++) { + BufferLike(ilkInstance.buffer).approve(cfg.swapTokens[i], ilkFunnelInstance.swapper, type(uint256).max); + } + for(uint256 i = 0; i < cfg.depositTokens.length; i++) { + BufferLike(ilkInstance.buffer).approve(cfg.depositTokens[i], ilkFunnelInstance.depositorUniV3, type(uint256).max); + } + + // Allow the facilitators to operate on the vault and funnels directly + for(uint256 i = 0; i < cfg.facilitators.length; i++) { + RolesLike(sharedInstance.roles).setUserRole(ilk, cfg.facilitators[i], cfg.facilitatorRole, true); + } + + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.facilitatorRole, ilkInstance.vault, VaultLike.draw.selector, true); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.facilitatorRole, ilkInstance.vault, VaultLike.wipe.selector, true); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.facilitatorRole, ilkFunnelInstance.swapper, SwapperLike.swap.selector, true); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.facilitatorRole, ilkFunnelInstance.depositorUniV3, DepositorUniV3Like.deposit.selector, true); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.facilitatorRole, ilkFunnelInstance.depositorUniV3, DepositorUniV3Like.withdraw.selector, true); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.facilitatorRole, ilkFunnelInstance.depositorUniV3, DepositorUniV3Like.collect.selector, true); + + // Allow the automation contracts to operate on the funnels + RolesLike(sharedInstance.roles).setUserRole(ilk, ilkFunnelInstance.vaultMinter, cfg.automationRole, true); + RolesLike(sharedInstance.roles).setUserRole(ilk, ilkFunnelInstance.stableSwapper, cfg.automationRole, true); + RolesLike(sharedInstance.roles).setUserRole(ilk, ilkFunnelInstance.stableDepositorUniV3, cfg.automationRole, true); + + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkInstance.vault, VaultLike.draw.selector, true); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkInstance.vault, VaultLike.wipe.selector, true); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkFunnelInstance.swapper, SwapperLike.swap.selector, true); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkFunnelInstance.depositorUniV3, DepositorUniV3Like.deposit.selector, true); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkFunnelInstance.depositorUniV3, DepositorUniV3Like.withdraw.selector, true); + RolesLike(sharedInstance.roles).setRoleAction(ilk, cfg.automationRole, ilkFunnelInstance.depositorUniV3, DepositorUniV3Like.collect.selector, true); + + // Allow facilitator to set configurations in the automation contracts + for(uint256 i = 0; i < cfg.facilitators.length; i++) { + WardsLike(ilkFunnelInstance.vaultMinter).rely(cfg.facilitators[i]); + WardsLike(ilkFunnelInstance.stableSwapper).rely(cfg.facilitators[i]); + WardsLike(ilkFunnelInstance.stableDepositorUniV3).rely(cfg.facilitators[i]); + WardsLike(ilkFunnelInstance.conduitMover).rely(cfg.facilitators[i]); + } + + // Add keepers to the automation contracts + for(uint256 i = 0; i < cfg.vaultMinterKeepers.length; i++) { + KissLike(ilkFunnelInstance.vaultMinter).kiss(cfg.vaultMinterKeepers[i]); + } + for(uint256 i = 0; i < cfg.stableSwapperKeepers.length; i++) { + KissLike(ilkFunnelInstance.stableSwapper).kiss(cfg.stableSwapperKeepers[i]); + } + for(uint256 i = 0; i < cfg.stableDepositorUniV3Keepers.length; i++) { + KissLike(ilkFunnelInstance.stableDepositorUniV3).kiss(cfg.stableDepositorUniV3Keepers[i]); + } + for(uint256 i = 0; i < cfg.conduitMoverKeepers.length; i++) { + KissLike(ilkFunnelInstance.conduitMover).kiss(cfg.conduitMoverKeepers[i]); + } + } +} diff --git a/deploy/funnels/AllocatorFunnelInstance.sol b/deploy/funnels/AllocatorFunnelInstance.sol new file mode 100644 index 00000000..bef2881e --- /dev/null +++ b/deploy/funnels/AllocatorFunnelInstance.sol @@ -0,0 +1,27 @@ +// SPDX-FileCopyrightText: © 2023 Dai Foundation +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +pragma solidity >=0.8.0; + +struct AllocatorIlkFunnelInstance { + address owner; + address swapper; + address depositorUniV3; + address vaultMinter; + address stableSwapper; + address stableDepositorUniV3; + address conduitMover; +} diff --git a/test/integration/Deployment.t.sol b/test/integration/Deployment.t.sol index 35379b84..3011bab9 100644 --- a/test/integration/Deployment.t.sol +++ b/test/integration/Deployment.t.sol @@ -18,9 +18,12 @@ pragma solidity ^0.8.16; import "dss-test/DssTest.sol"; -import { AllocatorSharedInstance, AllocatorIlkInstance, AllocatorIlkFunnelInstance } from "deploy/AllocatorInstances.sol"; +import { AllocatorSharedInstance, AllocatorIlkInstance } from "deploy/AllocatorInstances.sol"; +import { AllocatorIlkFunnelInstance } from "deploy/funnels/AllocatorFunnelInstance.sol"; import { AllocatorDeploy } from "deploy/AllocatorDeploy.sol"; -import { AllocatorInit, AllocatorIlkConfig, AllocatorIlkFunnelConfig } from "deploy/AllocatorInit.sol"; +import { AllocatorFunnelDeploy } from "deploy/funnels/AllocatorFunnelDeploy.sol"; +import { AllocatorInit, AllocatorIlkConfig } from "deploy/AllocatorInit.sol"; +import { AllocatorFunnelInit, AllocatorIlkFunnelConfig } from "deploy/funnels/AllocatorFunnelInit.sol"; import { SwapperCalleeUniV3 } from "src/funnels/callees/SwapperCalleeUniV3.sol"; @@ -142,7 +145,7 @@ contract DeploymentTest is DssTest { ilk : ILK, nstJoin : nstJoin }); - ilkFunnelInst = AllocatorDeploy.deployIlkFunnel({ + ilkFunnelInst = AllocatorFunnelDeploy.deployIlkFunnel({ deployer : address(this), owner : allocatorProxy, roles : sharedInst.roles, @@ -217,7 +220,7 @@ contract DeploymentTest is DssTest { depositTokens : depositTokens, uniV3Factory : UNIV3_FACTORY }); - AllocatorInit.initIlkFunnel(sharedInst, ilkInst, ilkFunnelInst, funnelCfg); + AllocatorFunnelInit.initIlkFunnel(sharedInst, ilkInst, ilkFunnelInst, funnelCfg); AllocatorRoles(sharedInst.roles).setUserRole(ILK, address(ilkFunnelInst.conduitMover), automationRole, true); From 226584d3b179d98025497815adb4ea585ea0102d Mon Sep 17 00:00:00 2001 From: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> Date: Wed, 28 Aug 2024 07:58:18 -0300 Subject: [PATCH 73/74] Renaming (#80) --- README.md | 14 ++-- certora/AllocatorVault.conf | 16 ++-- certora/AllocatorVault.spec | 76 +++++++++---------- deploy/AllocatorDeploy.sol | 4 +- deploy/AllocatorInit.sol | 6 +- src/AllocatorVault.sol | 34 ++++----- test/AllocatorVault.t.sol | 42 +++++----- test/funnels/automation/VaultMinter.t.sol | 32 ++++---- test/integration/Deployment.t.sol | 14 ++-- .../{NstJoinMock.sol => UsdsJoinMock.sol} | 14 ++-- test/mocks/{NstMock.sol => UsdsMock.sol} | 12 +-- 11 files changed, 132 insertions(+), 132 deletions(-) rename test/mocks/{NstJoinMock.sol => UsdsJoinMock.sol} (68%) rename test/mocks/{NstMock.sol => UsdsMock.sol} (84%) diff --git a/README.md b/README.md index 1e2599a9..82032bfa 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ The system is comprised of several layers: - Core Allocation System (*green above*): - Smart contracts that can be considered a part of the Maker Core Protocol, and are immutable and present in all Allocators. - - Their main role is to mint NST (New Stable Token) and hold it (possibly with other tokens) in the `AllocatorBuffer`. + - Their main role is to mint USDS (New Stable Token) and hold it (possibly with other tokens) in the `AllocatorBuffer`. - Deployment Funnels (*blue above*): - Contracts that pull funds from the `AllocatorBuffer`. - The funds can be swapped and/or deployed into AMM pools or specific conduits. @@ -33,7 +33,7 @@ The allocation system includes several actor types: - Pause Proxy: - Performs actions through spells with governance delay. - - In charge of setting up the core components and the NST minting instant access modules (DC-IAMs). + - In charge of setting up the core components and the USDS minting instant access modules (DC-IAMs). - Ward of the singleton contracts (e.g RWA conduits, Coinbase Custody, `AllocatorRoles`). - AllocatorDAO Proxy: - Performs actions through a sub-spell with governance delay. @@ -46,7 +46,7 @@ The allocation system includes several actor types: - An optional actor which is whitelisted through the `AllocatorRoles` contract to perform specified actions on the `AllocatorVault`, funnels and conduits. - Will typically be a facilitator multisig or an automation contract controlled by one (e.g `StableSwapper`, `StableDepositorUniV3`). - Keeper: - - An optional actor which can be set up to trigger the automation contracts in case repetitive actions are needed (such as swapping NST to USDC every time interval). + - An optional actor which can be set up to trigger the automation contracts in case repetitive actions are needed (such as swapping USDS to USDC every time interval). ![Untitled (1)](https://github.com/makerdao/dss-allocator/assets/130549691/c677928b-32f4-4000-b6ed-e3798caa9c5c) @@ -61,15 +61,15 @@ Each AllocatorDAO has a unique `ilk` (collateral type) with one VAT vault set up Single contract per `ilk`, which operators can use to: -- Mint (`draw`) NST from the vault to the AllocatorBuffer. -- Repay (`wipe`) NST from the AllocatorBuffer. +- Mint (`draw`) USDS from the vault to the AllocatorBuffer. +- Repay (`wipe`) USDS from the AllocatorBuffer. ### AllocatorBuffer A simple contract for the AllocatorDAO to hold funds in. - Supports approving contracts to `transferFrom` it. -- Note that although the `AllocatorVault` pushes and pulls NST to/from the `AllocatorBuffer`, it can manage other tokens as well. +- Note that although the `AllocatorVault` pushes and pulls USDS to/from the `AllocatorBuffer`, it can manage other tokens as well. ### AllocatorRoles @@ -112,7 +112,7 @@ An automation contract sample, which can be used by the AllocatorDAOs to `draw` ### StableSwapper -An automation contract, which can be used by the AllocatorDAOs to set up recurring swaps of stable tokens (e.g NST to USDC). +An automation contract, which can be used by the AllocatorDAOs to set up recurring swaps of stable tokens (e.g USDS to USDC). - In order to use it, the AllocatorDAO should list it as an operator of its `Swapper` primitive in the `AllocatorRoles` contract. - The `Swapper` primitive will rate-limit the automation contract. diff --git a/certora/AllocatorVault.conf b/certora/AllocatorVault.conf index 98118487..9a5356c7 100644 --- a/certora/AllocatorVault.conf +++ b/certora/AllocatorVault.conf @@ -4,18 +4,18 @@ "src/AllocatorRoles.sol", "test/mocks/VatMock.sol", "test/mocks/JugMock.sol", - "test/mocks/NstJoinMock.sol", - "test/mocks/NstMock.sol" + "test/mocks/UsdsJoinMock.sol", + "test/mocks/UsdsMock.sol" ], "link": [ "AllocatorVault:roles=AllocatorRoles", "AllocatorVault:vat=VatMock", "AllocatorVault:jug=JugMock", - "AllocatorVault:nstJoin=NstJoinMock", - "AllocatorVault:nst=NstMock", + "AllocatorVault:usdsJoin=UsdsJoinMock", + "AllocatorVault:usds=UsdsMock", "JugMock:vat=VatMock", - "NstJoinMock:vat=VatMock", - "NstJoinMock:nst=NstMock" + "UsdsJoinMock:vat=VatMock", + "UsdsJoinMock:usds=UsdsMock" ], "rule_sanity": "basic", "solc": "solc-0.8.16", @@ -24,8 +24,8 @@ "AllocatorRoles": "200", "VatMock": "0", "JugMock": "0", - "NstJoinMock": "0", - "NstMock": "0" + "UsdsJoinMock": "0", + "UsdsMock": "0" }, "verify": "AllocatorVault:certora/AllocatorVault.spec", "parametric_contracts": [ diff --git a/certora/AllocatorVault.spec b/certora/AllocatorVault.spec index 20105b54..cb2baad8 100644 --- a/certora/AllocatorVault.spec +++ b/certora/AllocatorVault.spec @@ -3,8 +3,8 @@ using AllocatorRoles as roles; using VatMock as vat; using JugMock as jug; -using NstJoinMock as nstJoin; -using NstMock as nst; +using UsdsJoinMock as usdsJoin; +using UsdsMock as usds; methods { function ilk() external returns (bytes32) envfree; @@ -19,9 +19,9 @@ methods { function vat.rate() external returns (uint256) envfree; function jug.duty() external returns (uint256) envfree; function jug.rho() external returns (uint256) envfree; - function nst.allowance(address, address) external returns (uint256) envfree; - function nst.balanceOf(address) external returns (uint256) envfree; - function nst.totalSupply() external returns (uint256) envfree; + function usds.allowance(address, address) external returns (uint256) envfree; + function usds.balanceOf(address) external returns (uint256) envfree; + function usds.totalSupply() external returns (uint256) envfree; } definition WAD() returns mathint = 10^18; @@ -145,9 +145,9 @@ rule file_revert(bytes32 what, address data) { rule draw(uint256 wad) { env e; - mathint nstTotalSupplyBefore = nst.totalSupply(); - mathint nstBalanceOfBufferBefore = nst.balanceOf(buffer()); - require nstBalanceOfBufferBefore <= nstTotalSupplyBefore; + mathint usdsTotalSupplyBefore = usds.totalSupply(); + mathint usdsBalanceOfBufferBefore = usds.balanceOf(buffer()); + require usdsBalanceOfBufferBefore <= usdsTotalSupplyBefore; mathint vatInkVaultBefore; mathint vatArtVaultBefore; vatInkVaultBefore, vatArtVaultBefore = vat.urns(ilk(), currentContract); mathint rate = vat.rate() + (jug.duty() - RAY()) * (e.block.timestamp - jug.rho()); @@ -156,15 +156,15 @@ rule draw(uint256 wad) { draw(e, wad); - mathint nstTotalSupplyAfter = nst.totalSupply(); - mathint nstBalanceOfBufferAfter = nst.balanceOf(buffer()); + mathint usdsTotalSupplyAfter = usds.totalSupply(); + mathint usdsBalanceOfBufferAfter = usds.balanceOf(buffer()); mathint vatInkVaultAfter; mathint vatArtVaultAfter; vatInkVaultAfter, vatArtVaultAfter = vat.urns(ilk(), currentContract); assert vatInkVaultAfter == vatInkVaultBefore, "draw did not keep vat.urns(ilk,vault).ink unchanged"; assert vatArtVaultAfter == vatArtVaultBefore + dart, "draw did not increase vat.urns(ilk,vault).art by dart"; - assert nstBalanceOfBufferAfter == nstBalanceOfBufferBefore + wad, "draw did not increase nst.balanceOf(buffer) by wad"; - assert nstTotalSupplyAfter == nstTotalSupplyBefore + wad, "draw did not increase nst.totalSupply() by wad"; + assert usdsBalanceOfBufferAfter == usdsBalanceOfBufferBefore + wad, "draw did not increase usds.balanceOf(buffer) by wad"; + assert usdsTotalSupplyAfter == usdsTotalSupplyBefore + wad, "draw did not increase usds.totalSupply() by wad"; } // Verify revert rules on draw @@ -173,9 +173,9 @@ rule draw_revert(uint256 wad) { bool canCall = roles.canCall(ilk(), e.msg.sender, currentContract, to_bytes4(0x3b304147)); mathint wardsSender = wards(e.msg.sender); - mathint nstTotalSupply = nst.totalSupply(); - mathint nstBalanceOfBuffer = nst.balanceOf(buffer()); - require nstBalanceOfBuffer <= nstTotalSupply; + mathint usdsTotalSupply = usds.totalSupply(); + mathint usdsBalanceOfBuffer = usds.balanceOf(buffer()); + require usdsBalanceOfBuffer <= usdsTotalSupply; mathint vatInkVault; mathint vatArtVault; vatInkVault, vatArtVault = vat.urns(ilk(), currentContract); mathint duty = jug.duty(); @@ -186,8 +186,8 @@ rule draw_revert(uint256 wad) { require rate > 0 && rate <= max_int256(); mathint dart = divUp(wad * RAY(), rate); mathint vatDaiVault = vat.dai(currentContract); - mathint vatCanVaultNstJoin = vat.can(currentContract, nstJoin); - mathint vatDaiNstJoin = vat.dai(nstJoin); + mathint vatCanVaultUsdsJoin = vat.can(currentContract, usdsJoin); + mathint vatDaiUsdsJoin = vat.dai(usdsJoin); draw@withrevert(e, wad); @@ -198,9 +198,9 @@ rule draw_revert(uint256 wad) { bool revert5 = vatArtVault + dart > max_uint256; bool revert6 = rate * dart > max_int256(); bool revert7 = vatDaiVault + rate * dart > max_uint256; - bool revert8 = vatCanVaultNstJoin != 1; - bool revert9 = vatDaiNstJoin + wad * RAY() > max_uint256; - bool revert10 = nstTotalSupply + wad > max_uint256; + bool revert8 = vatCanVaultUsdsJoin != 1; + bool revert9 = vatDaiUsdsJoin + wad * RAY() > max_uint256; + bool revert10 = usdsTotalSupply + wad > max_uint256; assert lastReverted <=> revert1 || revert2 || revert3 || revert4 || revert5 || revert6 || @@ -212,9 +212,9 @@ rule draw_revert(uint256 wad) { rule wipe(uint256 wad) { env e; - mathint nstTotalSupplyBefore = nst.totalSupply(); - mathint nstBalanceOfBufferBefore = nst.balanceOf(buffer()); - require nstBalanceOfBufferBefore <= nstTotalSupplyBefore; + mathint usdsTotalSupplyBefore = usds.totalSupply(); + mathint usdsBalanceOfBufferBefore = usds.balanceOf(buffer()); + require usdsBalanceOfBufferBefore <= usdsTotalSupplyBefore; mathint vatInkVaultBefore; mathint vatArtVaultBefore; vatInkVaultBefore, vatArtVaultBefore = vat.urns(ilk(), currentContract); mathint rate = vat.rate() + (jug.duty() - RAY()) * (e.block.timestamp - jug.rho()); @@ -223,15 +223,15 @@ rule wipe(uint256 wad) { wipe(e, wad); - mathint nstTotalSupplyAfter = nst.totalSupply(); - mathint nstBalanceOfBufferAfter = nst.balanceOf(buffer()); + mathint usdsTotalSupplyAfter = usds.totalSupply(); + mathint usdsBalanceOfBufferAfter = usds.balanceOf(buffer()); mathint vatInkVaultAfter; mathint vatArtVaultAfter; vatInkVaultAfter, vatArtVaultAfter = vat.urns(ilk(), currentContract); assert vatInkVaultAfter == vatInkVaultBefore, "wipe did not keep vat.urns(ilk,vault).ink unchanged"; assert vatArtVaultAfter == vatArtVaultBefore - dart, "wipe did not decrease vat.urns(ilk,vault).art by dart"; - assert nstBalanceOfBufferAfter == nstBalanceOfBufferBefore - wad, "wipe did not decrease nst.balanceOf(buffer) by wad"; - assert nstTotalSupplyAfter == nstTotalSupplyBefore - wad, "wipe did not decrease nst.totalSupply() by wad"; + assert usdsBalanceOfBufferAfter == usdsBalanceOfBufferBefore - wad, "wipe did not decrease usds.balanceOf(buffer) by wad"; + assert usdsTotalSupplyAfter == usdsTotalSupplyBefore - wad, "wipe did not decrease usds.totalSupply() by wad"; } // Verify revert rules on wipe @@ -240,14 +240,14 @@ rule wipe_revert(uint256 wad) { bool canCall = roles.canCall(ilk(), e.msg.sender, currentContract, to_bytes4(0xb38a1620)); mathint wardsSender = wards(e.msg.sender); - mathint nstTotalSupply = nst.totalSupply(); + mathint usdsTotalSupply = usds.totalSupply(); address buffer = buffer(); require buffer != currentContract; - mathint nstBalanceOfBuffer = nst.balanceOf(buffer); - mathint nstBalanceOfVault = nst.balanceOf(currentContract); - require nstBalanceOfBuffer + nstBalanceOfVault <= nstTotalSupply; - mathint nstAllowanceBufferVault = nst.allowance(buffer, currentContract); - mathint nstAllowanceVaultNstJoin = nst.allowance(currentContract, nstJoin); + mathint usdsBalanceOfBuffer = usds.balanceOf(buffer); + mathint usdsBalanceOfVault = usds.balanceOf(currentContract); + require usdsBalanceOfBuffer + usdsBalanceOfVault <= usdsTotalSupply; + mathint usdsAllowanceBufferVault = usds.allowance(buffer, currentContract); + mathint usdsAllowanceVaultUsdsJoin = usds.allowance(currentContract, usdsJoin); mathint vatInkVault; mathint vatArtVault; vatInkVault, vatArtVault = vat.urns(ilk(), currentContract); mathint duty = jug.duty(); @@ -258,18 +258,18 @@ rule wipe_revert(uint256 wad) { require rate > 0 && rate <= max_int256(); mathint dart = wad * RAY() / rate; mathint vatDaiVault = vat.dai(currentContract); - mathint vatDaiNstJoin = vat.dai(nstJoin); + mathint vatDaiUsdsJoin = vat.dai(usdsJoin); wipe@withrevert(e, wad); bool revert1 = e.msg.value > 0; bool revert2 = !canCall && wardsSender != 1; - bool revert3 = nstBalanceOfBuffer < to_mathint(wad); - bool revert4 = nstAllowanceBufferVault < to_mathint(wad); + bool revert3 = usdsBalanceOfBuffer < to_mathint(wad); + bool revert4 = usdsAllowanceBufferVault < to_mathint(wad); bool revert5 = wad * RAY() > max_uint256; - bool revert6 = nstAllowanceVaultNstJoin < to_mathint(wad); + bool revert6 = usdsAllowanceVaultUsdsJoin < to_mathint(wad); bool revert7 = vatArtVault < dart; - bool revert8 = vatDaiNstJoin < wad * RAY(); + bool revert8 = vatDaiUsdsJoin < wad * RAY(); bool revert9 = vatDaiVault + wad * RAY() > max_uint256; bool revert10 = rate * dart > max_int256(); diff --git a/deploy/AllocatorDeploy.sol b/deploy/AllocatorDeploy.sol index b372cb66..bf0a2917 100644 --- a/deploy/AllocatorDeploy.sol +++ b/deploy/AllocatorDeploy.sol @@ -52,13 +52,13 @@ library AllocatorDeploy { address owner, address roles, bytes32 ilk, - address nstJoin + address usdsJoin ) internal returns (AllocatorIlkInstance memory ilkInstance) { address _buffer = address(new AllocatorBuffer()); ScriptTools.switchOwner(_buffer, deployer, owner); ilkInstance.buffer = _buffer; - address _vault = address(new AllocatorVault(roles, _buffer, ilk, nstJoin)); + address _vault = address(new AllocatorVault(roles, _buffer, ilk, usdsJoin)); ScriptTools.switchOwner(_vault, deployer, owner); ilkInstance.vault = _vault; diff --git a/deploy/AllocatorInit.sol b/deploy/AllocatorInit.sol index 47f6bfb1..e5986bf3 100644 --- a/deploy/AllocatorInit.sol +++ b/deploy/AllocatorInit.sol @@ -47,7 +47,7 @@ interface VaultLike { function roles() external view returns (address); function buffer() external view returns (address); function vat() external view returns (address); - function nst() external view returns (address); + function usds() external view returns (address); function file(bytes32, address) external; } @@ -107,7 +107,7 @@ library AllocatorInit { require(VaultLike(ilkInstance.vault).roles() == sharedInstance.roles, "AllocatorInit/vault-roles-mismatch"); require(VaultLike(ilkInstance.vault).buffer() == ilkInstance.buffer, "AllocatorInit/vault-buffer-mismatch"); require(VaultLike(ilkInstance.vault).vat() == address(dss.vat), "AllocatorInit/vault-vat-mismatch"); - // Once nstJoin is in the chainlog and adapted to dss-test should also check against it + // Once usdsJoin is in the chainlog and adapted to dss-test should also check against it // Onboard the ilk dss.vat.init(ilk); @@ -134,7 +134,7 @@ library AllocatorInit { VaultLike(ilkInstance.vault).file("jug", address(dss.jug)); // Allow vault to pull funds from the buffer - BufferLike(ilkInstance.buffer).approve(VaultLike(ilkInstance.vault).nst(), ilkInstance.vault, type(uint256).max); + BufferLike(ilkInstance.buffer).approve(VaultLike(ilkInstance.vault).usds(), ilkInstance.vault, type(uint256).max); // Set the allocator proxy as the ilk admin instead of the Pause Proxy RolesLike(sharedInstance.roles).setIlkAdmin(ilk, cfg.allocatorProxy); diff --git a/src/AllocatorVault.sol b/src/AllocatorVault.sol index 4d46ffdb..163c6d0e 100644 --- a/src/AllocatorVault.sol +++ b/src/AllocatorVault.sol @@ -35,8 +35,8 @@ interface GemLike { function transferFrom(address, address, uint256) external; } -interface NstJoinLike { - function nst() external view returns (GemLike); +interface UsdsJoinLike { + function usds() external view returns (GemLike); function vat() external view returns (VatLike); function exit(address, uint256) external; function join(address, uint256) external; @@ -55,12 +55,12 @@ contract AllocatorVault { // --- immutables --- - RolesLike immutable public roles; - address immutable public buffer; - VatLike immutable public vat; - bytes32 immutable public ilk; - NstJoinLike immutable public nstJoin; - GemLike immutable public nst; + RolesLike immutable public roles; + address immutable public buffer; + VatLike immutable public vat; + bytes32 immutable public ilk; + UsdsJoinLike immutable public usdsJoin; + GemLike immutable public usds; // --- events --- @@ -80,18 +80,18 @@ contract AllocatorVault { // --- constructor --- - constructor(address roles_, address buffer_, bytes32 ilk_, address nstJoin_) { + constructor(address roles_, address buffer_, bytes32 ilk_, address usdsJoin_) { roles = RolesLike(roles_); buffer = buffer_; ilk = ilk_; - nstJoin = NstJoinLike(nstJoin_); + usdsJoin = UsdsJoinLike(usdsJoin_); - vat = nstJoin.vat(); - nst = nstJoin.nst(); + vat = usdsJoin.vat(); + usds = usdsJoin.usds(); - vat.hope(nstJoin_); - nst.approve(nstJoin_, type(uint256).max); + vat.hope(usdsJoin_); + usds.approve(usdsJoin_, type(uint256).max); wards[msg.sender] = 1; emit Rely(msg.sender); @@ -132,13 +132,13 @@ contract AllocatorVault { uint256 dart = _divup(wad * RAY, rate); require(dart <= uint256(type(int256).max), "AllocatorVault/overflow"); vat.frob(ilk, address(this), address(0), address(this), 0, int256(dart)); - nstJoin.exit(buffer, wad); + usdsJoin.exit(buffer, wad); emit Draw(msg.sender, wad); } function wipe(uint256 wad) external auth { - nst.transferFrom(buffer, address(this), wad); - nstJoin.join(address(this), wad); + usds.transferFrom(buffer, address(this), wad); + usdsJoin.join(address(this), wad); uint256 rate = jug.drip(ilk); uint256 dart = wad * RAY / rate; require(dart <= uint256(type(int256).max), "AllocatorVault/overflow"); diff --git a/test/AllocatorVault.t.sol b/test/AllocatorVault.t.sol index 4f4cde38..c693f5b6 100644 --- a/test/AllocatorVault.t.sol +++ b/test/AllocatorVault.t.sol @@ -9,15 +9,15 @@ import { RolesMock } from "test/mocks/RolesMock.sol"; import { VatMock } from "test/mocks/VatMock.sol"; import { JugMock } from "test/mocks/JugMock.sol"; import { GemMock } from "test/mocks/GemMock.sol"; -import { NstJoinMock } from "test/mocks/NstJoinMock.sol"; +import { UsdsJoinMock } from "test/mocks/UsdsJoinMock.sol"; contract AllocatorVaultTest is DssTest { using stdStorage for StdStorage; VatMock public vat; JugMock public jug; - GemMock public nst; - NstJoinMock public nstJoin; + GemMock public usds; + UsdsJoinMock public usdsJoin; AllocatorBuffer public buffer; RolesMock public roles; AllocatorVault public vault; @@ -35,32 +35,32 @@ contract AllocatorVaultTest is DssTest { } function setUp() public { - ilk = "TEST-ILK"; - vat = new VatMock(); - jug = new JugMock(vat); - nst = new GemMock(0); - nstJoin = new NstJoinMock(vat, nst); - buffer = new AllocatorBuffer(); - roles = new RolesMock(); - vault = new AllocatorVault(address(roles), address(buffer), ilk, address(nstJoin)); - buffer.approve(address(nst), address(vault), type(uint256).max); + ilk = "TEST-ILK"; + vat = new VatMock(); + jug = new JugMock(vat); + usds = new GemMock(0); + usdsJoin = new UsdsJoinMock(vat, usds); + buffer = new AllocatorBuffer(); + roles = new RolesMock(); + vault = new AllocatorVault(address(roles), address(buffer), ilk, address(usdsJoin)); + buffer.approve(address(usds), address(vault), type(uint256).max); vat.slip(ilk, address(vault), int256(1_000_000 * WAD)); vat.grab(ilk, address(vault), address(vault), address(0), int256(1_000_000 * WAD), 0); - // Add some existing DAI assigned to nstJoin to avoid a particular error - stdstore.target(address(vat)).sig("dai(address)").with_key(address(nstJoin)).depth(0).checked_write(100_000 * RAD); + // Add some existing DAI assigned to usdsJoin to avoid a particular error + stdstore.target(address(vat)).sig("dai(address)").with_key(address(usdsJoin)).depth(0).checked_write(100_000 * RAD); } function testConstructor() public { vm.expectEmit(true, true, true, true); emit Rely(address(this)); - address join = address(new NstJoinMock(vat, nst)); + address join = address(new UsdsJoinMock(vat, usds)); AllocatorVault v = new AllocatorVault(address(0xBEEF), address(0xCCC), "SubDAO 1", join); assertEq(address(v.roles()), address(0xBEEF)); assertEq(v.buffer(), address(0xCCC)); assertEq(v.ilk(), "SubDAO 1"); - assertEq(address(v.nstJoin()), join); + assertEq(address(v.usdsJoin()), join); assertEq(v.wards(address(this)), 1); } @@ -100,7 +100,7 @@ contract AllocatorVaultTest is DssTest { (, art) = vat.urns(ilk, address(vault)); assertEq(art, 50 * 10**18); assertEq(vat.rate(), 10**27); - assertEq(nst.balanceOf(address(buffer)), 50 * 10**18); + assertEq(usds.balanceOf(address(buffer)), 50 * 10**18); vm.warp(block.timestamp + 1); vm.expectEmit(true, true, true, true); emit Draw(address(this), 50 * 10**18); @@ -109,19 +109,19 @@ contract AllocatorVaultTest is DssTest { uint256 expectedArt = 50 * 10**18 + _divup(50 * 10**18 * 1000, 1001); assertEq(art, expectedArt); assertEq(vat.rate(), 1001 * 10**27 / 1000); - assertEq(nst.balanceOf(address(buffer)), 100 * 10**18); + assertEq(usds.balanceOf(address(buffer)), 100 * 10**18); assertGt(art * vat.rate(), 100.05 * 10**45); assertLt(art * vat.rate(), 100.06 * 10**45); vm.expectRevert("Gem/insufficient-balance"); vault.wipe(100.06 * 10**18); - deal(address(nst), address(buffer), 100.06 * 10**18, true); - assertEq(nst.balanceOf(address(buffer)), 100.06 * 10**18); + deal(address(usds), address(buffer), 100.06 * 10**18, true); + assertEq(usds.balanceOf(address(buffer)), 100.06 * 10**18); vm.expectRevert(); vault.wipe(100.06 * 10**18); // It will try to wipe more art than existing, then reverts vm.expectEmit(true, true, true, true); emit Wipe(address(this), 100.05 * 10**18); vault.wipe(100.05 * 10**18); - assertEq(nst.balanceOf(address(buffer)), 0.01 * 10**18); + assertEq(usds.balanceOf(address(buffer)), 0.01 * 10**18); (, art) = vat.urns(ilk, address(vault)); assertEq(art, 1); // Dust which is impossible to wipe } diff --git a/test/funnels/automation/VaultMinter.t.sol b/test/funnels/automation/VaultMinter.t.sol index d74a15b5..a4d78a3c 100644 --- a/test/funnels/automation/VaultMinter.t.sol +++ b/test/funnels/automation/VaultMinter.t.sol @@ -10,7 +10,7 @@ import { AllocatorBuffer } from "src/AllocatorBuffer.sol"; import { VatMock } from "test/mocks/VatMock.sol"; import { JugMock } from "test/mocks/JugMock.sol"; import { GemMock } from "test/mocks/GemMock.sol"; -import { NstJoinMock } from "test/mocks/NstJoinMock.sol"; +import { UsdsJoinMock } from "test/mocks/UsdsJoinMock.sol"; contract VaultMinterTest is DssTest { using stdStorage for StdStorage; @@ -23,8 +23,8 @@ contract VaultMinterTest is DssTest { VatMock public vat; JugMock public jug; - GemMock public nst; - NstJoinMock public nstJoin; + GemMock public usds; + UsdsJoinMock public usdsJoin; AllocatorBuffer public buffer; AllocatorRoles public roles; AllocatorVault public vault; @@ -36,15 +36,15 @@ contract VaultMinterTest is DssTest { uint8 constant MINTER_ROLE = uint8(1); function setUp() public { - vat = new VatMock(); - jug = new JugMock(vat); - nst = new GemMock(0); - nstJoin = new NstJoinMock(vat, nst); - buffer = new AllocatorBuffer(); - roles = new AllocatorRoles(); - vault = new AllocatorVault(address(roles), address(buffer), ILK, address(nstJoin)); + vat = new VatMock(); + jug = new JugMock(vat); + usds = new GemMock(0); + usdsJoin = new UsdsJoinMock(vat, usds); + buffer = new AllocatorBuffer(); + roles = new AllocatorRoles(); + vault = new AllocatorVault(address(roles), address(buffer), ILK, address(usdsJoin)); vault.file("jug", address(jug)); - buffer.approve(address(nst), address(vault), type(uint256).max); + buffer.approve(address(usds), address(vault), type(uint256).max); vat.slip(ILK, address(vault), int256(1_000_000 * WAD)); vat.grab(ILK, address(vault), address(vault), address(0), int256(1_000_000 * WAD), 0); @@ -135,7 +135,7 @@ contract VaultMinterTest is DssTest { function testDrawWipeByKeeper() public { minter.setConfig(int64(10), uint32(1 hours), uint128(1_000 * WAD)); - assertEq(nst.balanceOf(address(buffer)), 0); + assertEq(usds.balanceOf(address(buffer)), 0); (int64 num, uint32 hop, uint32 zzz, uint128 lot) = minter.config(); assertEq(num, 10); assertEq(hop, 1 hours); @@ -146,7 +146,7 @@ contract VaultMinterTest is DssTest { emit Draw(uint128(1_000 * WAD)); vm.prank(KEEPER); minter.draw(); - assertEq(nst.balanceOf(address(buffer)), 1_000 * WAD); + assertEq(usds.balanceOf(address(buffer)), 1_000 * WAD); (num, hop, zzz, lot) = minter.config(); assertEq(num, 9); assertEq(hop, 1 hours); @@ -160,7 +160,7 @@ contract VaultMinterTest is DssTest { vm.warp(block.timestamp + 1); vm.prank(KEEPER); minter.draw(); - assertEq(nst.balanceOf(address(buffer)), 2_000 * WAD); + assertEq(usds.balanceOf(address(buffer)), 2_000 * WAD); (num, hop, zzz, lot) = minter.config(); assertEq(num, 8); assertEq(hop, 1 hours); @@ -179,7 +179,7 @@ contract VaultMinterTest is DssTest { emit Wipe(uint128(100 * WAD)); vm.prank(KEEPER); minter.wipe(); - assertEq(nst.balanceOf(address(buffer)), 1_900 * WAD); + assertEq(usds.balanceOf(address(buffer)), 1_900 * WAD); (num, hop, zzz, lot) = minter.config(); assertEq(num, -9); assertEq(hop, 1 hours); @@ -193,7 +193,7 @@ contract VaultMinterTest is DssTest { vm.warp(block.timestamp + 1); vm.prank(KEEPER); minter.wipe(); - assertEq(nst.balanceOf(address(buffer)), 1_800 * WAD); + assertEq(usds.balanceOf(address(buffer)), 1_800 * WAD); (num, hop, zzz, lot) = minter.config(); assertEq(num, -8); assertEq(hop, 1 hours); diff --git a/test/integration/Deployment.t.sol b/test/integration/Deployment.t.sol index 3011bab9..5cb80411 100644 --- a/test/integration/Deployment.t.sol +++ b/test/integration/Deployment.t.sol @@ -28,7 +28,7 @@ import { AllocatorFunnelInit, AllocatorIlkFunnelConfig } from "deploy/funnels/Al import { SwapperCalleeUniV3 } from "src/funnels/callees/SwapperCalleeUniV3.sol"; import { GemMock } from "test/mocks/GemMock.sol"; -import { NstJoinMock } from "test/mocks/NstJoinMock.sol"; +import { UsdsJoinMock } from "test/mocks/UsdsJoinMock.sol"; import { VatMock } from "test/mocks/VatMock.sol"; import { AllocatorConduitMock } from "test/mocks/AllocatorConduitMock.sol"; @@ -105,8 +105,8 @@ contract DeploymentTest is DssTest { uint8 constant automationRole = uint8(2); // contracts to be deployed - address nst; - address nstJoin; + address usds; + address usdsJoin; address uniV3Callee; address conduit1; address conduit2; @@ -130,8 +130,8 @@ contract DeploymentTest is DssTest { ILK_REGISTRY = ChainlogLike(LOG).getAddress("ILK_REGISTRY"); USDC = ChainlogLike(LOG).getAddress("USDC"); - nst = address(new GemMock(0)); - nstJoin = address(new NstJoinMock(VatMock(address(dss.vat)), GemMock(nst))); + usds = address(new GemMock(0)); + usdsJoin = address(new UsdsJoinMock(VatMock(address(dss.vat)), GemMock(usds))); uniV3Callee = address(new SwapperCalleeUniV3(UNIV3_ROUTER)); usdcDaiPath = abi.encodePacked(USDC, uint24(100), address(dss.dai)); @@ -143,7 +143,7 @@ contract DeploymentTest is DssTest { owner : PAUSE_PROXY, roles : sharedInst.roles, ilk : ILK, - nstJoin : nstJoin + usdsJoin : usdsJoin }); ilkFunnelInst = AllocatorFunnelDeploy.deployIlkFunnel({ deployer : address(this), @@ -279,7 +279,7 @@ contract DeploymentTest is DssTest { assertEq(AllocatorRegistry(sharedInst.registry).buffers(ILK), ilkInst.buffer); assertEq(address(AllocatorVault(ilkInst.vault).jug()), address(dss.jug)); - assertEq(GemLike(nst).allowance(ilkInst.buffer, ilkInst.vault), type(uint256).max); + assertEq(GemLike(usds).allowance(ilkInst.buffer, ilkInst.vault), type(uint256).max); assertEq(GemLike(address(dss.dai)).allowance(ilkInst.buffer, ilkFunnelInst.swapper), type(uint256).max); assertEq(GemLike(address(dss.dai)).allowance(ilkInst.buffer, ilkFunnelInst.depositorUniV3), type(uint256).max); assertEq(GemLike(USDC).allowance(ilkInst.buffer, ilkFunnelInst.depositorUniV3), type(uint256).max); diff --git a/test/mocks/NstJoinMock.sol b/test/mocks/UsdsJoinMock.sol similarity index 68% rename from test/mocks/NstJoinMock.sol rename to test/mocks/UsdsJoinMock.sol index 20913ffc..5350848a 100644 --- a/test/mocks/NstJoinMock.sol +++ b/test/mocks/UsdsJoinMock.sol @@ -5,22 +5,22 @@ pragma solidity ^0.8.16; import { VatMock } from "test/mocks/VatMock.sol"; import { GemMock } from "test/mocks/GemMock.sol"; -contract NstJoinMock { +contract UsdsJoinMock { VatMock public vat; - GemMock public nst; + GemMock public usds; - constructor(VatMock vat_, GemMock nst_) { - vat = vat_; - nst = nst_; + constructor(VatMock vat_, GemMock usds_) { + vat = vat_; + usds = usds_; } function join(address usr, uint256 wad) external { vat.move(address(this), usr, wad * 10**27); - nst.burn(msg.sender, wad); + usds.burn(msg.sender, wad); } function exit(address usr, uint256 wad) external { vat.move(msg.sender, address(this), wad * 10**27); - nst.mint(usr, wad); + usds.mint(usr, wad); } } diff --git a/test/mocks/NstMock.sol b/test/mocks/UsdsMock.sol similarity index 84% rename from test/mocks/NstMock.sol rename to test/mocks/UsdsMock.sol index 555736f1..6b033e0e 100644 --- a/test/mocks/NstMock.sol +++ b/test/mocks/UsdsMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.16; -contract NstMock { +contract UsdsMock { mapping (address => uint256) public balanceOf; mapping (address => mapping (address => uint256)) public allowance; @@ -19,7 +19,7 @@ contract NstMock { function transfer(address to, uint256 value) external returns (bool) { uint256 balance = balanceOf[msg.sender]; - require(balance >= value, "Nst/insufficient-balance"); + require(balance >= value, "Usds/insufficient-balance"); unchecked { balanceOf[msg.sender] = balance - value; @@ -30,12 +30,12 @@ contract NstMock { function transferFrom(address from, address to, uint256 value) external returns (bool) { uint256 balance = balanceOf[from]; - require(balance >= value, "Nst/insufficient-balance"); + require(balance >= value, "Usds/insufficient-balance"); if (from != msg.sender) { uint256 allowed = allowance[from][msg.sender]; if (allowed != type(uint256).max) { - require(allowed >= value, "Nst/insufficient-allowance"); + require(allowed >= value, "Usds/insufficient-allowance"); unchecked { allowance[from][msg.sender] = allowed - value; @@ -59,12 +59,12 @@ contract NstMock { function burn(address from, uint256 value) external { uint256 balance = balanceOf[from]; - require(balance >= value, "Nst/insufficient-balance"); + require(balance >= value, "Usds/insufficient-balance"); if (from != msg.sender) { uint256 allowed = allowance[from][msg.sender]; if (allowed != type(uint256).max) { - require(allowed >= value, "Nst/insufficient-allowance"); + require(allowed >= value, "Usds/insufficient-allowance"); unchecked { allowance[from][msg.sender] = allowed - value; From 6e99d87374cff66e93fe44c55d4ed240dac1c3dc Mon Sep 17 00:00:00 2001 From: sunbreak1211 <129470872+sunbreak1211@users.noreply.github.com> Date: Mon, 9 Sep 2024 15:42:40 -0300 Subject: [PATCH 74/74] Update CS reports (#81) --- ...AO_Allocator_Deployment_Scripts_audit.pdf} | Bin 491277 -> 494327 bytes ...hainSecurity_MakerDAO_Allocator_audit.pdf} | Bin 596767 -> 612392 bytes 2 files changed, 0 insertions(+), 0 deletions(-) rename audit/{ChainSecurity_MakerDAO_Allocator_Deployment_Scripts_audit.pdf => 20240909-ChainSecurity_MakerDAO_Allocator_Deployment_Scripts_audit.pdf} (95%) rename audit/{ChainSecurity_Maker_DSS_Allocator_audit.pdf => 20240909-ChainSecurity_MakerDAO_Allocator_audit.pdf} (92%) diff --git a/audit/ChainSecurity_MakerDAO_Allocator_Deployment_Scripts_audit.pdf b/audit/20240909-ChainSecurity_MakerDAO_Allocator_Deployment_Scripts_audit.pdf similarity index 95% rename from audit/ChainSecurity_MakerDAO_Allocator_Deployment_Scripts_audit.pdf rename to audit/20240909-ChainSecurity_MakerDAO_Allocator_Deployment_Scripts_audit.pdf index 1c42f25e7c10907a6ae64769ac7b98c54909c11f..ccbaa117c38df68d5e757e86625df1cf701d07d2 100644 GIT binary patch delta 12000 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 diff --git a/audit/ChainSecurity_Maker_DSS_Allocator_audit.pdf b/audit/20240909-ChainSecurity_MakerDAO_Allocator_audit.pdf similarity index 92% rename from audit/ChainSecurity_Maker_DSS_Allocator_audit.pdf rename to audit/20240909-ChainSecurity_MakerDAO_Allocator_audit.pdf index 20b25a1f84d7356cad81d8d0f8e9e1d1badbd5f0..a7f5ab48126db0f8771d37cc81c8df52dea55623 100644 GIT binary patch delta 27044 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