From 05119a256ded7c95b4c7a5331798900cd0ce3047 Mon Sep 17 00:00:00 2001 From: SamG Date: Wed, 1 Dec 2021 20:55:52 +0000 Subject: [PATCH 1/5] [FIX] tests index file fixed, added all test cases/files. --- tests/index.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/tests/index.js b/tests/index.js index 00a1495d..70f39497 100644 --- a/tests/index.js +++ b/tests/index.js @@ -1,12 +1,11 @@ context("Unit Tests", async () => { - //require("./application"); - //require("./generics"); - //require("./votingContract"); - //require("./bepro/network"); - //require("./erc20Contract"); - //require('./dexStorage'); - //require("./erc20TokenLock"); - //require("./stakingContract"); - //require("./sablier/sablier"); + require("./application"); + require("./generics"); + require("./votingContract"); + require("./bepro/network"); + require("./erc20Contract"); + require('./dexStorage'); + require("./erc20TokenLock"); + require("./stakingContract"); require("./custom/loophole/loophole"); }); From 3ccebe15876f79269ea196eda79bc967063a5a22 Mon Sep 17 00:00:00 2001 From: SamG Date: Wed, 1 Dec 2021 21:03:20 +0000 Subject: [PATCH 2/5] [FIX] -fixed test index.js file, added all test cases. --- tests/index.js | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/tests/index.js b/tests/index.js index 4eb5056c..3fc94852 100644 --- a/tests/index.js +++ b/tests/index.js @@ -1,13 +1,12 @@ context("Unit Tests", async () => { - //require("./application"); - //require("./generics"); - //require("./votingContract"); - //require("./bepro/network"); + require("./application"); + require("./generics"); + require("./votingContract"); + require("./bepro/network"); require("./bepro/networkFactory"); - //require("./erc20Contract"); - //require('./dexStorage'); - //require("./erc20TokenLock"); - //require("./stakingContract"); - //require("./sablier/sablier"); - //require("./custom/loophole/loophole"); + require("./erc20Contract"); + require('./dexStorage'); + require("./erc20TokenLock"); + require("./stakingContract"); + require("./custom/loophole/loophole"); }); From f94b9b295d551e4d84f8179673f2fa0f12636184 Mon Sep 17 00:00:00 2001 From: SamG Date: Wed, 1 Dec 2021 21:24:44 +0000 Subject: [PATCH 3/5] [CODE REFACTORY] -sablier branch was removed as it has its own pull request. --- contracts/sablier/LICENSE.md | 674 -------------- contracts/sablier/protocol/Sablier.sol | 842 ------------------ contracts/sablier/protocol/Types.sol | 28 - .../protocol/interfaces/ICTokenManager.sol | 23 - .../sablier/protocol/interfaces/IERC1620.sol | 61 -- .../sablier/shared-contracts/ERC20Base.sol | 193 ---- .../shared-contracts/compound/CarefulMath.sol | 85 -- .../compound/EIP20Interface.sol | 59 -- .../shared-contracts/compound/Exponential.sol | 226 ----- .../shared-contracts/interfaces/ICERC20.sol | 28 - .../lifecycle/OwnableWithoutRenounce.sol | 71 -- .../shared-contracts/mocks/CERC20Mock.sol | 116 --- .../shared-contracts/test/EvilERC20.sol | 58 -- .../test/NonStandardERC20.sol | 102 --- src/index.js | 2 - src/models/Sablier/Sablier.js | 440 --------- tests/sablier/admin/TakeEarnings.js | 184 ---- tests/sablier/admin/UpdateFee.js | 50 -- .../CancelCompoundingStream.js | 328 ------- .../CreateCompoundingStream.js | 184 ---- .../WithdrawFromCompoundingStream.js | 366 -------- tests/sablier/effects/stream/CancelStream.js | 168 ---- tests/sablier/effects/stream/CreateStream.js | 331 ------- .../effects/stream/WithdrawFromStream.js | 233 ----- tests/sablier/sablier.behavior.js | 107 --- tests/sablier/sablier.js | 246 ----- tests/sablier/view/BalanceOf.js | 119 --- tests/sablier/view/DeltaOf.js | 71 -- tests/sablier/view/GetCompoundingStream.js | 48 - tests/sablier/view/GetEarnings.js | 15 - tests/sablier/view/GetStream.js | 16 - tests/sablier/view/InterestOf.js | 48 - tests/sablier/view/IsCompoundingStream.js | 85 -- 33 files changed, 5607 deletions(-) delete mode 100644 contracts/sablier/LICENSE.md delete mode 100644 contracts/sablier/protocol/Sablier.sol delete mode 100644 contracts/sablier/protocol/Types.sol delete mode 100644 contracts/sablier/protocol/interfaces/ICTokenManager.sol delete mode 100644 contracts/sablier/protocol/interfaces/IERC1620.sol delete mode 100644 contracts/sablier/shared-contracts/ERC20Base.sol delete mode 100644 contracts/sablier/shared-contracts/compound/CarefulMath.sol delete mode 100644 contracts/sablier/shared-contracts/compound/EIP20Interface.sol delete mode 100644 contracts/sablier/shared-contracts/compound/Exponential.sol delete mode 100644 contracts/sablier/shared-contracts/interfaces/ICERC20.sol delete mode 100644 contracts/sablier/shared-contracts/lifecycle/OwnableWithoutRenounce.sol delete mode 100644 contracts/sablier/shared-contracts/mocks/CERC20Mock.sol delete mode 100644 contracts/sablier/shared-contracts/test/EvilERC20.sol delete mode 100644 contracts/sablier/shared-contracts/test/NonStandardERC20.sol delete mode 100644 src/models/Sablier/Sablier.js delete mode 100644 tests/sablier/admin/TakeEarnings.js delete mode 100644 tests/sablier/admin/UpdateFee.js delete mode 100644 tests/sablier/effects/compoundingStream/CancelCompoundingStream.js delete mode 100644 tests/sablier/effects/compoundingStream/CreateCompoundingStream.js delete mode 100644 tests/sablier/effects/compoundingStream/WithdrawFromCompoundingStream.js delete mode 100644 tests/sablier/effects/stream/CancelStream.js delete mode 100644 tests/sablier/effects/stream/CreateStream.js delete mode 100644 tests/sablier/effects/stream/WithdrawFromStream.js delete mode 100644 tests/sablier/sablier.behavior.js delete mode 100644 tests/sablier/sablier.js delete mode 100644 tests/sablier/view/BalanceOf.js delete mode 100644 tests/sablier/view/DeltaOf.js delete mode 100644 tests/sablier/view/GetCompoundingStream.js delete mode 100644 tests/sablier/view/GetEarnings.js delete mode 100644 tests/sablier/view/GetStream.js delete mode 100644 tests/sablier/view/InterestOf.js delete mode 100644 tests/sablier/view/IsCompoundingStream.js diff --git a/contracts/sablier/LICENSE.md b/contracts/sablier/LICENSE.md deleted file mode 100644 index 4af7c410..00000000 --- a/contracts/sablier/LICENSE.md +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - -Copyright (C) 2019-2020 Sablier -Everyone is permitted to copy and distribute verbatim copies -of this license document, but changing it is not allowed. - - Preamble - -The GNU General Public License is a free, copyleft license for -software and other kinds of works. - -The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - -When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - -To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - -For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - -Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - -For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - -Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - -Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - -The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - -0. Definitions. - -"This License" refers to version 3 of the GNU General Public License. - -"Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - -"The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - -To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - -A "covered work" means either the unmodified Program or a work based -on the Program. - -To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - -To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - -An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - -1. Source Code. - -The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - -A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - -The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - -The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - -The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - -The Corresponding Source for a work in source code form is that -same work. - -2. Basic Permissions. - -All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - -You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - -Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - -3. Protecting Users' Legal Rights From Anti-Circumvention Law. - -No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - -When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - -4. Conveying Verbatim Copies. - -You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - -You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - -5. Conveying Modified Source Versions. - -You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - -A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - -6. Conveying Non-Source Forms. - -You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - -A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - -A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - -"Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - -If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - -The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - -Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - -7. Additional Terms. - -"Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - -When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - -Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - -All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - -If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - -Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - -8. Termination. - -You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - -However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - -Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - -Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - -9. Acceptance Not Required for Having Copies. - -You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - -10. Automatic Licensing of Downstream Recipients. - -Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - -An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - -You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - -11. Patents. - -A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - -A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - -Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - -In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - -If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - -If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - -A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - -Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - -12. No Surrender of Others' Freedom. - -If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - -13. Use with the GNU Affero General Public License. - -Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - -14. Revised Versions of this License. - -The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - -If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - -Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - -15. Disclaimer of Warranty. - -THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - -16. Limitation of Liability. - -IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - -17. Interpretation of Sections 15 and 16. - -If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - -If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - -To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - -If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and`show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - -You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - -The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/contracts/sablier/protocol/Sablier.sol b/contracts/sablier/protocol/Sablier.sol deleted file mode 100644 index 6bc7e359..00000000 --- a/contracts/sablier/protocol/Sablier.sol +++ /dev/null @@ -1,842 +0,0 @@ -pragma solidity >=0.6.0; - -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; - -import "../shared-contracts/compound/Exponential.sol"; -import "../shared-contracts/interfaces/ICERC20.sol"; -import "../../lifecycle/PausableWithoutRenounce.sol"; -import "../../utils/Ownable.sol"; - -import "./interfaces/IERC1620.sol"; -import "./Types.sol"; -import "../../IERC20View.sol"; - -/** - * @title Sablier's Money Streaming - * @author Sablier - */ -contract Sablier is IERC1620, Ownable, PausableWithoutRenounce, Exponential, ReentrancyGuard { - /*** Storage Properties ***/ - - // In Exp terms, 1e18 is 1, or 100% - uint256 constant hundredPercent = 1e18; - - // In Exp terms, 1e16 is 0.01, or 1% - uint256 constant onePercent = 1e16; - - // Stores information about the initial state of the underlying of the cToken. - mapping(uint256 => Types.CompoundingStreamVars) private compoundingStreamsVars; - - // The amount of interest has been accrued per token address. - mapping(address => uint256) private earnings; - - /** - * @notice The percentage fee charged by the contract on the accrued interest. - */ - Exp public fee; - - /** - * @notice Counter for new stream ids. - */ - uint256 public nextStreamId; - - // The stream objects identifiable by their unsigned integer ids. - mapping(uint256 => Types.Stream) private streams; - - /*** Events ***/ - - /** - * @notice Emits when a compounding stream is successfully created. - */ - event CreateCompoundingStream( - uint256 indexed streamId, - uint256 exchangeRate, - uint256 senderSharePercentage, - uint256 recipientSharePercentage - ); - - /** - * @notice Emits when the owner discards a cToken. - */ - event PayInterest( - uint256 indexed streamId, - uint256 senderInterest, - uint256 recipientInterest, - uint256 sablierInterest - ); - - /** - * @notice Emits when the owner takes the earnings. - */ - event TakeEarnings(address indexed tokenAddress, uint256 indexed amount); - - /** - * @notice Emits when the owner updates the percentage fee. - */ - event UpdateFee(uint256 indexed fee); - - /*** Modifiers ***/ - - /** - * @dev Throws if the caller is not the sender of the recipient of the stream. - */ - modifier onlySenderOrRecipient(uint256 streamId) { - require( - msg.sender == streams[streamId].sender || msg.sender == streams[streamId].recipient, - "caller is not the sender or the recipient of the stream" - ); - _; - } - - /** - * @dev Throws if the provided id does not point to a valid stream. - */ - modifier streamExists(uint256 streamId) { - require(streams[streamId].isEntity, "stream does not exist"); - _; - } - - /** - * @dev Throws if the provided id does not point to a valid compounding stream. - */ - modifier compoundingStreamExists(uint256 streamId) { - require(compoundingStreamsVars[streamId].isEntity, "compounding stream does not exist"); - _; - } - - /*** Contract Logic Starts Here */ - - constructor() public { - PausableWithoutRenounce.initialize(msg.sender); - nextStreamId = 1; - } - - /*** Owner Functions ***/ - - struct UpdateFeeLocalVars { - MathError mathErr; - uint256 feeMantissa; - } - - /** - * @notice Updates the Sablier fee. - * @dev Throws if the caller is not the owner of the contract. - * Throws if `feePercentage` is not lower or equal to 100. - * @param feePercentage The new fee as a percentage. - */ - function updateFee(uint256 feePercentage) external onlyOwner { - require(feePercentage <= 100, "fee percentage higher than 100%"); - UpdateFeeLocalVars memory vars; - - /* `feePercentage` will be stored as a mantissa, so we scale it up by one percent in Exp terms. */ - (vars.mathErr, vars.feeMantissa) = mulUInt(feePercentage, onePercent); - /* - * `mulUInt` can only return MathError.INTEGER_OVERFLOW but we control `onePercent` - * and we know `feePercentage` is maximum 100. - */ - assert(vars.mathErr == MathError.NO_ERROR); - - fee = Exp({ mantissa: vars.feeMantissa }); - emit UpdateFee(feePercentage); - } - - struct TakeEarningsLocalVars { - MathError mathErr; - } - - /** - * @notice Withdraws the earnings for the given token address. - * @dev Throws if `amount` exceeds the available balance. - * @param tokenAddress The address of the token to withdraw earnings for. - * @param amount The amount of tokens to withdraw. - */ - function takeEarnings(address tokenAddress, uint256 amount) external onlyOwner nonReentrant { - require(amount > 0, "amount is zero"); - require(earnings[tokenAddress] >= amount, "amount exceeds the available balance"); - - TakeEarningsLocalVars memory vars; - (vars.mathErr, earnings[tokenAddress]) = subUInt(earnings[tokenAddress], amount); - /* - * `subUInt` can only return MathError.INTEGER_UNDERFLOW but we know `earnings[tokenAddress]` - * is at least as big as `amount`. - */ - assert(vars.mathErr == MathError.NO_ERROR); - - emit TakeEarnings(tokenAddress, amount); - require(IERC20(tokenAddress).transfer(msg.sender, amount), "token transfer failure"); - } - - /*** View Functions ***/ - - /** - * @notice Returns the compounding stream with all its properties. - * @dev Throws if the id does not point to a valid stream. - * @param streamId The id of the stream to query. - * @return sender recipient deposit tokenAddress startTime stopTime remainingBalance ratePerSecond The stream object. - */ - function getStream(uint256 streamId) - external - view - override - streamExists(streamId) - returns ( - address sender, - address recipient, - uint256 deposit, - address tokenAddress, - uint256 startTime, - uint256 stopTime, - uint256 remainingBalance, - uint256 ratePerSecond - ) - { - sender = streams[streamId].sender; - recipient = streams[streamId].recipient; - deposit = streams[streamId].deposit; - tokenAddress = streams[streamId].tokenAddress; - startTime = streams[streamId].startTime; - stopTime = streams[streamId].stopTime; - remainingBalance = streams[streamId].remainingBalance; - ratePerSecond = streams[streamId].ratePerSecond; - } - - /** - * @notice Returns either the delta in seconds between `block.timestamp` and `startTime` or - * between `stopTime` and `startTime, whichever is smaller. If `block.timestamp` is before - * `startTime`, it returns 0. - * @dev Throws if the id does not point to a valid stream. - * @param streamId The id of the stream for which to query the delta. - * @return delta The time delta in seconds. - */ - function deltaOf(uint256 streamId) public view streamExists(streamId) returns (uint256 delta) { - Types.Stream memory stream = streams[streamId]; - if (block.timestamp <= stream.startTime) return 0; - if (block.timestamp < stream.stopTime) return block.timestamp - stream.startTime; - return stream.stopTime - stream.startTime; - } - - struct BalanceOfLocalVars { - MathError mathErr; - uint256 recipientBalance; - uint256 withdrawalAmount; - uint256 senderBalance; - } - - /** - * @notice Returns the available funds for the given stream id and address. - * @dev Throws if the id does not point to a valid stream. - * @param streamId The id of the stream for which to query the balance. - * @param who The address for which to query the balance. - * @return balance The total funds allocated to `who` as uint256. - */ - function balanceOf(uint256 streamId, address who) public view override streamExists(streamId) returns (uint256 balance) { - Types.Stream memory stream = streams[streamId]; - BalanceOfLocalVars memory vars; - - uint256 delta = deltaOf(streamId); - (vars.mathErr, vars.recipientBalance) = mulUInt(delta, stream.ratePerSecond); - require(vars.mathErr == MathError.NO_ERROR, "recipient balance calculation error"); - - /* - * If the stream `balance` does not equal `deposit`, it means there have been withdrawals. - * We have to subtract the total amount withdrawn from the amount of money that has been - * streamed until now. - */ - if (stream.deposit > stream.remainingBalance) { - (vars.mathErr, vars.withdrawalAmount) = subUInt(stream.deposit, stream.remainingBalance); - assert(vars.mathErr == MathError.NO_ERROR); - (vars.mathErr, vars.recipientBalance) = subUInt(vars.recipientBalance, vars.withdrawalAmount); - /* `withdrawalAmount` cannot and should not be bigger than `recipientBalance`. */ - assert(vars.mathErr == MathError.NO_ERROR); - } - - if (who == stream.recipient) return vars.recipientBalance; - if (who == stream.sender) { - (vars.mathErr, vars.senderBalance) = subUInt(stream.remainingBalance, vars.recipientBalance); - /* `recipientBalance` cannot and should not be bigger than `remainingBalance`. */ - assert(vars.mathErr == MathError.NO_ERROR); - return vars.senderBalance; - } - return 0; - } - - /** - * @notice Checks if the provided id points to a valid compounding stream. - * @param streamId The id of the compounding stream to check. - * @return bool true=if it is a compounding stream, otherwise false. - */ - function isCompoundingStream(uint256 streamId) public view returns (bool) { - return compoundingStreamsVars[streamId].isEntity; - } - - /** - * @notice Returns the compounding stream object with all its properties. - * @dev Throws if the id does not point to a valid compounding stream. - * @param streamId The id of the compounding stream to query. - * @return sender recipient deposit tokenAddress startTime stopTime remainingBalance ratePerSecond exchangeRateInitial senderSharePercentage recipientSharePercentage The compounding stream object. - */ - function getCompoundingStream(uint256 streamId) - external - view - streamExists(streamId) - compoundingStreamExists(streamId) - returns ( - address sender, - address recipient, - uint256 deposit, - address tokenAddress, - uint256 startTime, - uint256 stopTime, - uint256 remainingBalance, - uint256 ratePerSecond, - uint256 exchangeRateInitial, - uint256 senderSharePercentage, - uint256 recipientSharePercentage - ) - { - sender = streams[streamId].sender; - recipient = streams[streamId].recipient; - deposit = streams[streamId].deposit; - tokenAddress = streams[streamId].tokenAddress; - startTime = streams[streamId].startTime; - stopTime = streams[streamId].stopTime; - remainingBalance = streams[streamId].remainingBalance; - ratePerSecond = streams[streamId].ratePerSecond; - exchangeRateInitial = compoundingStreamsVars[streamId].exchangeRateInitial.mantissa; - senderSharePercentage = compoundingStreamsVars[streamId].senderShare.mantissa; - recipientSharePercentage = compoundingStreamsVars[streamId].recipientShare.mantissa; - } - - struct InterestOfLocalVars { - MathError mathErr; - Exp exchangeRateDelta; - Exp underlyingInterest; - Exp netUnderlyingInterest; - Exp senderUnderlyingInterest; - Exp recipientUnderlyingInterest; - Exp sablierUnderlyingInterest; - Exp senderInterest; - Exp recipientInterest; - Exp sablierInterest; - } - - /** - * @notice Computes the interest accrued while the money has been streamed. Returns (0, 0, 0) if - * the stream is either not a compounding stream or it does not exist. - * @dev Throws if there is a math error. We do not assert the calculations which involve the current - * exchange rate, because we can't know what value we'll get back from the cToken contract. - * @param streamId The id of the compounding stream for which to calculate the interest. - * @param amount The amount of money with respect to which to calculate the interest. - * @return senderInterest recipientInterest sablierInterest The interest accrued by the sender, the recipient and sablier, respectively, as uint256s. - */ - function interestOf(uint256 streamId, uint256 amount) - public - streamExists(streamId) - returns (uint256 senderInterest, uint256 recipientInterest, uint256 sablierInterest) - { - if (!compoundingStreamsVars[streamId].isEntity) { - return (0, 0, 0); - } - Types.Stream memory stream = streams[streamId]; - Types.CompoundingStreamVars memory compoundingStreamVars = compoundingStreamsVars[streamId]; - InterestOfLocalVars memory vars; - - /* - * The exchange rate delta is a key variable, since it leads us to how much interest has been earned - * since the compounding stream was created. - */ - Exp memory exchangeRateCurrent = Exp({ mantissa: ICERC20(stream.tokenAddress).exchangeRateCurrent() }); - if (exchangeRateCurrent.mantissa <= compoundingStreamVars.exchangeRateInitial.mantissa) { - return (0, 0, 0); - } - (vars.mathErr, vars.exchangeRateDelta) = subExp(exchangeRateCurrent, compoundingStreamVars.exchangeRateInitial); - assert(vars.mathErr == MathError.NO_ERROR); - - /* Calculate how much interest has been earned by holding `amount` in the smart contract. */ - (vars.mathErr, vars.underlyingInterest) = mulScalar(vars.exchangeRateDelta, amount); - require(vars.mathErr == MathError.NO_ERROR, "interest calculation error"); - - /* Calculate our share from that interest. */ - if (fee.mantissa == hundredPercent) { - (vars.mathErr, vars.sablierInterest) = divExp(vars.underlyingInterest, exchangeRateCurrent); - require(vars.mathErr == MathError.NO_ERROR, "sablier interest conversion error"); - return (0, 0, truncate(vars.sablierInterest)); - } else if (fee.mantissa == 0) { - vars.sablierUnderlyingInterest = Exp({ mantissa: 0 }); - vars.netUnderlyingInterest = vars.underlyingInterest; - } else { - (vars.mathErr, vars.sablierUnderlyingInterest) = mulExp(vars.underlyingInterest, fee); - require(vars.mathErr == MathError.NO_ERROR, "sablier interest calculation error"); - - /* Calculate how much interest is left for the sender and the recipient. */ - (vars.mathErr, vars.netUnderlyingInterest) = subExp( - vars.underlyingInterest, - vars.sablierUnderlyingInterest - ); - /* - * `subUInt` can only return MathError.INTEGER_UNDERFLOW but we know that `sablierUnderlyingInterest` - * is less or equal than `underlyingInterest`, because we control the value of `fee`. - */ - assert(vars.mathErr == MathError.NO_ERROR); - } - - /* Calculate the sender's share of the interest. */ - (vars.mathErr, vars.senderUnderlyingInterest) = mulExp( - vars.netUnderlyingInterest, - compoundingStreamVars.senderShare - ); - require(vars.mathErr == MathError.NO_ERROR, "sender interest calculation error"); - - /* Calculate the recipient's share of the interest. */ - (vars.mathErr, vars.recipientUnderlyingInterest) = subExp( - vars.netUnderlyingInterest, - vars.senderUnderlyingInterest - ); - /* - * `subUInt` can only return MathError.INTEGER_UNDERFLOW but we know that `senderUnderlyingInterest` - * is less or equal than `netUnderlyingInterest`, because `senderShare` is bounded between 1e16 and 1e18. - */ - assert(vars.mathErr == MathError.NO_ERROR); - - /* Convert the interest to the equivalent cToken denomination. */ - (vars.mathErr, vars.senderInterest) = divExp(vars.senderUnderlyingInterest, exchangeRateCurrent); - require(vars.mathErr == MathError.NO_ERROR, "sender interest conversion error"); - - (vars.mathErr, vars.recipientInterest) = divExp(vars.recipientUnderlyingInterest, exchangeRateCurrent); - require(vars.mathErr == MathError.NO_ERROR, "recipient interest conversion error"); - - (vars.mathErr, vars.sablierInterest) = divExp(vars.sablierUnderlyingInterest, exchangeRateCurrent); - require(vars.mathErr == MathError.NO_ERROR, "sablier interest conversion error"); - - /* Truncating the results means losing everything on the last 1e18 positions of the mantissa */ - return (truncate(vars.senderInterest), truncate(vars.recipientInterest), truncate(vars.sablierInterest)); - } - - /** - * @notice Returns the amount of interest that has been accrued for the given token address. - * @param tokenAddress The address of the token to get the earnings for. - * @return The amount of interest as uint256. - */ - function getEarnings(address tokenAddress) external view returns (uint256) { - return earnings[tokenAddress]; - } - - /*** Public Effects & Interactions Functions ***/ - - struct CreateStreamLocalVars { - MathError mathErr; - uint256 duration; - uint256 ratePerSecond; - } - - /** - * @notice Creates a new stream funded by `msg.sender` and paid towards `recipient`. - * @dev Throws if paused. - * Throws if the recipient is the zero address, the contract itself or the caller. - * Throws if the deposit is 0. - * Throws if the start time is before `block.timestamp`. - * Throws if the stop time is before the start time. - * Throws if the duration calculation has a math error. - * Throws if the deposit is smaller than the duration. - * Throws if the deposit is not a multiple of the duration. - * Throws if the rate calculation has a math error. - * Throws if the next stream id calculation has a math error. - * Throws if the contract is not allowed to transfer enough tokens. - * Throws if there is a token transfer failure. - * @param recipient The address towards which the money is streamed. - * @param deposit The amount of money to be streamed. - * @param tokenAddress The ERC20 token to use as streaming currency. - * @param startTime The unix timestamp for when the stream starts. - * @param stopTime The unix timestamp for when the stream stops. - * @return The uint256 id of the newly created stream. - */ - function createStream(address recipient, uint256 deposit, address tokenAddress, uint256 startTime, uint256 stopTime) - public - override - whenNotPaused - returns (uint256) - { - require(recipient != address(0x00), "stream to the zero address"); - require(recipient != address(this), "stream to the contract itself"); - require(recipient != msg.sender, "stream to the caller"); - require(deposit > 0, "deposit is zero"); - require(startTime >= block.timestamp, "start time before block.timestamp"); - require(stopTime > startTime, "stop time before the start time"); - - CreateStreamLocalVars memory vars; - (vars.mathErr, vars.duration) = subUInt(stopTime, startTime); - /* `subUInt` can only return MathError.INTEGER_UNDERFLOW but we know `stopTime` is higher than `startTime`. */ - assert(vars.mathErr == MathError.NO_ERROR); - - /* Without this, the rate per second would be zero. */ - require(deposit >= vars.duration, "deposit smaller than time delta"); - - /* This condition avoids dealing with remainders */ - require(deposit % vars.duration == 0, "deposit not multiple of time delta"); - - (vars.mathErr, vars.ratePerSecond) = divUInt(deposit, vars.duration); - /* `divUInt` can only return MathError.DIVISION_BY_ZERO but we know `duration` is not zero. */ - assert(vars.mathErr == MathError.NO_ERROR); - - /* Create and store the stream object. */ - uint256 streamId = nextStreamId; - streams[streamId] = Types.Stream({ - remainingBalance: deposit, - deposit: deposit, - isEntity: true, - ratePerSecond: vars.ratePerSecond, - recipient: recipient, - sender: msg.sender, - startTime: startTime, - stopTime: stopTime, - tokenAddress: tokenAddress - }); - - /* Increment the next stream id. */ - (vars.mathErr, nextStreamId) = addUInt(nextStreamId, uint256(1)); - require(vars.mathErr == MathError.NO_ERROR, "next stream id calculation error"); - - require(IERC20(tokenAddress).transferFrom(msg.sender, address(this), deposit), "token transfer failure"); - emit CreateStream(streamId, msg.sender, recipient, deposit, tokenAddress, startTime, stopTime); - return streamId; - } - - struct CreateCompoundingStreamLocalVars { - MathError mathErr; - uint256 shareSum; - uint256 underlyingBalance; - uint256 senderShareMantissa; - uint256 recipientShareMantissa; - } - - /** - * @notice Creates a new compounding stream funded by `msg.sender` and paid towards `recipient`. - * @dev Inherits all security checks from `createStream`. - * Throws if the cToken is not whitelisted. - * Throws if the sender share percentage and the recipient share percentage do not sum up to 100. - * Throws if the the sender share mantissa calculation has a math error. - * Throws if the the recipient share mantissa calculation has a math error. - * @param recipient The address towards which the money is streamed. - * @param deposit The amount of money to be streamed. - * @param tokenAddress The ERC20 token to use as streaming currency. - * @param startTime The unix timestamp for when the stream starts. - * @param stopTime The unix timestamp for when the stream stops. - * @param senderSharePercentage The sender's share of the interest, as a percentage. - * @param recipientSharePercentage The recipient's share of the interest, as a percentage. - * @return The uint256 id of the newly created compounding stream. - */ - function createCompoundingStream( - address recipient, - uint256 deposit, - address tokenAddress, - uint256 startTime, - uint256 stopTime, - uint256 senderSharePercentage, - uint256 recipientSharePercentage - ) external whenNotPaused returns (uint256) { - CreateCompoundingStreamLocalVars memory vars; - - /* Ensure that the interest shares sum up to 100%. */ - (vars.mathErr, vars.shareSum) = addUInt(senderSharePercentage, recipientSharePercentage); - require(vars.mathErr == MathError.NO_ERROR, "share sum calculation error"); - require(vars.shareSum == 100, "shares do not sum up to 100"); - - uint256 streamId = createStream(recipient, deposit, tokenAddress, startTime, stopTime); - - /* - * `senderSharePercentage` and `recipientSharePercentage` will be stored as mantissas, so we scale them up - * by one percent in Exp terms. - */ - (vars.mathErr, vars.senderShareMantissa) = mulUInt(senderSharePercentage, onePercent); - /* - * `mulUInt` can only return MathError.INTEGER_OVERFLOW but we control `onePercent` and - * we know `senderSharePercentage` is maximum 100. - */ - assert(vars.mathErr == MathError.NO_ERROR); - - (vars.mathErr, vars.recipientShareMantissa) = mulUInt(recipientSharePercentage, onePercent); - /* - * `mulUInt` can only return MathError.INTEGER_OVERFLOW but we control `onePercent` and - * we know `recipientSharePercentage` is maximum 100. - */ - assert(vars.mathErr == MathError.NO_ERROR); - - /* Create and store the compounding stream vars. */ - uint256 exchangeRateCurrent = ICERC20(tokenAddress).exchangeRateCurrent(); - compoundingStreamsVars[streamId] = Types.CompoundingStreamVars({ - exchangeRateInitial: Exp({ mantissa: exchangeRateCurrent }), - isEntity: true, - recipientShare: Exp({ mantissa: vars.recipientShareMantissa }), - senderShare: Exp({ mantissa: vars.senderShareMantissa }) - }); - - emit CreateCompoundingStream(streamId, exchangeRateCurrent, senderSharePercentage, recipientSharePercentage); - return streamId; - } - - /** - * @notice Withdraws from the contract to the recipient's account. - * @dev Throws if the id does not point to a valid stream. - * Throws if the caller is not the sender or the recipient of the stream. - * Throws if the amount exceeds the available balance. - * Throws if there is a token transfer failure. - * @param streamId The id of the stream to withdraw tokens from. - * @param amount The amount of tokens to withdraw. - * @return bool true=success, otherwise false. - */ - function withdrawFromStream(uint256 streamId, uint256 amount) - external - override - whenNotPaused - nonReentrant - streamExists(streamId) - onlySenderOrRecipient(streamId) - returns (bool) - { - require(amount > 0, "amount is zero"); - Types.Stream memory stream = streams[streamId]; - uint256 balance = balanceOf(streamId, stream.recipient); - require(balance >= amount, "amount exceeds the available balance"); - - if (!compoundingStreamsVars[streamId].isEntity) { - withdrawFromStreamInternal(streamId, amount); - } else { - withdrawFromCompoundingStreamInternal(streamId, amount); - } - return true; - } - - /** - * @notice Cancels the stream and transfers the tokens back on a pro rata basis. - * @dev Throws if the id does not point to a valid stream. - * Throws if the caller is not the sender or the recipient of the stream. - * Throws if there is a token transfer failure. - * @param streamId The id of the stream to cancel. - * @return bool true=success, otherwise false. - */ - function cancelStream(uint256 streamId) - external - override - nonReentrant - streamExists(streamId) - onlySenderOrRecipient(streamId) - returns (bool) - { - if (!compoundingStreamsVars[streamId].isEntity) { - cancelStreamInternal(streamId); - } else { - cancelCompoundingStreamInternal(streamId); - } - return true; - } - - /*** Internal Effects & Interactions Functions ***/ - - struct WithdrawFromStreamInternalLocalVars { - MathError mathErr; - } - - /** - * @notice Makes the withdrawal to the recipient of the stream. - * @dev If the stream balance has been depleted to 0, the stream object is deleted - * to save gas and optimise contract storage. - * Throws if the stream balance calculation has a math error. - * Throws if there is a token transfer failure. - * @param streamId The id of the stream to withdraw from. - * @param amount Withdraw tokens amount. - */ - function withdrawFromStreamInternal(uint256 streamId, uint256 amount) internal { - Types.Stream memory stream = streams[streamId]; - WithdrawFromStreamInternalLocalVars memory vars; - (vars.mathErr, streams[streamId].remainingBalance) = subUInt(stream.remainingBalance, amount); - /** - * `subUInt` can only return MathError.INTEGER_UNDERFLOW but we know that `remainingBalance` is at least - * as big as `amount`. See the `require` check in `withdrawFromInternal`. - */ - assert(vars.mathErr == MathError.NO_ERROR); - - if (streams[streamId].remainingBalance == 0) delete streams[streamId]; - - require(IERC20(stream.tokenAddress).transfer(stream.recipient, amount), "token transfer failure"); - emit WithdrawFromStream(streamId, stream.recipient, amount); - } - - struct WithdrawFromCompoundingStreamInternalLocalVars { - MathError mathErr; - uint256 amountWithoutSenderInterest; - uint256 netWithdrawalAmount; - } - - /** - * @notice Withdraws to the recipient's account and pays the accrued interest to all parties. - * @dev If the stream balance has been depleted to 0, the stream object to save gas and optimise - * contract storage. - * @param streamId The id of the stream to withdraw from. - * @param amount Withdraw tokens amount. - * Throws if there is a math error. - * Throws if there is a token transfer failure. - */ - function withdrawFromCompoundingStreamInternal(uint256 streamId, uint256 amount) internal { - Types.Stream memory stream = streams[streamId]; - WithdrawFromCompoundingStreamInternalLocalVars memory vars; - - /* Calculate the interest earned by each party for keeping `stream.balance` in the smart contract. */ - (uint256 senderInterest, uint256 recipientInterest, uint256 sablierInterest) = interestOf(streamId, amount); - - /* - * Calculate the net withdrawal amount by subtracting `senderInterest` and `sablierInterest`. - * Because the decimal points are lost when we truncate Exponentials, the recipient will implicitly earn - * `recipientInterest` plus a tiny-weeny amount of interest, max 2e-8 in cToken denomination. - */ - (vars.mathErr, vars.amountWithoutSenderInterest) = subUInt(amount, senderInterest); - require(vars.mathErr == MathError.NO_ERROR, "amount without sender interest calculation error"); - (vars.mathErr, vars.netWithdrawalAmount) = subUInt(vars.amountWithoutSenderInterest, sablierInterest); - require(vars.mathErr == MathError.NO_ERROR, "net withdrawal amount calculation error"); - - /* Subtract `amount` from the remaining balance of the stream. */ - (vars.mathErr, streams[streamId].remainingBalance) = subUInt(stream.remainingBalance, amount); - require(vars.mathErr == MathError.NO_ERROR, "balance subtraction calculation error"); - - /* Delete the objects from storage if the remaining balance has been depleted to 0. */ - if (streams[streamId].remainingBalance == 0) { - delete streams[streamId]; - delete compoundingStreamsVars[streamId]; - } - - /* Add the sablier interest to the earnings for this cToken. */ - (vars.mathErr, earnings[stream.tokenAddress]) = addUInt(earnings[stream.tokenAddress], sablierInterest); - require(vars.mathErr == MathError.NO_ERROR, "earnings addition calculation error"); - - /* Transfer the tokens to the sender and the recipient. */ - ICERC20 cToken = ICERC20(stream.tokenAddress); - if (senderInterest > 0) - require(cToken.transfer(stream.sender, senderInterest), "sender token transfer failure"); - require(cToken.transfer(stream.recipient, vars.netWithdrawalAmount), "recipient token transfer failure"); - - emit WithdrawFromStream(streamId, stream.recipient, vars.netWithdrawalAmount); - emit PayInterest(streamId, senderInterest, recipientInterest, sablierInterest); - } - - /** - * @notice Cancels the stream and transfers the tokens back on a pro rata basis. - * @dev The stream and compounding stream vars objects get deleted to save gas - * and optimise contract storage. - * Throws if there is a token transfer failure. - * @param streamId The id of the stream to cancel. - */ - function cancelStreamInternal(uint256 streamId) internal { - Types.Stream memory stream = streams[streamId]; - uint256 senderBalance = balanceOf(streamId, stream.sender); - uint256 recipientBalance = balanceOf(streamId, stream.recipient); - - delete streams[streamId]; - - IERC20 token = IERC20(stream.tokenAddress); - if (recipientBalance > 0) - require(token.transfer(stream.recipient, recipientBalance), "recipient token transfer failure"); - if (senderBalance > 0) require(token.transfer(stream.sender, senderBalance), "sender token transfer failure"); - - emit CancelStream(streamId, stream.sender, stream.recipient, senderBalance, recipientBalance); - } - - struct CancelCompoundingStreamInternal { - MathError mathErr; - uint256 netSenderBalance; - uint256 recipientBalanceWithoutSenderInterest; - uint256 netRecipientBalance; - } - - /** - * @notice Cancels the stream, transfers the tokens back on a pro rata basis and pays the accrued - * interest to all parties. - * @dev Importantly, the money that has not been streamed yet is not considered chargeable. - * All the interest generated by that underlying will be returned to the sender. - * Throws if there is a math error. - * Throws if there is a token transfer failure. - * @param streamId The id of the stream to cancel. - */ - function cancelCompoundingStreamInternal(uint256 streamId) internal { - Types.Stream memory stream = streams[streamId]; - CancelCompoundingStreamInternal memory vars; - - /* - * The sender gets back all the money that has not been streamed so far. By that, we mean both - * the underlying amount and the interest generated by it. - */ - uint256 senderBalance = balanceOf(streamId, stream.sender); - uint256 recipientBalance = balanceOf(streamId, stream.recipient); - - /* Calculate the interest earned by each party for keeping `recipientBalance` in the smart contract. */ - (uint256 senderInterest, uint256 recipientInterest, uint256 sablierInterest) = interestOf( - streamId, - recipientBalance - ); - - /* - * We add `senderInterest` to `senderBalance` to calculate the net balance for the sender. - * After this, the rest of the function is similar to `withdrawFromCompoundingStreamInternal`, except - * we add the sender's share of the interest generated by `recipientBalance` to `senderBalance`. - */ - (vars.mathErr, vars.netSenderBalance) = addUInt(senderBalance, senderInterest); - require(vars.mathErr == MathError.NO_ERROR, "net sender balance calculation error"); - - /* - * Calculate the net withdrawal amount by subtracting `senderInterest` and `sablierInterest`. - * Because the decimal points are lost when we truncate Exponentials, the recipient will implicitly earn - * `recipientInterest` plus a tiny-weeny amount of interest, max 2e-8 in cToken denomination. - */ - (vars.mathErr, vars.recipientBalanceWithoutSenderInterest) = subUInt(recipientBalance, senderInterest); - require(vars.mathErr == MathError.NO_ERROR, "recipient balance without sender interest calculation error"); - (vars.mathErr, vars.netRecipientBalance) = subUInt(vars.recipientBalanceWithoutSenderInterest, sablierInterest); - require(vars.mathErr == MathError.NO_ERROR, "net recipient balance calculation error"); - - /* Add the sablier interest to the earnings attributed to this cToken. */ - (vars.mathErr, earnings[stream.tokenAddress]) = addUInt(earnings[stream.tokenAddress], sablierInterest); - require(vars.mathErr == MathError.NO_ERROR, "earnings addition calculation error"); - - /* Delete the objects from storage. */ - delete streams[streamId]; - delete compoundingStreamsVars[streamId]; - - /* Transfer the tokens to the sender and the recipient. */ - IERC20 token = IERC20(stream.tokenAddress); - if (vars.netSenderBalance > 0) - require(token.transfer(stream.sender, vars.netSenderBalance), "sender token transfer failure"); - if (vars.netRecipientBalance > 0) - require(token.transfer(stream.recipient, vars.netRecipientBalance), "recipient token transfer failure"); - - emit CancelStream(streamId, stream.sender, stream.recipient, vars.netSenderBalance, vars.netRecipientBalance); - emit PayInterest(streamId, senderInterest, recipientInterest, sablierInterest); - } - - - - /*** UTILS ***/ - - /** - * @notice Get token decimals given a stream id. - * @dev This is an utility function for DApp layer when converting to float numbers. - * @param streamId The id of the stream. - */ - function getTokenDecimalsFromStream(uint256 streamId) - external - streamExists(streamId) - returns (uint8) - { - Types.Stream memory stream = streams[streamId]; - return IERC20View(stream.tokenAddress).decimals(); - } - - /** - * @notice Get token decimals given token address. - * @dev This is an utility function for DApp layer when converting to float numbers. - * @param tokenAddress The token address. - */ - function getTokenDecimals(address tokenAddress) - external - returns (uint8) - { - return IERC20View(tokenAddress).decimals(); - } -} diff --git a/contracts/sablier/protocol/Types.sol b/contracts/sablier/protocol/Types.sol deleted file mode 100644 index af0d6a9d..00000000 --- a/contracts/sablier/protocol/Types.sol +++ /dev/null @@ -1,28 +0,0 @@ -pragma solidity >=0.6.0; - -import "../shared-contracts/compound/Exponential.sol"; - -/** - * @title Sablier Types - * @author Sablier - */ -library Types { - struct Stream { - uint256 deposit; - uint256 ratePerSecond; - uint256 remainingBalance; - uint256 startTime; - uint256 stopTime; - address recipient; - address sender; - address tokenAddress; - bool isEntity; - } - - struct CompoundingStreamVars { - Exponential.Exp exchangeRateInitial; - Exponential.Exp senderShare; - Exponential.Exp recipientShare; - bool isEntity; - } -} diff --git a/contracts/sablier/protocol/interfaces/ICTokenManager.sol b/contracts/sablier/protocol/interfaces/ICTokenManager.sol deleted file mode 100644 index 685d0758..00000000 --- a/contracts/sablier/protocol/interfaces/ICTokenManager.sol +++ /dev/null @@ -1,23 +0,0 @@ -pragma solidity >=0.6.0; - -/** - * @title CTokenManager Interface - * @author Sablier - */ -interface ICTokenManager { - /** - * @notice Emits when the owner discards a cToken. - */ - event DiscardCToken(address indexed tokenAddress); - - /** - * @notice Emits when the owner whitelists a cToken. - */ - event WhitelistCToken(address indexed tokenAddress); - - function whitelistCToken(address tokenAddress) external; - - function discardCToken(address tokenAddress) external; - - function isCToken(address tokenAddress) external view returns (bool); -} diff --git a/contracts/sablier/protocol/interfaces/IERC1620.sol b/contracts/sablier/protocol/interfaces/IERC1620.sol deleted file mode 100644 index 61e7a8d8..00000000 --- a/contracts/sablier/protocol/interfaces/IERC1620.sol +++ /dev/null @@ -1,61 +0,0 @@ -pragma solidity >=0.6.0; - -/** - * @title ERC-1620 Money Streaming Standard - * @author Sablier - * @dev See https://eips.ethereum.org/EIPS/eip-1620 - */ -interface IERC1620 { - /** - * @notice Emits when a stream is successfully created. - */ - event CreateStream( - uint256 indexed streamId, - address indexed sender, - address indexed recipient, - uint256 deposit, - address tokenAddress, - uint256 startTime, - uint256 stopTime - ); - - /** - * @notice Emits when the recipient of a stream withdraws a portion or all their pro rata share of the stream. - */ - event WithdrawFromStream(uint256 indexed streamId, address indexed recipient, uint256 amount); - - /** - * @notice Emits when a stream is successfully cancelled and tokens are transferred back on a pro rata basis. - */ - event CancelStream( - uint256 indexed streamId, - address indexed sender, - address indexed recipient, - uint256 senderBalance, - uint256 recipientBalance - ); - - function balanceOf(uint256 streamId, address who) external view returns (uint256 balance); - - function getStream(uint256 streamId) - external - view - returns ( - address sender, - address recipient, - uint256 deposit, - address token, - uint256 startTime, - uint256 stopTime, - uint256 remainingBalance, - uint256 ratePerSecond - ); - - function createStream(address recipient, uint256 deposit, address tokenAddress, uint256 startTime, uint256 stopTime) - external - returns (uint256 streamId); - - function withdrawFromStream(uint256 streamId, uint256 funds) external returns (bool); - - function cancelStream(uint256 streamId) external returns (bool); -} diff --git a/contracts/sablier/shared-contracts/ERC20Base.sol b/contracts/sablier/shared-contracts/ERC20Base.sol deleted file mode 100644 index 03de3b00..00000000 --- a/contracts/sablier/shared-contracts/ERC20Base.sol +++ /dev/null @@ -1,193 +0,0 @@ -pragma solidity >=0.6.0; - -import "@openzeppelin/contracts/GSN/Context.sol"; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/math/SafeMath.sol"; - -/** - * @title Standard ERC20 token - * - * @dev Implementation of the basic standard token. - * https://eips.ethereum.org/EIPS/eip-20 - * Originally based on code by FirstBlood: - * https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol - * - * This implementation emits additional Approval events, allowing applications to reconstruct the allowance status for - * all accounts just by listening to said events. Note that this isn't required by the specification, and other - * compliant implementations may not do it. - */ -contract ERC20Base is Context, IERC20 { - using SafeMath for uint256; - - mapping (address => uint256) private _balances; - - mapping (address => mapping (address => uint256)) private _allowances; - - uint256 private _totalSupply; - - /** - * @dev Total number of tokens in existence - */ - function totalSupply() public view override returns (uint256) { - return _totalSupply; - } - - /** - * @dev Gets the balance of the specified address. - * @param owner The address to query the balance of. - * @return A uint256 representing the amount owned by the passed address. - */ - function balanceOf(address owner) public view override returns (uint256) { - return _balances[owner]; - } - - /** - * @dev Function to check the amount of tokens that an owner allowed to a spender. - * @param owner address The address which owns the funds. - * @param spender address The address which will spend the funds. - * @return A uint256 specifying the amount of tokens still available for the spender. - */ - function allowance(address owner, address spender) public view override returns (uint256) { - return _allowances[owner][spender]; - } - - /** - * @dev Transfer token to a specified address - * @param to The address to transfer to. - * @param value The amount to be transferred. - */ - function transfer(address to, uint256 value) public override returns (bool) { - _transfer(_msgSender(), to, value); - return true; - } - - /** - * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. - * Beware that changing an allowance with this method brings the risk that someone may use both the old - * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this - * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: - * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 - * @param spender The address which will spend the funds. - * @param value The amount of tokens to be spent. - */ - function approve(address spender, uint256 value) public override returns (bool) { - _approve(_msgSender(), spender, value); - return true; - } - - /** - * @dev Transfer tokens from one address to another. - * Note that while this function emits an Approval event, this is not required as per the specification, - * and other compliant implementations may not emit the event. - * @param from address The address which you want to send tokens from - * @param to address The address which you want to transfer to - * @param value uint256 the amount of tokens to be transferred - */ - function transferFrom(address from, address to, uint256 value) public override returns (bool) { - _transfer(from, to, value); - _approve(from, _msgSender(), _allowances[from][_msgSender()].sub(value)); - return true; - } - - /** - * @dev Increase the amount of tokens that an owner allowed to a spender. - * approve should be called when _allowances[msg.sender][spender] == 0. To increment - * allowed value is better to use this function to avoid 2 calls (and wait until - * the first transaction is mined) - * From MonolithDAO Token.sol - * Emits an Approval event. - * @param spender The address which will spend the funds. - * @param addedValue The amount of tokens to increase the allowance by. - */ - function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { - _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); - return true; - } - - /** - * @dev Decrease the amount of tokens that an owner allowed to a spender. - * approve should be called when _allowances[msg.sender][spender] == 0. To decrement - * allowed value is better to use this function to avoid 2 calls (and wait until - * the first transaction is mined) - * From MonolithDAO Token.sol - * Emits an Approval event. - * @param spender The address which will spend the funds. - * @param subtractedValue The amount of tokens to decrease the allowance by. - */ - function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { - _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue)); - return true; - } - - /** - * @dev Transfer token for a specified addresses - * @param from The address to transfer from. - * @param to The address to transfer to. - * @param value The amount to be transferred. - */ - function _transfer(address from, address to, uint256 value) internal { - require(to != address(0)); - - _balances[from] = _balances[from].sub(value); - _balances[to] = _balances[to].add(value); - emit Transfer(from, to, value); - } - - /** - * @dev Internal function that mints an amount of the token and assigns it to - * an account. This encapsulates the modification of balances such that the - * proper events are emitted. - * @param account The account that will receive the created tokens. - * @param value The amount that will be created. - */ - function _mint(address account, uint256 value) internal { - require(account != address(0)); - - _totalSupply = _totalSupply.add(value); - _balances[account] = _balances[account].add(value); - emit Transfer(address(0), account, value); - } - - /** - * @dev Internal function that burns an amount of the token of a given - * account. - * @param account The account whose tokens will be burnt. - * @param value The amount that will be burnt. - */ - function _burn(address account, uint256 value) internal { - require(account != address(0)); - - _totalSupply = _totalSupply.sub(value); - _balances[account] = _balances[account].sub(value); - emit Transfer(account, address(0), value); - } - - /** - * @dev Approve an address to spend another addresses' tokens. - * @param owner The address that owns the tokens. - * @param spender The address that will spend the tokens. - * @param value The number of tokens that can be spent. - */ - function _approve(address owner, address spender, uint256 value) internal { - require(spender != address(0)); - require(owner != address(0)); - - _allowances[owner][spender] = value; - emit Approval(owner, spender, value); - } - - /** - * @dev Internal function that burns an amount of the token of a given - * account, deducting from the sender's allowance for said account. Uses the - * internal burn function. - * Emits an Approval event (reflecting the reduced allowance). - * @param account The account whose tokens will be burnt. - * @param amount The amount that will be burnt. - */ - function _burnFrom(address account, uint256 amount) internal { - _burn(account, amount); - _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount)); - } - - uint256[50] private ______gap; -} diff --git a/contracts/sablier/shared-contracts/compound/CarefulMath.sol b/contracts/sablier/shared-contracts/compound/CarefulMath.sol deleted file mode 100644 index 1d22b1a3..00000000 --- a/contracts/sablier/shared-contracts/compound/CarefulMath.sol +++ /dev/null @@ -1,85 +0,0 @@ -pragma solidity >=0.6.0; - -/** - * @title Careful Math - * @author Compound - * @notice Derived from OpenZeppelin's SafeMath library - * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol - */ -contract CarefulMath { - - /** - * @dev Possible error codes that we can return - */ - enum MathError { - NO_ERROR, - DIVISION_BY_ZERO, - INTEGER_OVERFLOW, - INTEGER_UNDERFLOW - } - - /** - * @dev Multiplies two numbers, returns an error on overflow. - */ - function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (a == 0) { - return (MathError.NO_ERROR, 0); - } - - uint c = a * b; - - if (c / a != b) { - return (MathError.INTEGER_OVERFLOW, 0); - } else { - return (MathError.NO_ERROR, c); - } - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function divUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b == 0) { - return (MathError.DIVISION_BY_ZERO, 0); - } - - return (MathError.NO_ERROR, a / b); - } - - /** - * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). - */ - function subUInt(uint a, uint b) internal pure returns (MathError, uint) { - if (b <= a) { - return (MathError.NO_ERROR, a - b); - } else { - return (MathError.INTEGER_UNDERFLOW, 0); - } - } - - /** - * @dev Adds two numbers, returns an error on overflow. - */ - function addUInt(uint a, uint b) internal pure returns (MathError, uint) { - uint c = a + b; - - if (c >= a) { - return (MathError.NO_ERROR, c); - } else { - return (MathError.INTEGER_OVERFLOW, 0); - } - } - - /** - * @dev add a and b and then subtract c - */ - function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { - (MathError err0, uint sum) = addUInt(a, b); - - if (err0 != MathError.NO_ERROR) { - return (err0, 0); - } - - return subUInt(sum, c); - } -} diff --git a/contracts/sablier/shared-contracts/compound/EIP20Interface.sol b/contracts/sablier/shared-contracts/compound/EIP20Interface.sol deleted file mode 100644 index 460705c4..00000000 --- a/contracts/sablier/shared-contracts/compound/EIP20Interface.sol +++ /dev/null @@ -1,59 +0,0 @@ -pragma solidity >=0.6.0; - -/** - * @title ERC 20 Token Standard Interface - * https://eips.ethereum.org/EIPS/eip-20 - */ -interface EIP20Interface { - - /** - * @notice Get the total number of tokens in circulation - * @return The supply of tokens - */ - function totalSupply() external view returns (uint256); - - /** - * @notice Gets the balance of the specified address - * @param owner The address from which the balance will be retrieved - * @return balance The balance - */ - function balanceOf(address owner) external view returns (uint256 balance); - - /** - * @notice Transfer `amount` tokens from `msg.sender` to `dst` - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transfer(address dst, uint256 amount) external returns (bool success); - - /** - * @notice Transfer `amount` tokens from `src` to `dst` - * @param src The address of the source account - * @param dst The address of the destination account - * @param amount The number of tokens to transfer - * @return success Whether or not the transfer succeeded - */ - function transferFrom(address src, address dst, uint256 amount) external returns (bool success); - - /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return success Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) external returns (bool success); - - /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return remaining The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) external view returns (uint256 remaining); - - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval(address indexed owner, address indexed spender, uint256 amount); -} diff --git a/contracts/sablier/shared-contracts/compound/Exponential.sol b/contracts/sablier/shared-contracts/compound/Exponential.sol deleted file mode 100644 index a190f196..00000000 --- a/contracts/sablier/shared-contracts/compound/Exponential.sol +++ /dev/null @@ -1,226 +0,0 @@ -pragma solidity >=0.6.0; - -import "./CarefulMath.sol"; - -/** - * @title Exponential module for storing fixed-decision decimals - * @author Compound - * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. - * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: - * `Exp({mantissa: 5100000000000000000})`. - */ -contract Exponential is CarefulMath { - uint constant expScale = 1e18; - uint constant halfExpScale = expScale/2; - uint constant mantissaOne = expScale; - - struct Exp { - uint mantissa; - } - - /** - * @dev Creates an exponential from numerator and denominator values. - * Note: Returns an error if (`num` * 10e18) > MAX_INT, - * or if `denom` is zero. - */ - function getExp(uint num, uint denom) pure internal returns (MathError, Exp memory) { - (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - (MathError err1, uint rational) = divUInt(scaledNumerator, denom); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: rational})); - } - - /** - * @dev Adds two exponentials, returning a new exponential. - */ - function addExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) { - (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Subtracts two exponentials, returning a new exponential. - */ - function subExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) { - (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); - - return (error, Exp({mantissa: result})); - } - - /** - * @dev Multiply an Exp by a scalar, returning a new Exp. - */ - function mulScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) { - (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); - } - - /** - * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. - */ - function mulScalarTruncate(Exp memory a, uint scalar) pure internal returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(product)); - } - - /** - * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. - */ - function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (MathError, uint) { - (MathError err, Exp memory product) = mulScalar(a, scalar); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return addUInt(truncate(product), addend); - } - - /** - * @dev Divide an Exp by a scalar, returning a new Exp. - */ - function divScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) { - (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); - } - - /** - * @dev Divide a scalar by an Exp, returning a new Exp. - */ - function divScalarByExp(uint scalar, Exp memory divisor) pure internal returns (MathError, Exp memory) { - /* - We are doing this as: - getExp(mulUInt(expScale, scalar), divisor.mantissa) - - How it works: - Exp = a / b; - Scalar = s; - `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` - */ - (MathError err0, uint numerator) = mulUInt(expScale, scalar); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - return getExp(numerator, divisor.mantissa); - } - - /** - * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. - */ - function divScalarByExpTruncate(uint scalar, Exp memory divisor) pure internal returns (MathError, uint) { - (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); - if (err != MathError.NO_ERROR) { - return (err, 0); - } - - return (MathError.NO_ERROR, truncate(fraction)); - } - - /** - * @dev Multiplies two exponentials, returning a new exponential. - */ - function mulExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) { - - (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); - if (err0 != MathError.NO_ERROR) { - return (err0, Exp({mantissa: 0})); - } - - // We add half the scale before dividing so that we get rounding instead of truncation. - // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 - // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. - (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); - if (err1 != MathError.NO_ERROR) { - return (err1, Exp({mantissa: 0})); - } - - (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); - // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. - assert(err2 == MathError.NO_ERROR); - - return (MathError.NO_ERROR, Exp({mantissa: product})); - } - - /** - * @dev Multiplies two exponentials given their mantissas, returning a new exponential. - */ - function mulExp(uint a, uint b) pure internal returns (MathError, Exp memory) { - return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); - } - - /** - * @dev Multiplies three exponentials, returning a new exponential. - */ - function mulExp3(Exp memory a, Exp memory b, Exp memory c) pure internal returns (MathError, Exp memory) { - (MathError err, Exp memory ab) = mulExp(a, b); - if (err != MathError.NO_ERROR) { - return (err, ab); - } - return mulExp(ab, c); - } - - /** - * @dev Divides two exponentials, returning a new exponential. - * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, - * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) - */ - function divExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) { - return getExp(a.mantissa, b.mantissa); - } - - /** - * @dev Truncates the given exp to a whole number value. - * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 - */ - function truncate(Exp memory exp) pure internal returns (uint) { - // Note: We are not using careful math here as we're performing a division that cannot fail - return exp.mantissa / expScale; - } - - /** - * @dev Checks if first Exp is less than second Exp. - */ - function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa < right.mantissa; //TODO: Add some simple tests and this in another PR yo. - } - - /** - * @dev Checks if left Exp <= right Exp. - */ - function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa <= right.mantissa; - } - - /** - * @dev Checks if left Exp > right Exp. - */ - function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { - return left.mantissa > right.mantissa; - } - - /** - * @dev returns true if Exp is exactly zero - */ - function isZeroExp(Exp memory value) pure internal returns (bool) { - return value.mantissa == 0; - } -} diff --git a/contracts/sablier/shared-contracts/interfaces/ICERC20.sol b/contracts/sablier/shared-contracts/interfaces/ICERC20.sol deleted file mode 100644 index eb7d1aca..00000000 --- a/contracts/sablier/shared-contracts/interfaces/ICERC20.sol +++ /dev/null @@ -1,28 +0,0 @@ -pragma solidity >=0.6.0; - -/** - * @title CERC20 interface - * @author Sablier - * @dev See https://compound.finance/developers - */ -interface ICERC20 { - function balanceOf(address who) external view returns (uint256); - - function isCToken() external view returns (bool); - - function approve(address spender, uint256 value) external returns (bool); - - function balanceOfUnderlying(address account) external returns (uint256); - - function exchangeRateCurrent() external returns (uint256); - - function mint(uint256 mintAmount) external returns (uint256); - - function redeem(uint256 redeemTokens) external returns (uint256); - - function redeemUnderlying(uint256 redeemAmount) external returns (uint256); - - function transfer(address recipient, uint256 amount) external returns (bool); - - function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); -} diff --git a/contracts/sablier/shared-contracts/lifecycle/OwnableWithoutRenounce.sol b/contracts/sablier/shared-contracts/lifecycle/OwnableWithoutRenounce.sol deleted file mode 100644 index bd293560..00000000 --- a/contracts/sablier/shared-contracts/lifecycle/OwnableWithoutRenounce.sol +++ /dev/null @@ -1,71 +0,0 @@ -pragma solidity >=0.6.0; - -import "@openzeppelin/contracts/GSN/Context.sol"; -import "@openzeppelin/contracts/proxy/Initializable.sol"; - -/** - * @title OwnableWithoutRenounce - * @author Sablier - * @dev Fork of OpenZeppelin's Ownable contract, which provides basic authorization control, but with - * the `renounceOwnership` function removed to avoid fat-finger errors. - * We inherit from `Context` to keep this contract compatible with the Gas Station Network. - * See https://github.com/OpenZeppelin/openzeppelin-contracts-ethereum-package/blob/master/contracts/ownership/Ownable.sol - * See https://forum.openzeppelin.com/t/contract-request-ownable-without-renounceownership/1400 - * See https://docs.openzeppelin.com/contracts/2.x/gsn#_msg_sender_and_msg_data - */ -contract OwnableWithoutRenounce is Initializable, Context { - address private _owner; - - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); - - /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function initialize(address sender) public initializer { - _owner = sender; - emit OwnershipTransferred(address(0), _owner); - } - - /** - * @return the address of the owner. - */ - function owner() public view returns (address) { - return _owner; - } - - /** - * @dev Throws if called by any account other than the owner. - */ - modifier onlyOwner() { - require(isOwner()); - _; - } - - /** - * @return true if `msg.sender` is the owner of the contract. - */ - function isOwner() public view returns (bool) { - return _msgSender() == _owner; - } - - /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ - function transferOwnership(address newOwner) public onlyOwner { - _transferOwnership(newOwner); - } - - /** - * @dev Transfers control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ - function _transferOwnership(address newOwner) internal { - require(newOwner != address(0)); - emit OwnershipTransferred(_owner, newOwner); - _owner = newOwner; - } - - uint256[50] private ______gap; -} diff --git a/contracts/sablier/shared-contracts/mocks/CERC20Mock.sol b/contracts/sablier/shared-contracts/mocks/CERC20Mock.sol deleted file mode 100644 index 4e2dce7a..00000000 --- a/contracts/sablier/shared-contracts/mocks/CERC20Mock.sol +++ /dev/null @@ -1,116 +0,0 @@ -pragma solidity >=0.6.0; - -import "@openzeppelin/contracts/math/SafeMath.sol"; -import "../ERC20Base.sol"; -import "../compound/EIP20Interface.sol"; - -/** - * @title CERC20 Mock - * @author Sablier - * @dev See https://compound.finance/developers - * based on Sablier's CERC20 Mock - */ -contract CERC20Mock is ERC20Base { - using SafeMath for uint256; - - /** - * @notice Indicator that this is a CToken contract (for inspection) - */ - bool public constant isCToken = true; - - /** - * @notice Block number that interest started to increase from - */ - uint256 public initialBlockNumber; - - /** - * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0) - */ - uint256 public initialExchangeRate; - - /** - * @notice Underlying asset for this CToken - */ - address public underlying; - - /** - * @notice EIP-20 token decimals for this token - */ - uint256 public decimals; - - /** - * @notice Construct a new money market - * @param underlying_ The address of the underlying asset - * @param initialExchangeRate_ The initial exchange rate, scaled by 1e18 - * @param decimals_ ERC-20 decimal precision of this token - */ - constructor(address underlying_, uint256 initialExchangeRate_, uint256 decimals_) public { - initialBlockNumber = block.number; - underlying = underlying_; - initialExchangeRate = initialExchangeRate_; - decimals = decimals_; - EIP20Interface(underlying).totalSupply(); // Sanity check the underlying - } - - /*** User Interface ***/ - - /** - * @notice Get the underlying balance of the `owner` - * @dev This also accrues interest in a transaction - * @param owner The address of the account to query - * @return The amount of underlying owned by `owner` - */ - function balanceOfUnderlying(address owner) public view returns (uint256) { - uint256 underlyingBalance = EIP20Interface(underlying).balanceOf(address(this)); - if (balanceOf(owner) == 0) return 0; - return (totalSupply().mul(1e18).div(balanceOf(owner))).mul(underlyingBalance).div(1e18); - } - - /** - * @notice Accrue interest then return the up-to-date exchange rate - * @return Calculated exchange rate scaled by 1e18 - */ - function exchangeRateCurrent() public view returns (uint256) { - uint256 totalUnderlying = EIP20Interface(underlying).balanceOf(address(this)); - uint256 tokenValueExp = initialExchangeRate; - if (totalSupply() > 0 && totalUnderlying > 0) { - totalUnderlying = totalUnderlying.mul(1e18); - tokenValueExp = totalUnderlying.div(totalSupply()); - } - return tokenValueExp; - } - - /** - * @notice Sender supplies assets into the market and receives cTokens in exchange - * @dev Accrues interest whether or not the operation succeeds, unless reverted - * @param mintAmount The amount of the underlying asset to supply - * @return true=success, otherwise a failure - */ - function mint(uint256 mintAmount) external returns (bool) { - uint256 mintedTokens = (mintAmount.mul(1e18)).div(exchangeRateCurrent()); - _mint(msg.sender, mintedTokens); - return EIP20Interface(underlying).transferFrom(msg.sender, address(this), mintAmount); - } - - /** - * @notice Sender supplies underlying to the money market - * @dev This is just a mock - * @param supplyAmount The amount of underlying to supply - * @return true=success, otherwise a failure - */ - function supplyUnderlying(uint256 supplyAmount) external returns (bool) { - return EIP20Interface(underlying).transferFrom(msg.sender, address(this), supplyAmount); - } - - /** - * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset - * @dev This is just a mock - * @param redeemAmount The amount of underlying to redeem - * @return true=success, otherwise a failure - */ - function redeemUnderlying(uint256 redeemAmount) external returns (bool) { - uint256 redeemTokens = redeemAmount.mul(1e18).div(exchangeRateCurrent()); - _burn(msg.sender, redeemTokens); - return EIP20Interface(underlying).transfer(msg.sender, redeemAmount); - } -} diff --git a/contracts/sablier/shared-contracts/test/EvilERC20.sol b/contracts/sablier/shared-contracts/test/EvilERC20.sol deleted file mode 100644 index e33b8db7..00000000 --- a/contracts/sablier/shared-contracts/test/EvilERC20.sol +++ /dev/null @@ -1,58 +0,0 @@ -pragma solidity >=0.6.0; - -import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; - -/// @dev Mock class using ERC20 -/// @author Sablier - -contract EvilERC20 is ERC20 { - bool shouldDisableTransfer; - bool shouldDisableTransferFrom; - - constructor() public ERC20("EvilERC20", "evilerc20") { - shouldDisableTransfer = false; - shouldDisableTransferFrom = false; - } - - function setShouldDisableTransfer(bool value) external { - shouldDisableTransfer = value; - } - - function setShouldDisableTransferFrom(bool value) external { - shouldDisableTransferFrom = value; - } - - /** - * @dev Transfers token to a specified address, unless `shouldDisableTransfer` is `true`. - * @param to The address to transfer to. - * @param value The amount to be transferred. - */ - function transfer(address to, uint256 value) public override returns (bool) { - if (shouldDisableTransfer) { - return false; - } - return super.transfer(to, value); - } - - /** - * @dev Transfer tokens from one address to another unless `shouldDisableTransferFrom` is `true`. - * @param from address The address which you want to send tokens from - * @param to address The address which you want to transfer to - * @param value uint256 the amount of tokens to be transferred - */ - function transferFrom(address from, address to, uint256 value) public override returns (bool) { - if (shouldDisableTransferFrom) { - return false; - } - return super.transferFrom(from, to, value); - } - - /** - * @dev Allows anyone to mint tokens to any address - * @param to The address that will receive the minted tokens. - * @param amount The amount of tokens to mint. - */ - function mint(address to, uint256 amount) public { - _mint(to, amount); - } -} diff --git a/contracts/sablier/shared-contracts/test/NonStandardERC20.sol b/contracts/sablier/shared-contracts/test/NonStandardERC20.sol deleted file mode 100644 index c8641538..00000000 --- a/contracts/sablier/shared-contracts/test/NonStandardERC20.sol +++ /dev/null @@ -1,102 +0,0 @@ -pragma solidity >=0.6.0; - -import "@openzeppelin/contracts/math/SafeMath.sol"; - -/** - * @title Non Standard ERC20 - * @dev Forked from OpenZeppelin's ERC20 - * @author Sablier - */ - -contract NonStandardERC20 { - using SafeMath for uint256; - - mapping(address => uint256) private _balances; - - mapping(address => mapping(address => uint256)) private _allowances; - - uint256 private _totalSupply; - - event NonStandardTransfer(address indexed from, address indexed to, uint256 value); - - event NonStandardApproval(address indexed owner, address indexed spender, uint256 value); - - function nonStandardTotalSupply() public view returns (uint256) { - return _totalSupply; - } - - function nonStandardBalanceOf(address account) public view returns (uint256) { - return _balances[account]; - } - - function nonStandardTransfer(address recipient, uint256 amount) public returns (bool) { - _transfer(msg.sender, recipient, amount); - return true; - } - - function nonStandardAllowance(address owner, address spender) public view returns (uint256) { - return _allowances[owner][spender]; - } - function nonStandardApprove(address spender, uint256 value) public returns (bool) { - _approve(msg.sender, spender, value); - return true; - } - - function nonStandardTransferFrom(address sender, address recipient, uint256 amount) public returns (bool) { - _transfer(sender, recipient, amount); - _approve(sender, msg.sender, _allowances[sender][msg.sender].sub(amount)); - return true; - } - - function nonStandardIncreaseAllowance(address spender, uint256 addedValue) public returns (bool) { - _approve(msg.sender, spender, _allowances[msg.sender][spender].add(addedValue)); - return true; - } - - function nonStandardDecreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { - _approve(msg.sender, spender, _allowances[msg.sender][spender].sub(subtractedValue)); - return true; - } - - function nonStandardMint(address account, uint256 amount) public { - _mint(account, amount); - } - - function _transfer(address sender, address recipient, uint256 amount) internal { - require(sender != address(0), "ERC20: nonStandardTransfer from the zero address"); - require(recipient != address(0), "ERC20: nonStandardTransfer to the zero address"); - - _balances[sender] = _balances[sender].sub(amount); - _balances[recipient] = _balances[recipient].add(amount); - emit NonStandardTransfer(sender, recipient, amount); - } - - function _mint(address account, uint256 amount) internal { - require(account != address(0), "ERC20: mint to the zero address"); - - _totalSupply = _totalSupply.add(amount); - _balances[account] = _balances[account].add(amount); - emit NonStandardTransfer(address(0), account, amount); - } - - function _burn(address account, uint256 value) internal { - require(account != address(0), "ERC20: burn from the zero address"); - - _totalSupply = _totalSupply.sub(value); - _balances[account] = _balances[account].sub(value); - emit NonStandardTransfer(account, address(0), value); - } - - function _approve(address owner, address spender, uint256 value) internal { - require(owner != address(0), "ERC20: nonStandardApprove from the zero address"); - require(spender != address(0), "ERC20: nonStandardApprove to the zero address"); - - _allowances[owner][spender] = value; - emit NonStandardApproval(owner, spender, value); - } - - function _burnFrom(address account, uint256 amount) internal { - _burn(account, amount); - _approve(account, msg.sender, _allowances[account][msg.sender].sub(amount)); - } -} diff --git a/src/index.js b/src/index.js index 7a539a90..5e5db892 100644 --- a/src/index.js +++ b/src/index.js @@ -8,7 +8,6 @@ import ERC721Collectibles from './models/ERC721/ERC721Collectibles'; import ERC721Standard from './models/ERC721/ERC721Standard'; import Network from './models/BEPRO/Network'; import { VotingContract } from './models'; -import Sablier from './models/Sablier/Sablier'; import ETHUtils from './utils/ETHUtils'; import UniswapV3Pool from './models/Uniswap/UniswapV3Pool'; import UniswapV3Factory from './models/Uniswap/UniswapV3Factory'; @@ -30,7 +29,6 @@ export { ERC20TokenLock, ERC721Collectibles, ERC721Standard, - Sablier, ETHUtils, UniswapV3Pool, UniswapV3Factory, diff --git a/src/models/Sablier/Sablier.js b/src/models/Sablier/Sablier.js deleted file mode 100644 index 7c6cf52c..00000000 --- a/src/models/Sablier/Sablier.js +++ /dev/null @@ -1,440 +0,0 @@ -import { sablier } from '../../interfaces'; -import IContract from '../IContract'; -import Numbers from '../../utils/Numbers'; - -const assert = require('assert'); - -/** - * Sablier Object for decentralized escrow payments - * @class Sablier - * @param {Sablier~Options} options - */ -export default class Sablier extends IContract { - constructor(params) { - super({ abi: sablier, ...params }); - } - - - /** - * Add pauser role to given address. - * @param {Object} params - * @param {address} params.account Address to assign pauser role to. - * @returns {Promise} - */ - async addPauser({ account }) { - return await this.__sendTx(this.getWeb3Contract().methods.addPauser(account)); - } - - - /** - * Pause contract. - * @returns {Promise} - */ - async pause() { - return await this.__sendTx(this.getWeb3Contract().methods.pause()); - } - - - /** - * Unpause/resume contract. - * @returns {Promise} - */ - async unpause() { - return await this.__sendTx(this.getWeb3Contract().methods.unpause()); - } - - - /** - * Check if the given address has pauser role. - * @param {Object} params - * @param {address} params.account Address to check. - * @returns {Promise} - */ - async isPauser({ account }) { - return await this.getWeb3Contract().methods.isPauser(account).call(); - } - - - /** - * Counter for new stream ids. - * @returns {Promise} - */ - async nextStreamId() { - return await this.getWeb3Contract().methods.nextStreamId().call(); - } - - - /** - * The percentage fee charged by the contract on the accrued interest. For example 75 - * @returns {Promise} mantissa - */ - async fee() { - const res = await this.getWeb3Contract().methods.fee().call(); - // 1e16 is 1% of 1e18, fee is stored with 16 decimals as one hundred percent. - return Numbers.fromDecimalsToBN(res, 16); - } - - - /** - * Updates the Sablier fee. - * Throws if the caller is not the owner of the contract. - * @param {Object} params - * @param {uint256} params.feePercentage The new fee as a percentage, for example 75 means 75%. - * @returns {Promise} - */ - async updateFee({ feePercentage }) { - // const fee = Numbers.toSmartContractDecimals(feePercentage, 2); - return await this.__sendTx(this.getWeb3Contract().methods.updateFee(feePercentage)); - } - - - /** - * Withdraws the earnings for the given token address. - * Throws if `amount` exceeds the available balance. - * @param {Object} params - * @param {address} params.tokenAddress The address of the token to withdraw earnings for. - * @param {uint256} params.amount The amount of tokens to withdraw. - * @returns {Promise} - */ - async takeEarnings({ tokenAddress, amount }) { - const decimals = await this.getWeb3Contract().methods.getTokenDecimals(tokenAddress).call(); - const amountWithDecimals = Numbers.fromBNToDecimals( - amount, - decimals, - ); - return await this.__sendTx(this.getWeb3Contract().methods.takeEarnings(tokenAddress, amountWithDecimals)); - } - - - /** - * @typedef {Object} Sablier~getStreamType - * @property {address} sender - * @property {address} recipient - * @property {uint256} deposit - * @property {address} tokenAddress - * @property {uint256} startTime - * @property {uint256} stopTime - * @property {uint256} remainingBalance - * @property {uint256} ratePerSecond - */ - - /** - * Returns the compounding stream with all its properties. - * Throws if the id does not point to a valid stream. - * @param {Object} params - * @param {uint256} params.streamId The id of the stream to query. - * @returns {Promise} The stream object. - */ - async getStream({ streamId }) { - const res = await this.getWeb3Contract().methods.getStream(streamId).call(); - - const tokenAddress = res[3]; - const decimals = await this.getWeb3Contract().methods.getTokenDecimals(tokenAddress).call(); - return { - sender: res[0], - recipient: res[1], - deposit: Numbers.fromDecimalsToBN(res[2], decimals), - tokenAddress, // res[3] - startTime: res[4], // Numbers.fromSmartContractTimeToMinutes(res[4]), - stopTime: res[5], // Numbers.fromSmartContractTimeToMinutes(res[5]), - remainingBalance: Numbers.fromDecimalsToBN(res[6], decimals), - ratePerSecond: Numbers.fromDecimalsToBN(res[7], decimals), - }; - } - - - /** - * Returns either the delta in seconds between `block.timestamp` and `startTime` or - * between `stopTime` and `startTime, whichever is smaller. If `block.timestamp` is before - * `startTime`, it returns 0. - * Throws if the id does not point to a valid stream. - * @param {Object} params - * @param {uint256} params.streamId The id of the stream for which to query the delta. - * @returns {Promise} delta The time delta in seconds. - */ - async deltaOf({ streamId }) { - return await this.getWeb3Contract().methods.deltaOf(streamId).call(); - } - - - /** - * Returns the available funds for the given stream id and address. - * Throws if the id does not point to a valid stream. - * @param {Object} params - * @param {uint256} params.streamId The id of the stream for which to query the balance. - * @param {address} params.who The address for which to query the balance. - * @returns {Promise} balance The total funds allocated to `who` as uint256. - */ - async balanceOf({ streamId, who }) { - const decimals = await this.getWeb3Contract().methods.getTokenDecimalsFromStream(streamId).call(); - const balance = await this.getWeb3Contract().methods.balanceOf(streamId, who).call(); - const ret = Numbers.fromDecimalsToBN( - // const ret = Numbers.fromTokens( - balance, - decimals, - ); - console.log('Sablier.balanceOf: raw ', balance, ' converted ', ret); - return ret; - } - - - /** - * Checks if the provided id points to a valid compounding stream. - * @param {Object} params - * @param {uint256} params.streamId The id of the compounding stream to check. - * @returns {Promise} True if it is a compounding stream, otherwise false. - */ - async isCompoundingStream({ streamId }) { - return await this.getWeb3Contract().methods.isCompoundingStream(streamId).call(); - } - - - /** - * @typedef {Object} Sablier~getCompoundingStreamType - * @property {address} sender - * @property {address} recipient - * @property {uint256} deposit - * @property {address} tokenAddress - * @property {uint256} startTime - * @property {uint256} stopTime - * @property {uint256} remainingBalance - * @property {uint256} ratePerSecond - * @property {uint256} exchangeRateInitial - * @property {uint256} senderSharePercentage - * @property {uint256} recipientSharePercentage - */ - - /** - * Returns the compounding stream object with all its properties. - * Throws if the id does not point to a valid compounding stream. - * @param {Object} params - * @param {uint256} params.streamId The id of the compounding stream to query. - * @returns {Promise} The compounding stream object. - */ - async getCompoundingStream({ streamId }) { - const res = await this.getWeb3Contract().methods.getCompoundingStream(streamId).call(); - - const tokenAddress = res[3]; - const decimals = await this.getWeb3Contract().methods.getTokenDecimals(tokenAddress).call(); - return { - sender: res[0], - recipient: res[1], - deposit: Numbers.fromDecimalsToBN(res[2], decimals), - tokenAddress, // res[3] - startTime: res[4], // Numbers.fromSmartContractTimeToMinutes(res[4]), - stopTime: res[5], // Numbers.fromSmartContractTimeToMinutes(res[5]), - remainingBalance: Numbers.fromDecimalsToBN(res[6], decimals), - ratePerSecond: Numbers.fromDecimalsToBN(res[7], decimals), - exchangeRateInitial: Numbers.fromDecimalsToBN(res[8], decimals), // uint256, TODO ??? any conversion needed - senderSharePercentage: Numbers.fromDecimalsToBN(res[9], 16), // comes scaled up to 1e16, for example 75*1e16 is 75% - recipientSharePercentage: Numbers.fromDecimalsToBN(res[10], 16), - }; - } - - - /** @typedef {Object} Sablier~interestOfType - * @property {uint256} senderInterest - * @property {uint256} recipientInterest - * @property {uint256} sablierInterest - */ - - /** - * Computes the interest accrued while the money has been streamed. Returns (0, 0, 0) if - * the stream is either not a compounding stream or it does not exist. - * Throws if there is a math error. We do not assert the calculations which involve the current - * exchange rate, because we can't know what value we'll get back from the cToken contract. - * @param {Object} params - * @param {uint256} params.streamId The id of the compounding stream for which to calculate the interest. - * @param {uint256} params.amount The amount of money with respect to which to calculate the interest. - * @returns {Promise} The interest accrued by the sender, the recipient and sablier, respectively, as uint256s. - */ - async interestOf({ streamId, amount }) { - const decimals = await this.getWeb3Contract().methods.getTokenDecimalsFromStream(streamId).call(); - const amountWithDecimals = Numbers.fromBNToDecimals( - amount, - decimals, - ); - const res = await this.getWeb3Contract().methods.interestOf(streamId, amountWithDecimals).call(); - return { - senderInterest: Numbers.fromDecimalsToBN(res[0], decimals), - recipientInterest: Numbers.fromDecimalsToBN(res[1], decimals), - sablierInterest: Numbers.fromDecimalsToBN(res[2], decimals), - }; - } - - - /** - * Returns the amount of interest that has been accrued for the given token address. - * @param {Object} params - * @param {address} params.tokenAddress The address of the token to get the earnings for. - * @returns {Promise} The amount of interest as uint256. - */ - async getEarnings({ tokenAddress }) { - const earnings = await this.getWeb3Contract().methods.getEarnings(tokenAddress).call(); - const decimals = await this.getWeb3Contract().methods.getTokenDecimals(tokenAddress).call(); - const ret1 = Numbers.fromDecimalsToBN( - earnings, - decimals, - ); - /* const ret2 = Numbers.fromExponential( - earnings, - ); - const ret3 = Numbers.fromTokens( - earnings, - decimals, - ); */ - console.log('...Sablier.getEarnings.earnings: ', earnings, ' | decimals: ', decimals); - console.log('...Sablier.getEarnings.earnings.fromDecimalsToBN: ', ret1); - // console.log('...Sablier.getEarnings.earnings.fromExponential: ', ret2); - // console.log('...Sablier.getEarnings.earnings.fromTokens: ', ret3); - return ret1; - } - - - /** - * Creates a new stream funded by `msg.sender` and paid towards `recipient`. - * Throws if paused. - * Throws if the recipient is the zero address, the contract itself or the caller. - * Throws if the deposit is 0. - * Throws if the start time is before `block.timestamp`. - * Throws if the stop time is before the start time. - * Throws if the duration calculation has a math error. - * Throws if the deposit is smaller than the duration. - * Throws if the deposit is not a multiple of the duration. - * Throws if the rate calculation has a math error. - * Throws if the next stream id calculation has a math error. - * Throws if the contract is not allowed to transfer enough tokens. - * Throws if there is a token transfer failure. - * @param {Object} params - * @param {address} params.recipient The address towards which the money is streamed. - * @param {uint256} params.deposit The amount of money to be streamed. - * @param {address} params.tokenAddress The ERC20 token to use as streaming currency. - * @param {uint256} params.startTime The unix timestamp for when the stream starts. - * @param {uint256} params.stopTime The unix timestamp for when the stream stops. - * @returns {Promise} The uint256 id of the newly created stream. - */ - async createStream({ - recipient, deposit, tokenAddress, startTime, stopTime, - }) { - const decimals = await this.getWeb3Contract().methods.getTokenDecimals(tokenAddress).call(); - const depositWithDecimals = Numbers.fromBNToDecimals( - deposit, - decimals, - ); - // const startTime2 = Numbers.timeToSmartContractTime(startTime); - // const stopTime2 = Numbers.timeToSmartContractTime(stopTime); - return await this.__sendTx(this.getWeb3Contract().methods.createStream(recipient, depositWithDecimals, tokenAddress, startTime, stopTime)); - } - - - /** - * Creates a new compounding stream funded by `msg.sender` and paid towards `recipient`. - * Inherits all security checks from `createStream`. - * Throws if the cToken is not whitelisted. - * Throws if the sender share percentage and the recipient share percentage do not sum up to 100. - * Throws if the the sender share mantissa calculation has a math error. - * Throws if the the recipient share mantissa calculation has a math error. - * @param {Object} params - * @param {address} params.recipient The address towards which the money is streamed. - * @param {uint256} params.deposit The amount of money to be streamed. - * @param {address} params.tokenAddress The ERC20 token to use as streaming currency. - * @param {uint256} params.startTime The unix timestamp for when the stream starts. - * @param {uint256} params.stopTime The unix timestamp for when the stream stops. - * @param {uint256} params.senderSharePercentage The sender's share of the interest, as a percentage. - * @param {uint256} params.recipientSharePercentage The recipient's share of the interest, as a percentage. - * @returns {Promise} The uint256 id of the newly created compounding stream. - */ - async createCompoundingStream({ - recipient, deposit, tokenAddress, startTime, stopTime, senderSharePercentage, recipientSharePercentage, - }) { - const decimals = await this.getWeb3Contract().methods.getTokenDecimals(tokenAddress).call(); - const depositWithDecimals = Numbers.fromBNToDecimals( - deposit, - decimals, - ); - // const startTime2 = Numbers.timeToSmartContractTime(startTime); - // const stopTime2 = Numbers.timeToSmartContractTime(stopTime); - // console.log('Sablier.createCompoundingStream.bp3.startTime | startTime2: ', startTime, ' | ', startTime2); - // console.log('Sablier.createCompoundingStream.bp3.stopTime | stopTime2 : ', stopTime, ' | ', stopTime2); - return await this.__sendTx(this.getWeb3Contract().methods.createCompoundingStream( - recipient, depositWithDecimals, tokenAddress, startTime, stopTime, senderSharePercentage, recipientSharePercentage, - )); - } - - - /** - * Withdraws from the contract to the recipient's account. - * Throws if the id does not point to a valid stream. - * Throws if the caller is not the sender or the recipient of the stream. - * Throws if the amount exceeds the available balance. - * Throws if there is a token transfer failure. - * @param {Object} params - * @param {uint256} params.streamId The id of the stream to withdraw tokens from. - * @param {uint256} params.amount The amount of tokens to withdraw. - * @returns {Promise} True if success, otherwise false. - */ - async withdrawFromStream({ streamId, amount }) { - const decimals = await this.getWeb3Contract().methods.getTokenDecimalsFromStream(streamId).call(); - const amountWithDecimals = Numbers.fromBNToDecimals( - amount, - decimals, - ); - return await this.__sendTx(this.getWeb3Contract().methods.withdrawFromStream(streamId, amountWithDecimals)); - } - - - /** - * Cancels the stream and transfers the tokens back on a pro rata basis. - * Throws if the id does not point to a valid stream. - * Throws if the caller is not the sender or the recipient of the stream. - * Throws if there is a token transfer failure. - * @param {Object} params - * @param {uint256} params.streamId The id of the stream to cancel. - * @returns {Promise} True if success, otherwise false. - */ - async cancelStream({ streamId }) { - return await this.__sendTx(this.getWeb3Contract().methods.cancelStream(streamId)); - } - - /** - * Get token decimals given a stream id. - * This is an utility function for DApp layer when converting to float numbers. - * @param streamId The id of the stream. - */ - async getTokenDecimalsFromStream({ streamId }) { - return await this.getWeb3Contract().methods.getTokenDecimalsFromStream(streamId).call(); - } - - /** - * - * @return {Promise} - * @throws {Error} Contract is not deployed, first deploy it and provide a contract address - */ - __assert = async () => { - if (!this.getAddress()) { - throw new Error( - 'Contract is not deployed, first deploy it and provide a contract address', - ); - } - - /* Use ABI */ - this.params.contract.use(sablier, this.getAddress()); - }; - - /** - * Deploy the Sablier Contract - * @function - * @param {Object} params - * @param {function():void} params.callback - * @return {Promise<*|undefined>} - */ - deploy = async ({ callback } = {}) => { - const params = []; - - const res = await this.__deploy(params, callback); - this.params.contractAddress = res.contractAddress; - /* Call to Backend API */ - await this.__assert(); - return res; - }; -} diff --git a/tests/sablier/admin/TakeEarnings.js b/tests/sablier/admin/TakeEarnings.js deleted file mode 100644 index e87a231e..00000000 --- a/tests/sablier/admin/TakeEarnings.js +++ /dev/null @@ -1,184 +0,0 @@ -/* eslint-disable no-await-in-loop */ -//const { dappConstants, mochaContexts } = require("./sablier/dev-utils"); -const project_root = process.cwd(); -const { dappConstants, devConstants, mochaContexts } = require(project_root + "/src/sablier/dev-utils"); -const BigNumber = require("bignumber.js"); -const dayjs = require("dayjs"); -const truffleAssert = require("truffle-assertions"); -const beproAssert = require(project_root + "/src/utils/beproAssert"); - -const { - FIVE_UNITS_CTOKEN, - STANDARD_RECIPIENT_SHARE_PERCENTAGE, - STANDARD_SALARY_CTOKEN, - STANDARD_SABLIER_FEE, - STANDARD_SENDER_SHARE_PERCENTAGE, - STANDARD_SUPPLY_AMOUNT, - STANDARD_TIME_DELTA, - STANDARD_TIME_OFFSET, -} = dappConstants; -const { contextForStreamDidStartButNotEnd } = mochaContexts; - -function shouldBehaveLikeTakeEarnings(_this) { //alice, bob, eve) { -//const shouldBehaveLikeTakeEarnings = (_this) => { - const alice = _this.alice; - const bob = _this.bob; - const eve = _this.eve; - //const admin = alice; - - describe("when the caller is the admin", () => { - //const opts = { from: admin }; - console.log('---shouldBehaveLikeTakeEarnings.web3: ', (web3 != null)); - - beforeEach(async () => { - await _this.sablier.updateFee({ feePercentage: STANDARD_SABLIER_FEE }); - }); - - describe("when the cToken is whitelisted", () => { - beforeEach(async () => { - //await this.cTokenManager.whitelistCToken(this.cToken.address, opts); - }); - - describe("when the amount does not exceed the available balance", () => { - console.log('---TakeEarnings.bp0'); - let streamId; - const recipient = bob; - const deposit = STANDARD_SALARY_CTOKEN.toString(10); - const senderSharePercentage = STANDARD_SENDER_SHARE_PERCENTAGE; - const recipientSharePercentage = STANDARD_RECIPIENT_SHARE_PERCENTAGE; - const now = new BigNumber(dayjs().unix()); - const startTime = now.plus(STANDARD_TIME_OFFSET); - const stopTime = startTime.plus(STANDARD_TIME_DELTA); - console.log('---TakeEarnings.bp1'); - console.log('---TakeEarnings.now : ', now); - console.log('---TakeEarnings.startTime: ', startTime); - console.log('---TakeEarnings.stopTime : ', stopTime); - - beforeEach(async () => { - console.log('---TakeEarnings.beforeEach.bp0.deposit: ', deposit); - await _this.cToken.approve({ address: _this.sablier.getAddress(), amount: deposit }); - const allowance = await _this.cToken.allowance({ address: _this.userAddress, spenderAddress: _this.sablier.getAddress() }); - console.log('---TakeEarnings.beforeEach.cToken.allowance: ', allowance); - console.log('---TakeEarnings.beforeEach.bp1'); - const result = await _this.sablier.createCompoundingStream({ - recipient, - deposit, - tokenAddress: _this.cToken.getAddress(), - startTime, - stopTime, - senderSharePercentage, - recipientSharePercentage, - }); - //const res = await beproAssert.createTransactionResult(_this.sablier.getWeb3Contract(), result.transactionHash); - //console.log('---TakeEarnings.result.beproAssert\n', res); - //const res2 = await truffleAssert.createTransactionResult(_this.sablier.getWeb3Contract(), result.transactionHash); - //console.log('---TakeEarnings.result.truffleAssert\n', res2); - //console.log('---TakeEarnings.result.bp0\n', result); - //console.log('---TakeEarnings.result.bp2\n', result.events.CreateCompoundingStream.returnValues); - //streamId = Number(result.logs[0].args.streamId); - streamId = Number(result.events.CreateStream.returnValues.streamId); - console.log('---TakeEarnings.result.streamId:', streamId); - await _this.token.approve({ address: _this.cToken.getAddress(), amount: STANDARD_SUPPLY_AMOUNT.toString(10) }); - await _this.cToken.supplyUnderlying(STANDARD_SUPPLY_AMOUNT.toString(10)); - }); - - describe("when the amount is not zero", () => { - const amount = FIVE_UNITS_CTOKEN.toString(10); - - contextForStreamDidStartButNotEnd(() => { - it("takes the earnings", async () => { - /*let precision = '1e' + 8; - let test = 17640000253575; - let p1 = (test / precision); - let p2 = p1 + 1; - console.log('...take the earnings.TEST.precision: ', precision, ' >> ', p1); - console.log('...take the earnings.TEST.p2: ', p2); - let f0 = parseFloat('17640000253575'); - let f1 = Number(parseFloat(test).toPrecision(8)); // truncates to first 8 digits from the left - let f2 = f1 + 1; - console.log('...take the earnings.TEST.f0: ', f0); - console.log('...take the earnings.TEST.f1: ', f1); - console.log('...take the earnings.TEST.f2: ', f2); - let f3 = f0.toFixed(8); //string - let f4 = Number(f0.toFixed(8)); //number - let f5 = f3 + 1; - let f6 = f4 + 1; - console.log('...take the earnings.TEST.f3: ', f3); - console.log('...take the earnings.TEST.f4: ', f4); - console.log('...take the earnings.TEST.f5: ', f5); - console.log('...take the earnings.TEST.f6: ', f6); - */ - const balance0 = await _this.cToken.balanceOf(_this.userAddress); - console.log('---take the earnings.bp0.balance0: ', balance0); - console.log('---take the earnings.bp0. streamId | amount: ', streamId, ' | ', amount); - await _this.sablier.withdrawFromStream({ streamId, amount }); - console.log('---take the earnings.bp1'); - const balance = await _this.cToken.balanceOf(_this.userAddress); //balanceOf(admin); - console.log('---take the earnings.bp2.balance: ', balance); - const earningsAmount = await _this.sablier.getEarnings({ tokenAddress: _this.cToken.getAddress() }); - console.log('---take the earnings.bp3.earningsAmount: ', earningsAmount); - await _this.sablier.takeEarnings({ tokenAddress: _this.cToken.getAddress(), amount: earningsAmount }); - console.log('---take the earnings.bp4'); - const newBalance = await _this.cToken.balanceOf(_this.userAddress); //balanceOf(admin); - console.log('---take the earnings.bp5.newBalance: ', newBalance); - balance.should.be.bignumber.equal((new BigNumber(newBalance)).minus(earningsAmount)); - console.log('---take the earnings.bp6'); - }); - }); - }); - - describe("when the amount is zero", () => { - const amount = new BigNumber(0).toString(10); - console.log('---TakeEarnings.bp3.amount: ', amount); - - it("reverts", async () => { - await truffleAssert.reverts(_this.sablier.takeEarnings({ tokenAddress: _this.cToken.getAddress(), amount }), "amount is zero"); - }); - }); - }); - - describe("when the amount exceeds the available balance", () => { - const amount = new BigNumber(8123101); - - it("reverts", async () => { - await truffleAssert.reverts( - _this.sablier.takeEarnings({ tokenAddress: _this.cToken.getAddress(), amount }), - "amount exceeds the available balance", - ); - }); - }); - }); - - /*describe("when the cToken is not whitelisted", function() { - const amount = new BigNumber(8123101); - - it("reverts", async function() { - await truffleAssert.reverts( - this.sablier.takeEarnings(this.cToken.address, amount, opts), - "cToken is not whitelisted", - ); - }); - });*/ - }); - - describe("when the stream does not exist", () => { - it("reverts", async () => { - const streamId = new BigNumber(419863); - await truffleAssert.reverts(_this.sablier.getStream({ streamId }), "stream does not exist"); - }); - }); - - /*describe("when the caller is not the admin", function() { - const opts = { from: eve }; - const amount = new BigNumber(8123101); - - it("reverts", async function() { - await truffleAssert.reverts( - this.sablier.takeEarnings(this.cToken.address, amount, opts), - truffleAssert.ErrorType.REVERT, - ); - }); - });*/ -} - -module.exports = shouldBehaveLikeTakeEarnings; diff --git a/tests/sablier/admin/UpdateFee.js b/tests/sablier/admin/UpdateFee.js deleted file mode 100644 index ad082bc7..00000000 --- a/tests/sablier/admin/UpdateFee.js +++ /dev/null @@ -1,50 +0,0 @@ -//const { devConstants } = require("@sablier/dev-utils"); -const project_root = process.cwd(); -const { dappConstants } = require(project_root + "/src/sablier/dev-utils"); - -const BigNumber = require("bignumber.js"); -const truffleAssert = require("truffle-assertions"); - -const { STANDARD_SABLIER_FEE } = dappConstants; -import { expect, assert } from "chai"; - -function shouldBehaveLikeUpdateFee(_this) { //alice, eve) { - console.log('---sablier.BalanceOf. alice: ', _this.alice); - //const admin = alice; - - describe("when the caller is the admin", () => {//function() { - //const opts = { from: admin }; - - describe("when the fee is a valid percentage", () => {//function() { - console.log('---sablier.BalanceOf.bp1 alice: ', _this.alice); - const newFee = STANDARD_SABLIER_FEE; - - it("updates the fee", async () => {//async function() { - await _this.sablier.updateFee({ feePercentage: newFee }); //, opts); - const result = await _this.sablier.fee(); - console.log('---updates the fee.result: ' + result); - // The new fee is a mantissa - result.should.be.bignumber.equal(newFee); //.multipliedBy(1e16)); - //expect((new BigNumber(result)).toString()).to.equal(newFee.multipliedBy(1e16).toString()); - }); - }); - - describe("when the fee is not a valid percentage", () => {//function() { - it("reverts", async () => {//async function() { - const newFee = new BigNumber(110); - await truffleAssert.reverts(_this.sablier.updateFee({ feePercentage: newFee }), "fee percentage higher than 100%"); - }); - }); - }); - - /*describe("when the caller is not the admin", async () => {//function() { - const opts = { from: eve }; - const newFee = STANDARD_SABLIER_FEE; - - it("reverts", async function() { - await truffleAssert.reverts(this.sablier.updateFee(newFee, opts), truffleAssert.ErrorType.REVERT); - }); - });*/ -} - -module.exports = shouldBehaveLikeUpdateFee; diff --git a/tests/sablier/effects/compoundingStream/CancelCompoundingStream.js b/tests/sablier/effects/compoundingStream/CancelCompoundingStream.js deleted file mode 100644 index de70bc3a..00000000 --- a/tests/sablier/effects/compoundingStream/CancelCompoundingStream.js +++ /dev/null @@ -1,328 +0,0 @@ -//const { dappConstants, mochaContexts } = require("@sablier/dev-utils"); -const project_root = process.cwd(); -const { dappConstants, mochaContexts } = require(project_root + "/src/sablier/dev-utils"); -const BigNumber = require("bignumber.js"); -const dayjs = require("dayjs"); -const truffleAssert = require("truffle-assertions"); -const beproAssert = require(project_root + "/src/utils/beproAssert"); - -const { contextForStreamDidEnd, contextForStreamDidStartButNotEnd } = mochaContexts; - -const { - FIVE_UNITS_CTOKEN, - STANDARD_RECIPIENT_SHARE_PERCENTAGE, - STANDARD_SABLIER_FEE, - STANDARD_SALARY_CTOKEN, - STANDARD_SCALE_CTOKEN, - STANDARD_SCALE_INTEREST, - STANDARD_SENDER_SHARE_PERCENTAGE, - STANDARD_SUPPLY_AMOUNT, - STANDARD_TIME_OFFSET, - STANDARD_TIME_DELTA, -} = dappConstants; - -let sender; -let recipient; -let deposit; -let streamId; - -function runTests(_this) { - describe("when there were no withdrawals", () => { - describe("when the stream did not start", () => { - it("cancels the stream", async () => { - await _this.sablier.cancelStream({ streamId }); - await truffleAssert.reverts(_this.sablier.getStream({ streamId }), "stream does not exist"); - await truffleAssert.reverts(_this.sablier.getCompoundingStream({ streamId }), "stream does not exist"); - }); - }); - - contextForStreamDidStartButNotEnd(() => { - const recipientBalance = FIVE_UNITS_CTOKEN.toString(10); - - it("cancels the stream", async () => { - await _this.sablier.cancelStream({ streamId }); - await truffleAssert.reverts(_this.sablier.getStream({ streamId }), "stream does not exist"); - await truffleAssert.reverts(_this.sablier.getCompoundingStream({ streamId }), "stream does not exist"); - }); - - it("transfers the tokens and pays the interest to the sender of the stream", async () => { - const balance = await _this.cToken.balanceOf(sender); - const { senderInterest } = await _this.sablier.interestOf({ streamId, amount: recipientBalance }); - await _this.sablier.cancelStream({ streamId }); - const newBalance = await _this.cToken.balanceOf(sender); - const tolerateByAddition = false; - newBalance.should.tolerateTheBlockTimeVariation( - balance - .minus(recipientBalance) - .plus(deposit) - .plus(senderInterest), - STANDARD_SCALE_CTOKEN, - tolerateByAddition, - ); - }); - - it("transfers the tokens and pays the interest to the recipient of the stream", async () => { - const balance = await _this.cToken.balanceOf(recipient); - const { senderInterest, sablierInterest } = await _this.sablier.interestOf({ streamId, amount: recipientBalance }); - await _this.sablier.cancelStream({ streamId }); - const netWithdrawalAmount = new BigNumber(recipientBalance).minus(senderInterest).minus(sablierInterest); - const newBalance = await _this.cToken.balanceOf(recipient,); - newBalance.should.tolerateTheBlockTimeVariation(balance.plus(netWithdrawalAmount), STANDARD_SCALE_CTOKEN); - }); - - it("pays the interest to the sablier contract", async () => { - const earnings = await _this.sablier.getEarnings({ tokenAddress: _this.cToken.getAddress() }); - const balance = await _this.cToken.balanceOf(_this.sablier.getAddress()); - const { remainingBalance } = await _this.sablier.getStream({ streamId }); - const { sablierInterest } = await _this.sablier.interestOf({ streamId, amount: recipientBalance }); - await _this.sablier.cancelStream({ streamId }); - const newEarnings = await _this.sablier.getEarnings({ tokenAddress: _this.cToken.getAddress() }); - const newBalance = await _this.cToken.balanceOf(_this.sablier.getAddress()); - newEarnings.should.tolerateTheBlockTimeVariation(earnings.plus(sablierInterest), STANDARD_SCALE_INTEREST); - // The sender and the recipient's interests are included in `stream.remainingBalance`, - // so we don't subtract them again - newBalance.should.tolerateTheBlockTimeVariation( - balance.minus(remainingBalance).plus(sablierInterest), - STANDARD_SCALE_INTEREST, - ); - }); - - it("emits a cancelstream event", async () => { - const result = await _this.sablier.cancelStream({ streamId }); - //truffleAssert.eventEmitted(result, "CancelStream"); - beproAssert.eventEmitted(result, "CancelStream"); - }); - - it("emits a payinterest event", async () => { - const result = await _this.sablier.cancelStream({ streamId }); - //truffleAssert.eventEmitted(result, "PayInterest"); - beproAssert.eventEmitted(result, "PayInterest"); - }); - }); - - contextForStreamDidEnd(() => { - const recipientBalance = STANDARD_SALARY_CTOKEN.toString(10); - - it("cancels the stream", async () => { - await _this.sablier.cancelStream({ streamId }); - await truffleAssert.reverts(_this.sablier.getStream({ streamId }), "stream does not exist"); - await truffleAssert.reverts(_this.sablier.getCompoundingStream({ streamId }), "stream does not exist"); - }); - - it("transfers the tokens and pays the interest to the sender of the stream", async () => { - const balance = await _this.cToken.balanceOf(sender); - const { senderInterest } = await _this.sablier.interestOf({ streamId, amount: recipientBalance }); - await _this.sablier.cancelStream({ streamId }); - const newBalance = await _this.cToken.balanceOf(sender); - newBalance.should.be.bignumber.equal(balance.plus(senderInterest)); - }); - - it("transfers the tokens and pays the interest to the recipient of the stream", async () => { - const balance = await _this.cToken.balanceOf(recipient); - const { senderInterest, sablierInterest } = await _this.sablier.interestOf({ streamId, amount: recipientBalance }); - await _this.sablier.cancelStream({ streamId }); - const netWithdrawalAmount = new BigNumber(recipientBalance).minus(senderInterest).minus(sablierInterest); - const newBalance = await _this.cToken.balanceOf(recipient); - newBalance.should.be.bignumber.equal(balance.plus(netWithdrawalAmount)); - }); - - it("pays the interest to the sablier contract", async () => { - const earnings = await _this.sablier.getEarnings({ tokenAddress: _this.cToken.getAddress() }); - const balance = await _this.cToken.balanceOf(_this.sablier.getAddress()); - const stream = await _this.sablier.getStream({ streamId }); - const { sablierInterest } = await _this.sablier.interestOf({ streamId, amount: recipientBalance }); - await _this.sablier.cancelStream({ streamId }); - const newEarnings = await _this.sablier.getEarnings({ tokenAddress: _this.cToken.getAddress() }); - const newBalance = await _this.cToken.balanceOf(_this.sablier.getAddress()); - // The sender and the recipient's interests are included in `stream.remainingBalance`, - // so we don't subtract them again - newEarnings.should.tolerateTheBlockTimeVariation(earnings.plus(sablierInterest), STANDARD_SCALE_INTEREST); - newBalance.should.tolerateTheBlockTimeVariation( - balance.minus(stream.remainingBalance).plus(sablierInterest), - STANDARD_SCALE_INTEREST, - ); - }); - - it("emits a cancelstream event", async () => { - const result = await _this.sablier.cancelStream({ streamId }); - //truffleAssert.eventEmitted(result, "CancelStream"); - beproAssert.eventEmitted(result, "CancelStream"); - }); - - it("emits a payinterest event", async () => { - const result = await _this.sablier.cancelStream({ streamId }); - //truffleAssert.eventEmitted(result, "PayInterest"); - beproAssert.eventEmitted(result, "PayInterest"); - }); - }); - }); - - describe("when there were withdrawals", () => { - contextForStreamDidStartButNotEnd(() => { - beforeEach(async () => { - const streamedAmount = FIVE_UNITS_CTOKEN.toString(10); - await _this.sablier.withdrawFromStream({ streamId, amount: streamedAmount }); - }); - - it("cancels the stream", async () => { - await _this.sablier.cancelStream({ streamId }); - await truffleAssert.reverts(_this.sablier.getStream({ streamId }), "stream does not exist"); - await truffleAssert.reverts(_this.sablier.getCompoundingStream({ streamId }), "stream does not exist"); - }); - }); - }); -} - -function shouldBehaveLikeCancelCompoundingStream(_this) { //alice, bob) { - const alice = _this.alice; - const bob = _this.bob; - const now = new BigNumber(dayjs().unix()); - const startTime = now.plus(STANDARD_TIME_OFFSET); - const stopTime = startTime.plus(STANDARD_TIME_DELTA); - - beforeEach(async () => { - sender = alice; - recipient = bob; - deposit = STANDARD_SALARY_CTOKEN.toString(10); - //this.opts = { from: this.sender }; - //await this.cTokenManager.whitelistCToken(this.cToken.address, { from: alice }); - await _this.cToken.approve({ address: _this.sablier.getAddress(), amount: deposit }); //{ from: alice }); - }); - - describe("when the sender's interest share is not zero and the recipient's interest share is not zero", () => { - const senderSharePercentage = STANDARD_SENDER_SHARE_PERCENTAGE; - const recipientSharePercentage = STANDARD_RECIPIENT_SHARE_PERCENTAGE; - - beforeEach(async () => { - const result = await _this.sablier.createCompoundingStream({ - recipient, - deposit, - tokenAddress: _this.cToken.getAddress(), - startTime, - stopTime, - senderSharePercentage, - recipientSharePercentage, - }); - streamId = Number(result.events.CreateStream.returnValues.streamId); - console.log('---CancelCompoundingStream.streamId.bp0: ', streamId); - await _this.token.approve({ address: _this.cToken.getAddress(), amount: STANDARD_SUPPLY_AMOUNT.toString(10) }); //, this.opts); - await _this.cToken.supplyUnderlying(STANDARD_SUPPLY_AMOUNT.toString(10)); - }); - - describe("when the sablier fee is not zero and is not 100", () => { - beforeEach(async () => { - await _this.sablier.updateFee({ feePercentage: STANDARD_SABLIER_FEE }); - }); - - runTests(_this); - }); - - describe("when the sablier fee is 0", () => { - beforeEach(async () => { - await _this.sablier.updateFee({ feePercentage: new BigNumber(0) }); - }); - - runTests(_this); - }); - - describe("when the sablier fee is 100", () => { - beforeEach(async () => { - await _this.sablier.updateFee({ feePercentage: new BigNumber(100) }); - }); - - runTests(_this); - }); - }); - - describe("when the sender's interest share is zero", () => { - const senderSharePercentage = new BigNumber(0); - const recipientSharePercentage = new BigNumber(100); - - beforeEach(async () => { - const result = await _this.sablier.createCompoundingStream({ - recipient, - deposit, - tokenAddress: _this.cToken.getAddress(), - startTime, - stopTime, - senderSharePercentage, - recipientSharePercentage, - }); - streamId = Number(result.events.CreateStream.returnValues.streamId); - console.log('---CancelCompoundingStream.streamId.bp1: ', streamId); - await _this.token.approve({ address: _this.cToken.getAddress(), amount: STANDARD_SUPPLY_AMOUNT.toString(10) }); //, this.opts); - await _this.cToken.supplyUnderlying(STANDARD_SUPPLY_AMOUNT.toString(10)); - }); - - describe("when the sablier fee is not zero and is not 100", () => { - beforeEach(async () => { - await _this.sablier.updateFee({ feePercentage: STANDARD_SABLIER_FEE }); - }); - - runTests(_this); - }); - - describe("when the sablier fee is 0", () => { - beforeEach(async () => { - await _this.sablier.updateFee({ feePercentage: new BigNumber(0) }); - }); - - runTests(_this); - }); - - describe("when the sablier fee is 100", () => { - beforeEach(async () => { - await _this.sablier.updateFee({ feePercentage: new BigNumber(100) }); - }); - - runTests(_this); - }); - }); - - describe("when the recipient's interest share is zero", () => { - const senderSharePercentage = new BigNumber(100); - const recipientSharePercentage = new BigNumber(0); - - beforeEach(async () => { - const result = await _this.sablier.createCompoundingStream({ - recipient, - deposit, - tokenAddress: _this.cToken.getAddress(), - startTime, - stopTime, - senderSharePercentage, - recipientSharePercentage, - }); - streamId = Number(result.events.CreateStream.returnValues.streamId); - console.log('---CancelCompoundingStream.streamId.bp2: ', streamId); - await _this.token.approve({ address: _this.cToken.getAddress(), amount: STANDARD_SUPPLY_AMOUNT.toString(10) }); //, this.opts); - await _this.cToken.supplyUnderlying(STANDARD_SUPPLY_AMOUNT.toString(10)); - }); - - describe("when the sablier fee is not zero and is not 100", () => { - beforeEach(async () => { - await _this.sablier.updateFee({ feePercentage: STANDARD_SABLIER_FEE }); - }); - - runTests(_this); - }); - - describe("when the sablier fee is 0", () => { - beforeEach(async () => { - await _this.sablier.updateFee({ feePercentage: new BigNumber(0) }); - }); - - runTests(_this); - }); - - describe("when the sablier fee is 100", () => { - beforeEach(async () => { - await _this.sablier.updateFee({ feePercentage: new BigNumber(100) }); - }); - - runTests(_this); - }); - }); -} - -module.exports = shouldBehaveLikeCancelCompoundingStream; diff --git a/tests/sablier/effects/compoundingStream/CreateCompoundingStream.js b/tests/sablier/effects/compoundingStream/CreateCompoundingStream.js deleted file mode 100644 index 2491206b..00000000 --- a/tests/sablier/effects/compoundingStream/CreateCompoundingStream.js +++ /dev/null @@ -1,184 +0,0 @@ -//const { dappConstants } = require("@sablier/dev-utils"); -const project_root = process.cwd(); -const { dappConstants } = require(project_root + "/src/sablier/dev-utils"); -const dayjs = require("dayjs"); -const BigNumber = require("bignumber.js"); -const truffleAssert = require("truffle-assertions"); -const beproAssert = require(project_root + "/src/utils/beproAssert"); - -const { - ONE_PERCENT_MANTISSA, - STANDARD_RATE_PER_SECOND_CTOKEN, - STANDARD_RECIPIENT_SHARE_PERCENTAGE, - STANDARD_SALARY_CTOKEN, - STANDARD_SENDER_SHARE_PERCENTAGE, - STANDARD_TIME_DELTA, - STANDARD_TIME_OFFSET, -} = dappConstants; - -/** - * We do not tests all the logical branches as in `CreateStream.js`, because these are unit tests. - * The `createCompoundingStream` method uses `createStream`, so if that fails with non-compliant erc20 - * or insufficient allowances, this must fail too. - */ -function shouldBehaveLikeCreateCompoundingStream(_this) { //alice, bob) { - const alice = _this.alice; - const bob = _this.bob; - const sender = alice; - const recipient = bob; - const deposit = STANDARD_SALARY_CTOKEN.toString(10); - //const opts = { from: sender }; - const now = new BigNumber(dayjs().unix()); - const startTime = now.plus(STANDARD_TIME_OFFSET); - const stopTime = startTime.plus(STANDARD_TIME_DELTA); - - describe("when not paused", () => { - describe("when the cToken is whitelisted", () => { - beforeEach(async () => { - //await _this.cTokenManager.whitelistCToken(_this.cToken.getAddress(), opts); - await _this.cToken.approve({ address: _this.sablier.getAddress(), amount: deposit }); - }); - - describe("when interest shares are valid", () => { - const senderSharePercentage = STANDARD_SENDER_SHARE_PERCENTAGE; - const recipientSharePercentage = STANDARD_RECIPIENT_SHARE_PERCENTAGE; - - it("creates the compounding stream", async () => { - const paused = await _this.sablier.isPaused(); - console.log('---sablier.CreateCompoundingStream.isPaused: ', paused); - - const result = await _this.sablier.createCompoundingStream({ - recipient, - deposit, - tokenAddress: _this.cToken.getAddress(), - startTime, - stopTime, - senderSharePercentage, - recipientSharePercentage, - }); - const exchangeRateInitial = new BigNumber(await _this.cToken.exchangeRateCurrent()); - - const streamId = Number(result.events.CreateStream.returnValues.streamId); - console.log('---CreateCompoundingStream.streamId: ', streamId); - const compoundingStreamObject = await _this.sablier.getCompoundingStream({ streamId }); - compoundingStreamObject.sender.should.be.equal(sender); - compoundingStreamObject.recipient.should.be.equal(recipient); - compoundingStreamObject.deposit.should.be.bignumber.equal(deposit); - compoundingStreamObject.tokenAddress.should.be.equal(_this.cToken.getAddress()); - compoundingStreamObject.startTime.should.be.bignumber.equal(startTime); - compoundingStreamObject.stopTime.should.be.bignumber.equal(stopTime); - compoundingStreamObject.remainingBalance.should.be.bignumber.equal(deposit); - compoundingStreamObject.ratePerSecond.should.be.bignumber.equal(STANDARD_RATE_PER_SECOND_CTOKEN); - compoundingStreamObject.exchangeRateInitial.should.be.bignumber.equal(exchangeRateInitial); - compoundingStreamObject.senderSharePercentage.should.be.bignumber.equal( - senderSharePercentage.multipliedBy(ONE_PERCENT_MANTISSA), - ); - compoundingStreamObject.recipientSharePercentage.should.be.bignumber.equal( - recipientSharePercentage.multipliedBy(ONE_PERCENT_MANTISSA), - ); - }); - - it("transfers the tokens to the contract", async () => { - const balance = await _this.cToken.balanceOf(sender); - await _this.sablier.createCompoundingStream({ - recipient, - deposit, - tokenAddress: _this.cToken.getAddress(), - startTime, - stopTime, - senderSharePercentage, - recipientSharePercentage, - }); - const newBalance = await _this.cToken.balanceOf(sender); - newBalance.should.be.bignumber.equal(new BigNumber(balance).minus(STANDARD_SALARY_CTOKEN)); - }); - - it("emits a createcompoundingstream event", async () => { - const result = await _this.sablier.createCompoundingStream({ - recipient, - deposit, - tokenAddress: _this.cToken.getAddress(), - startTime, - stopTime, - senderSharePercentage, - recipientSharePercentage, - }); - //truffleAssert.eventEmitted(result, "CreateCompoundingStream"); - beproAssert.eventEmitted(result, "CreateCompoundingStream"); - }); - }); - - describe("when interest shares are not valid", () => { - const senderSharePercentage = new BigNumber(40); - const recipientSharePercentage = new BigNumber(140); - - it("reverts", async () => { - await truffleAssert.reverts( - _this.sablier.createCompoundingStream({ - recipient, - deposit, - tokenAddress: _this.cToken.getAddress(), - startTime, - stopTime, - senderSharePercentage, - recipientSharePercentage, - }), - "shares do not sum up to 100", - ); - }); - }); - }); - - /*describe("when the cToken is not whitelisted", () => { - const senderSharePercentage = STANDARD_SENDER_SHARE_PERCENTAGE; - const recipientSharePercentage = STANDARD_RECIPIENT_SHARE_PERCENTAGE; - - it("reverts", async () => { - await truffleAssert.reverts( - _this.sablier.createCompoundingStream({ - recipient, - deposit, - tokenAddress: _this.cToken.getAddress(), - startTime, - stopTime, - senderSharePercentage, - recipientSharePercentage, - }), - "cToken is not whitelisted", - ); - }); - });*/ - }); - - describe("when paused", () => { - const senderSharePercentage = STANDARD_SENDER_SHARE_PERCENTAGE; - const recipientSharePercentage = STANDARD_RECIPIENT_SHARE_PERCENTAGE; - - beforeEach(async () => { - // Note that `sender` coincides with the owner of the contract - await _this.sablier.pause(); - }); - - it("reverts", async () => { - await truffleAssert.reverts( - _this.sablier.createCompoundingStream({ - recipient, - deposit, - tokenAddress: _this.cToken.getAddress(), - startTime, - stopTime, - senderSharePercentage, - recipientSharePercentage, - }), - "Pausable: paused", - ); - }); - - afterEach(async () => { - // Note that `sender` coincides with the owner of the contract - await _this.sablier.unpause(); - }); - }); -} - -module.exports = shouldBehaveLikeCreateCompoundingStream; diff --git a/tests/sablier/effects/compoundingStream/WithdrawFromCompoundingStream.js b/tests/sablier/effects/compoundingStream/WithdrawFromCompoundingStream.js deleted file mode 100644 index 327b1654..00000000 --- a/tests/sablier/effects/compoundingStream/WithdrawFromCompoundingStream.js +++ /dev/null @@ -1,366 +0,0 @@ -//const { dappConstants, mochaContexts } = require("@sablier/dev-utils"); -const project_root = process.cwd(); -const { dappConstants, mochaContexts } = require(project_root + "/src/sablier/dev-utils"); -const BigNumber = require("bignumber.js"); -const dayjs = require("dayjs"); -const truffleAssert = require("truffle-assertions"); -const beproAssert = require(project_root + "/src/utils/beproAssert"); -import Numbers from "../../../../build/utils/Numbers"; - -const { - FIVE_UNITS_CTOKEN, - STANDARD_RECIPIENT_SHARE_PERCENTAGE, - STANDARD_SABLIER_FEE, - STANDARD_SALARY_CTOKEN, - STANDARD_SCALE_CTOKEN, - STANDARD_SCALE_INTEREST, - STANDARD_SENDER_SHARE_PERCENTAGE, - STANDARD_SUPPLY_AMOUNT, - STANDARD_TIME_OFFSET, - STANDARD_TIME_DELTA, -} = dappConstants; -const { contextForStreamDidEnd, contextForStreamDidStartButNotEnd } = mochaContexts; - -let sender; -let recipient; -let deposit; -let streamId; -let tokenDecimals; - -function runTests(_this) { - describe("when not paused", () => { - describe("when the stream did not start", () => { - const streamedAmount = FIVE_UNITS_CTOKEN.toString(10); - - it("reverts", async () => { - await truffleAssert.reverts( - _this.sablier.withdrawFromStream({ streamId, amount: streamedAmount }), //this.opts); - "amount exceeds the available balance", - ); - }); - }); - - contextForStreamDidStartButNotEnd(() => { - const streamedAmount = FIVE_UNITS_CTOKEN.toString(10); - - it("withdraws from the stream", async () => { - const senderBalance = await _this.cToken.balanceOf(sender); - const recipientBalance = await _this.cToken.balanceOf(recipient); - const sablierBalance = await _this.cToken.balanceOf(_this.sablier.getAddress()); - await _this.sablier.withdrawFromStream({ streamId, amount: streamedAmount }); - const newSenderBalance = await _this.cToken.balanceOf(sender); - const newRecipientBalance = await _this.cToken.balanceOf(recipient); - const newSablierBalance = await _this.cToken.balanceOf(_this.sablier.getAddress()); - - const sum = new BigNumber(senderBalance).plus(recipientBalance).plus(sablierBalance); - const newSum = new BigNumber(newSenderBalance).plus(newRecipientBalance).plus(newSablierBalance); - sum.should.be.bignumber.equal(newSum); - }); - - it("pays the interest to the sender of the stream", async () => { - const balance = await _this.cToken.balanceOf(sender); - const { senderInterest } = await _this.sablier.interestOf({ streamId, amount: streamedAmount }); - await _this.sablier.withdrawFromStream({ streamId, amount: streamedAmount }); - const newBalance = await _this.cToken.balanceOf(sender); - newBalance.should.be.bignumber.equal(new BigNumber(balance).plus(senderInterest)); - }); - - it("transfers the tokens and pays the interest to the recipient of the stream", async () => { - const balance = await _this.cToken.balanceOf(recipient); - const { senderInterest, sablierInterest } = await _this.sablier.interestOf({ streamId, amount: streamedAmount }); - await _this.sablier.withdrawFromStream({ streamId, amount: streamedAmount }); - const netWithdrawalAmount = new BigNumber(streamedAmount).minus(senderInterest).minus(sablierInterest); - const newBalance = await _this.cToken.balanceOf(recipient); - newBalance.should.be.bignumber.equal(new BigNumber(balance).plus(netWithdrawalAmount)); - }); - - it("pays the interest to the sablier contract", async () => { - const earnings = await _this.sablier.getEarnings({ tokenAddress: _this.cToken.getAddress() }); - const balance = await _this.cToken.balanceOf(_this.sablier.getAddress()); - const { sablierInterest } = await _this.sablier.interestOf({ streamId, amount: streamedAmount }); - await _this.sablier.withdrawFromStream({ streamId, amount: streamedAmount }); - const newEarnings = await _this.sablier.getEarnings({ tokenAddress: _this.cToken.getAddress() }); - const newBalance = await _this.cToken.balanceOf(_this.sablier.getAddress()); - // The sender and the recipient's interests are included in `amount`, - // so we don't subtract them again - // newEarnings.should.tolerateTheBlockTimeVariation(new BigNumber(earnings).plus(sablierInterest), STANDARD_SCALE_INTEREST); - newBalance.should.tolerateTheBlockTimeVariation( - new BigNumber(balance).minus(streamedAmount).plus(sablierInterest), - STANDARD_SCALE_INTEREST, - ); - }); - - it("emits a withdrawfromstream event", async () => { - const result = await _this.sablier.withdrawFromStream({ streamId, amount: streamedAmount }); - //truffleAssert.eventEmitted(result, "WithdrawFromStream"); - beproAssert.eventEmitted(result, "WithdrawFromStream"); - }); - - it("emits a payinterest event", async () => { - const result = await _this.sablier.withdrawFromStream({ streamId, amount: streamedAmount }); - //truffleAssert.eventEmitted(result, "PayInterest"); - beproAssert.eventEmitted(result, "PayInterest"); - }); - - it("decreases the stream balance", async () => { - const balance = await _this.sablier.balanceOf({ streamId, who: recipient }); - await _this.sablier.withdrawFromStream({ streamId, amount: streamedAmount }); - const newBalance = await _this.sablier.balanceOf({ streamId, who: recipient }); - // Intuitively, one may say we don't have to tolerate the block time variation here. - // However, the Sablier balance for the recipient can only go up from the bottom - // low of `balance` - `amount`, due to uncontrollable runtime costs. - newBalance.should.tolerateTheBlockTimeVariation(new BigNumber(balance).minus(streamedAmount), STANDARD_SCALE_CTOKEN); - }); - }); - - contextForStreamDidEnd(() => { - const streamedAmount = STANDARD_SALARY_CTOKEN.toString(10); - - it("withdraws from the stream", async () => { - const senderBalance = await _this.cToken.balanceOf(sender); - const recipientBalance = await _this.cToken.balanceOf(recipient); - const sablierBalance = await _this.cToken.balanceOf(_this.sablier.getAddress()); - await _this.sablier.withdrawFromStream({ streamId, amount: streamedAmount }); - const newSenderBalance = await _this.cToken.balanceOf(sender); - const newRecipientBalance = await _this.cToken.balanceOf(recipient); - const newSablierBalance = await _this.cToken.balanceOf(_this.sablier.getAddress()); - - const sum = new BigNumber(senderBalance).plus(recipientBalance).plus(sablierBalance); - const newSum = new BigNumber(newSenderBalance).plus(newRecipientBalance).plus(newSablierBalance); - sum.should.be.bignumber.equal(newSum); - }); - - it("pays the interest to the sender of the stream", async () => { - const balance = _this.cToken.toTokens(await _this.cToken.balanceOf(sender)); - let { senderInterest } = await _this.sablier.interestOf({ streamId, amount: streamedAmount }); - senderInterest = Numbers.toSmartContractDecimals(senderInterest, await _this.sablier.getTokenDecimalsFromStream({ streamId })); - await _this.sablier.withdrawFromStream({ streamId, amount: streamedAmount }); - const newBalance = _this.cToken.toTokens(await _this.cToken.balanceOf(sender)); - //TODO - newBalance.should.be.bignumber.equal(new BigNumber(balance).plus(senderInterest)); - }); - - it("transfers the tokens and pays the interest to the recipient of the stream", async () => { - const balance = _this.cToken.toTokens(await _this.cToken.balanceOf(recipient)); - const { senderInterest, sablierInterest } = await _this.sablier.interestOf({ streamId, amount: streamedAmount }); - await _this.sablier.withdrawFromStream({ streamId, amount: streamedAmount }); - let netWithdrawalAmount = new BigNumber(streamedAmount).minus(senderInterest).minus(sablierInterest); - netWithdrawalAmount = Numbers.toSmartContractDecimals(netWithdrawalAmount, tokenDecimals); - const newBalance = _this.cToken.toTokens(await _this.cToken.balanceOf(recipient)); - //TODO - newBalance.should.be.bignumber.equal(new BigNumber(balance).plus(netWithdrawalAmount)); - }); - - it("pays the interest to the sablier contract", async () => { - const earnings = await _this.sablier.getEarnings({ tokenAddress: _this.cToken.getAddress() }); - const balance = await _this.cToken.balanceOf(_this.sablier.getAddress()); - const { sablierInterest } = await _this.sablier.interestOf({ streamId, amount: streamedAmount }); - await _this.sablier.withdrawFromStream({ streamId, amount: streamedAmount }); - const newEarnings = await _this.sablier.getEarnings({ tokenAddress: _this.cToken.getAddress() }); - const newBalance = await _this.cToken.balanceOf(_this.sablier.getAddress()); - // The sender and the recipient's interests are included in `amount`, - // so we don't subtract them again - newEarnings.should.tolerateTheBlockTimeVariation(new BigNumber(earnings).plus(sablierInterest), STANDARD_SCALE_INTEREST); - newBalance.should.tolerateTheBlockTimeVariation( - new BigNumber(balance).minus(streamedAmount).plus(sablierInterest), - STANDARD_SCALE_INTEREST, - ); - }); - - it("emits a withdrawfromstream event", async () => { - const result = await _this.sablier.withdrawFromStream({ streamId, amount: streamedAmount }); - //truffleAssert.eventEmitted(result, "WithdrawFromStream"); - beproAssert.eventEmitted(result, "WithdrawFromStream"); - }); - - it("emits a payinterest event", async () => { - const result = await _this.sablier.withdrawFromStream({ streamId, amount: streamedAmount }); - //truffleAssert.eventEmitted(result, "PayInterest"); - beproAssert.eventEmitted(result, "PayInterest"); - }); - - it("deletes the stream objects", async () => { - await _this.sablier.withdrawFromStream({ streamId, amount: streamedAmount }); - await truffleAssert.reverts(_this.sablier.getStream({ streamId }), "stream does not exist"); - await truffleAssert.reverts(_this.sablier.getCompoundingStream({ streamId }), "stream does not exist"); - }); - }); - }); - - describe("when paused", () => { - const streamedAmount = FIVE_UNITS_CTOKEN.toString(10); - - beforeEach(async () => { - // Note that `sender` coincides with the owner of the contract - await _this.sablier.pause(); //({ from: this.sender }); - }); - - it("reverts", async () => { - await truffleAssert.reverts( - _this.sablier.withdrawFromStream({ streamId, amount: streamedAmount }), //, this.opts), - "Pausable: paused", - ); - }); - - afterEach(async () => { - // Note that `sender` coincides with the owner of the contract - await _this.sablier.unpause(); //({ from: this.sender }); - }); - }); -} - -function shouldBehaveLikeWithdrawFromCompoundingStream(_this) { //alice, bob) { - const alice = _this.alice; - const bob = _this.bob; - const deposit = STANDARD_SALARY_CTOKEN.toString(10); - const now = new BigNumber(dayjs().unix()); - const startTime = now.plus(STANDARD_TIME_OFFSET); - const stopTime = startTime.plus(STANDARD_TIME_DELTA); - - beforeEach(async () => { - sender = alice; - recipient = bob; - //this.opts = { from: this.sender }; - //await this.cTokenManager.whitelistCToken(this.cToken.address, this.opts); - await _this.cToken.approve({ address: _this.sablier.getAddress(), amount: deposit }); - }); - - describe("when the sender's interest share is not zero and the recipient's interest share is not zero", () => { - const senderSharePercentage = STANDARD_SENDER_SHARE_PERCENTAGE; - const recipientSharePercentage = STANDARD_RECIPIENT_SHARE_PERCENTAGE; - - beforeEach(async () => { - const result = await _this.sablier.createCompoundingStream({ - recipient, - deposit, - tokenAddress: _this.cToken.getAddress(), - startTime, - stopTime, - senderSharePercentage, - recipientSharePercentage, - }); - streamId = Number(result.events.CreateStream.returnValues.streamId); - console.log('---WithdrawFromCompoundingStream.streamId.bp0: ', streamId); - await _this.token.approve({ address: _this.cToken.getAddress(), amount: STANDARD_SUPPLY_AMOUNT.toString(10) }); - await _this.cToken.supplyUnderlying(STANDARD_SUPPLY_AMOUNT.toString(10)); - tokenDecimals = await _this.sablier.getTokenDecimalsFromStream({ streamId }); - console.log('---WithdrawFromCompoundingStream.tokenDecimals: ', tokenDecimals); - }); - - describe("when the sablier fee is not zero and is not 100", () => { - beforeEach(async () => { - await _this.sablier.updateFee({ feePercentage: new BigNumber(STANDARD_SABLIER_FEE) }); - }); - - runTests(_this); - }); - - describe("when the sablier fee is 0", () => { - beforeEach(async () => { - await _this.sablier.updateFee({ feePercentage: new BigNumber(0) }); - }); - - runTests(_this); - }); - - describe("when the sablier fee is 100", () => { - beforeEach(async () => { - await _this.sablier.updateFee({ feePercentage: new BigNumber(100) }); - }); - - runTests(_this); - }); - }); - - describe("when the sender's interest share is zero", () => { - const senderSharePercentage = new BigNumber(0); - const recipientSharePercentage = new BigNumber(100); - - beforeEach(async () => { - const result = await _this.sablier.createCompoundingStream({ - recipient, - deposit, - tokenAddress: _this.cToken.getAddress(), - startTime, - stopTime, - senderSharePercentage, - recipientSharePercentage, - }); - streamId = Number(result.events.CreateStream.returnValues.streamId); - console.log('---WithdrawFromCompoundingStream.streamId.bp1: ', streamId); - await _this.token.approve({ address: _this.cToken.getAddress(), amount: STANDARD_SUPPLY_AMOUNT.toString(10) }); - await _this.cToken.supplyUnderlying(STANDARD_SUPPLY_AMOUNT.toString(10)); - }); - - describe("when the sablier fee is not zero and is not 100", () => { - beforeEach(async () => { - await _this.sablier.updateFee({ feePercentage: new BigNumber(STANDARD_SABLIER_FEE) }); - }); - - runTests(_this); - }); - - describe("when the sablier fee is 0", () => { - beforeEach(async () => { - await _this.sablier.updateFee({ feePercentage: new BigNumber(0) }); - }); - - runTests(_this); - }); - - describe("when the sablier fee is 100", () => { - beforeEach(async () => { - await _this.sablier.updateFee({ feePercentage: new BigNumber(100) }); - }); - - runTests(_this); - }); - }); - - describe("when the recipient's interest share is zero", () => { - const senderSharePercentage = new BigNumber(100); - const recipientSharePercentage = new BigNumber(0); - - beforeEach(async () => { - const result = await _this.sablier.createCompoundingStream({ - recipient, - deposit, - tokenAddress: _this.cToken.getAddress(), - startTime, - stopTime, - senderSharePercentage, - recipientSharePercentage, - }); - streamId = Number(result.events.CreateStream.returnValues.streamId); - console.log('---WithdrawFromCompoundingStream.streamId.bp2: ', streamId); - await _this.token.approve({ address: _this.cToken.getAddress(), amount: STANDARD_SUPPLY_AMOUNT.toString(10) }); - await _this.cToken.supplyUnderlying(STANDARD_SUPPLY_AMOUNT.toString(10)); - }); - - describe("when the sablier fee is not zero and is not 100", () => { - beforeEach(async () => { - await _this.sablier.updateFee({ feePercentage: new BigNumber(STANDARD_SABLIER_FEE) }); - }); - - runTests(_this); - }); - - describe("when the sablier fee is 0", () => { - beforeEach(async () => { - await _this.sablier.updateFee({ feePercentage: new BigNumber(0) }); - }); - - runTests(_this); - }); - - describe("when the sablier fee is 100", () => { - beforeEach(async () => { - await _this.sablier.updateFee({ feePercentage: new BigNumber(100) }); - }); - - runTests(_this); - }); - }); -} - -module.exports = shouldBehaveLikeWithdrawFromCompoundingStream; diff --git a/tests/sablier/effects/stream/CancelStream.js b/tests/sablier/effects/stream/CancelStream.js deleted file mode 100644 index fcab3896..00000000 --- a/tests/sablier/effects/stream/CancelStream.js +++ /dev/null @@ -1,168 +0,0 @@ -//const { dappConstants, mochaContexts } = require("@sablier/dev-utils"); -const project_root = process.cwd(); -const { dappConstants, mochaContexts } = require(project_root + "/src/sablier/dev-utils"); -const BigNumber = require("bignumber.js"); -const dayjs = require("dayjs"); -const truffleAssert = require("truffle-assertions"); -const beproAssert = require(project_root + "/src/utils/beproAssert"); - -const { FIVE_UNITS, STANDARD_SALARY, STANDARD_SCALE, STANDARD_TIME_OFFSET, STANDARD_TIME_DELTA } = dappConstants; -const { contextForStreamDidEnd, contextForStreamDidStartButNotEnd } = mochaContexts; - -let streamId; -let recipient; -let deposit; -let sender; - -function runTests(_this) { - describe("when the stream did not start", () => { - it("cancels the stream", async () => { - await _this.sablier.cancelStream({ streamId }); - await truffleAssert.reverts(_this.sablier.getStream({ streamId }), "stream does not exist"); - }); - - it("transfers all tokens to the sender of the stream", async () => { - const balance = await _this.token.balanceOf(sender); - await _this.sablier.cancelStream({ streamId }); - const newBalance = await _this.token.balanceOf(sender); - newBalance.should.be.bignumber.equal(new BigNumber(balance).plus(deposit)); - }); - - it("emits a cancel event", async () => { - const result = await _this.sablier.cancelStream({ streamId }); - //truffleAssert.eventEmitted(result, "CancelStream"); - beproAssert.eventEmitted(result, "CancelStream"); - }); - }); - - contextForStreamDidStartButNotEnd(() => { - const streamedAmount = FIVE_UNITS.toString(10); - - it("cancels the stream", async () => { - await _this.sablier.cancelStream({ streamId }); - await truffleAssert.reverts(_this.sablier.getStream({ streamId }), "stream does not exist"); - }); - - it("transfers the tokens to the sender of the stream", async () => { - const balance = await _this.token.balanceOf(sender); - await _this.sablier.cancelStream({ streamId }); - const newBalance = await _this.token.balanceOf(sender); - const tolerateByAddition = false; - newBalance.should.tolerateTheBlockTimeVariation( - new BigNumber(balance).minus(streamedAmount).plus(deposit), - STANDARD_SCALE, - tolerateByAddition, - ); - }); - - it("transfers the tokens to the recipient of the stream", async () => { - const balance = await _this.token.balanceOf(recipient); - await _this.sablier.cancelStream({ streamId }); - const newBalance = await _this.token.balanceOf(recipient); - newBalance.should.tolerateTheBlockTimeVariation(new BigNumber(balance).plus(streamedAmount), STANDARD_SCALE); - }); - - it("emits a cancel event", async () => { - const result = await _this.sablier.cancelStream({ streamId }); - //truffleAssert.eventEmitted(result, "CancelStream"); - beproAssert.eventEmitted(result, "CancelStream"); - }); - }); - - contextForStreamDidEnd(() => { - const streamedAmount = STANDARD_SALARY.toString(10); - - it("cancels the stream", async () => { - await _this.sablier.cancelStream({ streamId }); - await truffleAssert.reverts(_this.sablier.getStream({ streamId }), "stream does not exist"); - }); - - it("transfers nothing to the sender of the stream", async () => { - const balance = await _this.token.balanceOf(sender); - await _this.sablier.cancelStream({ streamId }); - const newBalance = await _this.token.balanceOf(recipient); - newBalance.should.be.bignumber.equal(balance); - }); - - it("transfers all tokens to the recipient of the stream", async () => { - const balance = await _this.token.balanceOf(recipient); - await _this.sablier.cancelStream({ streamId }); - const newBalance = await _this.token.balanceOf(recipient); - newBalance.should.be.bignumber.equal(new BigNumber(balance).plus(streamedAmount)); - }); - - it("emits a cancel event", async () => { - const result = await _this.sablier.cancelStream({ streamId }); - //truffleAssert.eventEmitted(result, "CancelStream"); - beproAssert.eventEmitted(result, "CancelStream"); - }); - }); -} - -function shouldBehaveLikeERC1620CancelStream(_this) { //alice, bob, eve) { - const alice = _this.alice; - const bob = _this.bob; - const eve = _this.eve; - const now = new BigNumber(dayjs().unix()); - - describe("when the stream exists", () => { - const startTime = now.plus(STANDARD_TIME_OFFSET); - const stopTime = startTime.plus(STANDARD_TIME_DELTA); - - beforeEach(async () => { - sender = alice; - recipient = bob; - deposit = STANDARD_SALARY.toString(10); - //const opts = { from: this.sender }; - await _this.token.approve({ address: _this.sablier.getAddress(), amount: deposit }); - const result = await _this.sablier.createStream({ - recipient, - deposit, - tokenAddress: _this.token.getAddress(), - startTime, - stopTime, - }); - streamId = Number(result.events.CreateStream.returnValues.streamId); - console.log('---CancelStream.streamId: ', streamId); - }); - - describe("when the caller is the sender of the stream", () => { - beforeEach(() => { - //this.opts = { from: this.sender }; - }); - - runTests(_this); - }); - - /*describe("when the caller is the recipient of the stream", () => { - beforeEach(() => { - this.opts = { from: this.recipient }; - }); - - runTests(_this); - });*/ - - /*describe("when the caller is not the sender or the recipient of the stream", () => { - const opts = { from: eve }; - - it("reverts", async () => { - await truffleAssert.reverts( - _this.sablier.cancelStream({ streamId }), - "caller is not the sender or the recipient of the stream", - ); - }); - });*/ - }); - - describe("when the stream does not exist", () => { - const recipient = bob; - //const opts = { from: recipient }; - - it("reverts", async () => { - const streamId = new BigNumber(419863); - await truffleAssert.reverts(_this.sablier.cancelStream({ streamId }), "stream does not exist"); - }); - }); -} - -module.exports = shouldBehaveLikeERC1620CancelStream; diff --git a/tests/sablier/effects/stream/CreateStream.js b/tests/sablier/effects/stream/CreateStream.js deleted file mode 100644 index 393fa007..00000000 --- a/tests/sablier/effects/stream/CreateStream.js +++ /dev/null @@ -1,331 +0,0 @@ -//const { dappConstants } = require("@sablier/dev-utils"); -const project_root = process.cwd(); -const { dappConstants } = require(project_root + "/src/sablier/dev-utils"); -const BigNumber = require("bignumber.js"); -const dayjs = require("dayjs"); -const truffleAssert = require("truffle-assertions"); -const beproAssert = require(project_root + "/src/utils/beproAssert"); -import Numbers from "../../../../build/utils/Numbers"; - -const { - STANDARD_RATE_PER_SECOND, - STANDARD_SALARY, - STANDARD_TIME_OFFSET, - STANDARD_TIME_DELTA, - ZERO_ADDRESS, -} = dappConstants; - -function shouldBehaveLikeERC1620Stream(_this) { //alice, bob) { - const alice = _this.alice; - const bob = _this.bob; - const sender = alice; - //const opts = { from: sender }; - const now = new BigNumber(dayjs().unix()); - - describe("when not paused", () => { - describe("when the recipient is valid", () => { - const recipient = bob; - - describe("when the token contract is erc20 compliant", () => { - describe("when the sablier contract has enough allowance", () => { - beforeEach(async () => { - await _this.token.approve({ address: _this.sablier.getAddress(), amount: STANDARD_SALARY.toString(10) }); - }); - - describe("when the sender has enough tokens", () => { - describe("when the deposit is valid", () => { - const deposit = STANDARD_SALARY.toString(10); - - describe("when the start time is after block.timestamp", () => { - describe("when the stop time is after the start time", () => { - const startTime = now.plus(STANDARD_TIME_OFFSET); - const stopTime = startTime.plus(STANDARD_TIME_DELTA); - - it("creates the stream", async () => { - const result = await _this.sablier.createStream({ - recipient, - deposit, - tokenAddress: _this.token.getAddress(), - startTime, - stopTime, - }); - const streamId = Number(result.events.CreateStream.returnValues.streamId); - console.log('---CreateStream.streamId: ', streamId); - const streamObject = await _this.sablier.getStream({ streamId }); - streamObject.sender.should.be.equal(sender); - streamObject.recipient.should.be.equal(recipient); - streamObject.deposit.should.be.bignumber.equal(deposit); - streamObject.tokenAddress.should.be.equal(_this.token.getAddress()); - streamObject.startTime.should.be.bignumber.equal(startTime); - streamObject.stopTime.should.be.bignumber.equal(stopTime); - streamObject.remainingBalance.should.be.bignumber.equal(deposit); - streamObject.ratePerSecond.should.be.bignumber.equal(STANDARD_RATE_PER_SECOND); - }); - - it("transfers the tokens to the contract", async () => { - const balance = await _this.token.balanceOf(sender); - await _this.sablier.createStream({ recipient, deposit, tokenAddress: _this.token.getAddress(), startTime, stopTime }); - const newBalance = await _this.token.balanceOf(sender); - ///TODO: float precision comparison - ///newBalance.should.be.bignumber.equal((new BigNumber(balance)).minus(STANDARD_SALARY)); - }); - - it("increases the stream next stream id", async () => { - const nextStreamId = await _this.sablier.nextStreamId(); - await _this.sablier.createStream({ recipient, deposit, tokenAddress: _this.token.getAddress(), startTime, stopTime }); - const newNextStreamId = await _this.sablier.nextStreamId(); - newNextStreamId.should.be.bignumber.equal((new BigNumber(nextStreamId)).plus(1)); - }); - - it("emits a stream event", async () => { - const result = await _this.sablier.createStream({ - recipient, - deposit, - tokenAddress: _this.token.getAddress(), - startTime, - stopTime, - }); - //truffleAssert.eventEmitted(result, "CreateStream"); - beproAssert.eventEmitted(result, "CreateStream"); - }); - }); - - describe("when the stop time is not after the start time", () => { - let startTime; - let stopTime; - - beforeEach(async () => { - startTime = now.plus(STANDARD_TIME_OFFSET); - stopTime = startTime; - }); - - it("reverts", async () => { - await truffleAssert.reverts( - _this.sablier.createStream({ recipient, deposit, tokenAddress: _this.token.getAddress(), startTime, stopTime }), - "stop time before the start time", - ); - }); - }); - }); - - describe("when the start time is not after block.timestamp", () => { - let startTime; - let stopTime; - - beforeEach(async () => { - startTime = now.minus(STANDARD_TIME_OFFSET); - stopTime = startTime.plus(STANDARD_TIME_DELTA); - }); - - it("reverts", async () => { - await truffleAssert.reverts( - _this.sablier.createStream({ recipient, deposit, tokenAddress: _this.token.getAddress(), startTime, stopTime }), - "start time before block.timestamp", - ); - }); - }); - }); - - describe("when the deposit is not valid", () => { - const startTime = now.plus(STANDARD_TIME_OFFSET); - const stopTime = startTime.plus(STANDARD_TIME_DELTA); - - describe("when the deposit is zero", () => { - const deposit = new BigNumber(0).toString(10); - - it("reverts", async () => { - await truffleAssert.reverts( - _this.sablier.createStream({ recipient, deposit, tokenAddress: _this.token.getAddress(), startTime, stopTime }), - "deposit is zero", - ); - }); - }); - - describe("when the deposit is smaller than the time delta", () => { - //const deposit = STANDARD_TIME_DELTA.minus(1).toString(10); - const deposit = Numbers.fromDecimals(STANDARD_TIME_DELTA.minus(1), dappConstants.TOKEN_DECIMALS); - - it("reverts", async () => { - await truffleAssert.reverts( - _this.sablier.createStream({ recipient, deposit, tokenAddress: _this.token.getAddress(), startTime, stopTime }), - "deposit smaller than time delta", - ); - }); - }); - - describe("when the deposit is not a multiple of the time delta", () => { - //const deposit = STANDARD_SALARY.plus(5).toString(10); - const deposit = Numbers.fromDecimals(STANDARD_SALARY.plus(5), dappConstants.TOKEN_DECIMALS); - - it("reverts", async () => { - await truffleAssert.reverts( - _this.sablier.createStream({ recipient, deposit, tokenAddress: _this.token.getAddress(), startTime, stopTime }), - "deposit not multiple of time delta", - ); - }); - }); - }); - }); - - describe("when the sender does not have enough tokens", () => { - const deposit = STANDARD_SALARY.multipliedBy(2).toString(10); - const startTime = now.plus(STANDARD_TIME_OFFSET); - const stopTime = startTime.plus(STANDARD_TIME_DELTA); - - it("reverts", async () => { - await truffleAssert.reverts( - _this.sablier.createStream({ recipient, deposit, tokenAddress: _this.token.getAddress(), startTime, stopTime }), - truffleAssert.ErrorType.REVERT, - ); - }); - }); - }); - - describe("when the sablier contract does not have enough allowance", () => { - let startTime; - let stopTime; - - beforeEach(async () => { - startTime = now.plus(STANDARD_TIME_OFFSET); - stopTime = startTime.plus(STANDARD_TIME_DELTA); - await _this.token.approve({ address: _this.sablier.getAddress(), amount: STANDARD_SALARY.minus(5).toString(10) }); - }); - - describe("when the sender has enough tokens", () => { - const deposit = STANDARD_SALARY.toString(10); - - it("reverts", async () => { - await truffleAssert.reverts( - _this.sablier.createStream({ recipient, deposit, tokenAddress: _this.token.getAddress(), startTime, stopTime }), - truffleAssert.ErrorType.REVERT, - ); - }); - }); - - describe("when the sender does not have enough tokens", () => { - const deposit = STANDARD_SALARY.multipliedBy(2).toString(10); - - it("reverts", async () => { - await truffleAssert.reverts( - _this.sablier.createStream({ recipient, deposit, tokenAddress: _this.token.getAddress(), startTime, stopTime }), - truffleAssert.ErrorType.REVERT, - ); - }); - }); - }); - }); - - describe("when the token contract is not erc20", () => { - const deposit = STANDARD_SALARY.toString(10); - let startTime; - let stopTime; - - beforeEach(async () => { - startTime = now.plus(STANDARD_TIME_OFFSET); - stopTime = startTime.plus(STANDARD_TIME_DELTA); - }); - - /*describe("when the token contract is non-compliant", () => { - beforeEach(async () => { - await _this.nonStandardERC20Token.nonStandardApprove( - _this.sablier.getAddress(), - STANDARD_SALARY.toString(10), - ); - }); - - it("reverts", async () => { - await truffleAssert.reverts( - _this.sablier.createStream({ - recipient, - deposit, - tokenAddress: _this.nonStandardERC20Token.getAddress(), - startTime, - stopTime, - }), - truffleAssert.ErrorType.REVERT, - ); - }); - });*/ - - describe("when the token contract is the zero address", () => { - it("reverts", async () => { - await truffleAssert.reverts( - _this.sablier.createStream({ recipient, deposit, tokenAddress: ZERO_ADDRESS, startTime, stopTime }), - truffleAssert.ErrorType.REVERT, - ); - }); - }); - }); - }); - - describe("when the recipient is the caller itself", () => { - const recipient = sender; - const deposit = STANDARD_SALARY.toString(10); - const startTime = now.plus(STANDARD_TIME_OFFSET); - const stopTime = startTime.plus(STANDARD_TIME_DELTA); - - it("reverts", async () => { - await truffleAssert.reverts( - _this.sablier.createStream({ recipient, deposit, tokenAddress: _this.token.getAddress(), startTime, stopTime }), - "stream to the caller", - ); - }); - }); - - describe("when the recipient is the contract itself", () => { - const deposit = STANDARD_SALARY.toString(10); - const startTime = now.plus(STANDARD_TIME_OFFSET); - const stopTime = startTime.plus(STANDARD_TIME_DELTA); - - it("reverts", async () => { - // Can't be defined in the context above because "_this.sablier" is undefined there - const recipient = _this.sablier.getAddress(); - - await truffleAssert.reverts( - _this.sablier.createStream({ recipient, deposit, tokenAddress: _this.token.getAddress(), startTime, stopTime }), - "stream to the contract itself", - ); - }); - }); - - describe("when the recipient is the zero address", () => { - const recipient = ZERO_ADDRESS; - const deposit = STANDARD_SALARY.toString(10); - const startTime = now.plus(STANDARD_TIME_OFFSET); - const stopTime = startTime.plus(STANDARD_TIME_DELTA); - - it("reverts", async () => { - await truffleAssert.reverts( - _this.sablier.createStream({ recipient, deposit, tokenAddress: _this.token.getAddress(), startTime, stopTime }), - "stream to the zero address", - ); - }); - }); - }); - - describe("when paused", () => { - const recipient = bob; - const deposit = STANDARD_SALARY.toString(10); - const startTime = now.plus(STANDARD_TIME_OFFSET); - const stopTime = startTime.plus(STANDARD_TIME_DELTA); - - beforeEach(async () => { - // Note that `sender` coincides with the owner of the contract - await _this.sablier.pause(); - }); - - it("reverts", async () => { - await truffleAssert.reverts( - _this.sablier.createStream({ recipient, deposit, tokenAddress: _this.token.getAddress(), startTime, stopTime }), - "Pausable: paused", - ); - }); - - afterEach(async () => { - // Note that `sender` coincides with the owner of the contract - await _this.sablier.unpause(); - }); - }); -} - -module.exports = shouldBehaveLikeERC1620Stream; diff --git a/tests/sablier/effects/stream/WithdrawFromStream.js b/tests/sablier/effects/stream/WithdrawFromStream.js deleted file mode 100644 index 5006005e..00000000 --- a/tests/sablier/effects/stream/WithdrawFromStream.js +++ /dev/null @@ -1,233 +0,0 @@ -//const { dappConstants, mochaContexts } = require("@sablier/dev-utils"); -const project_root = process.cwd(); -const { dappConstants, mochaContexts } = require(project_root + "/src/sablier/dev-utils"); -const BigNumber = require("bignumber.js"); -const dayjs = require("dayjs"); -const truffleAssert = require("truffle-assertions"); -const beproAssert = require(project_root + "/src/utils/beproAssert"); - -const { contextForStreamDidEnd, contextForStreamDidStartButNotEnd } = mochaContexts; -const { FIVE_UNITS, STANDARD_SALARY, STANDARD_SCALE, STANDARD_TIME_OFFSET, STANDARD_TIME_DELTA } = dappConstants; - -let streamId; -let recipient; -let deposit; -let sender; - -function runTests(_this) { - describe("when not paused", () => { - describe("when the withdrawal amount is higher than 0", () => { - describe("when the stream did not start", () => { - const withdrawalAmount = FIVE_UNITS.toString(10); - - it("reverts", async () => { - await truffleAssert.reverts( - _this.sablier.withdrawFromStream({ streamId, amount: withdrawalAmount }), - "amount exceeds the available balance", - ); - }); - }); - - contextForStreamDidStartButNotEnd(() => { - describe("when the withdrawal amount does not exceed the available balance", () => { - const withdrawalAmount = FIVE_UNITS.toString(10); - - it("withdraws from the stream", async () => { - const balance = await _this.token.balanceOf(recipient); - await _this.sablier.withdrawFromStream({ streamId, amount: withdrawalAmount }); - const newBalance = await _this.token.balanceOf(recipient); - newBalance.should.be.bignumber.equal(new BigNumber(balance).plus(FIVE_UNITS)); - }); - - it("emits a withdrawfromstream event", async () => { - const result = await _this.sablier.withdrawFromStream({ streamId, amount: withdrawalAmount }); - //truffleAssert.eventEmitted(result, "WithdrawFromStream"); - beproAssert.eventEmitted(result, "WithdrawFromStream"); - }); - - it("decreases the stream balance", async () => { - const balance = await _this.sablier.balanceOf({ streamId, who: recipient }); - await _this.sablier.withdrawFromStream({ streamId, amount: withdrawalAmount }); - const newBalance = await _this.sablier.balanceOf({ streamId, who: recipient }); - // Intuitively, one may say we don't have to tolerate the block time variation here. - // However, the Sablier balance for the recipient can only go up from the bottom - // low of `balance` - `amount`, due to uncontrollable runtime costs. - newBalance.should.tolerateTheBlockTimeVariation(new BigNumber(balance).minus(withdrawalAmount), STANDARD_SCALE); - }); - }); - - describe("when the withdrawal amount exceeds the available balance", () => { - const withdrawalAmount = FIVE_UNITS.multipliedBy(2).toString(10); - - it("reverts", async () => { - await truffleAssert.reverts( - _this.sablier.withdrawFromStream({ streamId, amount: withdrawalAmount }), - "amount exceeds the available balance", - ); - }); - }); - }); - - contextForStreamDidEnd(() => { - describe("when the withdrawal amount does not exceed the available balance", () => { - describe("when the balance is not withdrawn in full", () => { - const withdrawalAmount = STANDARD_SALARY.dividedBy(2).toString(10); - - it("withdraws from the stream", async () => { - const balance = await _this.token.balanceOf(recipient); - await _this.sablier.withdrawFromStream({ streamId, amount: withdrawalAmount }); - const newBalance = await _this.token.balanceOf(recipient); - newBalance.should.be.bignumber.equal(new BigNumber(balance).plus(withdrawalAmount)); - }); - - it("emits a withdrawfromstream event", async () => { - const result = await _this.sablier.withdrawFromStream({ streamId, amount: withdrawalAmount }); - //truffleAssert.eventEmitted(result, "WithdrawFromStream"); - beproAssert.eventEmitted(result, "WithdrawFromStream"); - }); - - it("decreases the stream balance", async () => { - const balance = await _this.sablier.balanceOf({ streamId, who: recipient }); - await _this.sablier.withdrawFromStream({ streamId, amount: withdrawalAmount }); - const newBalance = await _this.sablier.balanceOf({ streamId, who: recipient }); - newBalance.should.be.bignumber.equal(new BigNumber(balance).minus(withdrawalAmount)); - }); - }); - - describe("when the balance is withdrawn in full", () => { - const withdrawalAmount = STANDARD_SALARY.toString(10); - - it("withdraws from the stream", async () => { - const balance = await _this.token.balanceOf(recipient); - await _this.sablier.withdrawFromStream({ streamId, amount: withdrawalAmount }); - const newBalance = await _this.token.balanceOf(recipient); - newBalance.should.be.bignumber.equal(new BigNumber(balance).plus(withdrawalAmount)); - }); - - it("emits a withdrawfromstream event", async () => { - const result = await _this.sablier.withdrawFromStream({ streamId, amount: withdrawalAmount }); - //truffleAssert.eventEmitted(result, "WithdrawFromStream"); - beproAssert.eventEmitted(result, "WithdrawFromStream"); - }); - - it("deletes the stream object", async () => { - await _this.sablier.withdrawFromStream({ streamId, amount: withdrawalAmount }); - await truffleAssert.reverts(_this.sablier.getStream({ streamId }), "stream does not exist"); - }); - }); - }); - - describe("when the withdrawal amount exceeds the available balance", () => { - const withdrawalAmount = STANDARD_SALARY.plus(FIVE_UNITS).toString(10); - - it("reverts", async () => { - await truffleAssert.reverts( - _this.sablier.withdrawFromStream({ streamId, amount: withdrawalAmount }), - "amount exceeds the available balance", - ); - }); - }); - }); - }); - - describe("when the withdrawal amount is zero", () => { - const withdrawalAmount = new BigNumber(0).toString(10); - - it("reverts", async () => { - await truffleAssert.reverts( - _this.sablier.withdrawFromStream({ streamId, amount: withdrawalAmount }), - "amount is zero", - ); - }); - }); - }); - - describe("when paused", () => { - const withdrawalAmount = FIVE_UNITS.toString(10); - - beforeEach(async () => { - // Note that `sender` coincides with the owner of the contract - await _this.sablier.pause(); //({ from: _this.sender }); - }); - - it("reverts", async () => { - await truffleAssert.reverts( - _this.sablier.withdrawFromStream({ streamId, amount: withdrawalAmount }), - "Pausable: paused", - ); - }); - - afterEach(async () => { - // Note that `sender` coincides with the owner of the contract - await _this.sablier.unpause(); //({ from: _this.sender }); - }); - }); -} - -function shouldBehaveLikeERC1620WithdrawFromStream(_this) { //alice, bob, eve) { - const alice = _this.alice; - const bob = _this.bob; - const eve = _this.eve; - const now = new BigNumber(dayjs().unix()); - - describe("when the stream exists", () => { - const startTime = now.plus(STANDARD_TIME_OFFSET); - const stopTime = startTime.plus(STANDARD_TIME_DELTA); - - beforeEach(async () => { - sender = alice; - recipient = bob; - deposit = STANDARD_SALARY.toString(10); - //const opts = { from: this.sender }; - await _this.token.approve({ address: _this.sablier.getAddress(), amount: deposit }); - const result = await _this.sablier.createStream({ - recipient, - deposit, - tokenAddress: _this.token.getAddress(), - startTime, - stopTime, - }); - streamId = Number(result.events.CreateStream.returnValues.streamId); - console.log('---WithdrawFromStream.streamId: ', streamId); - }); - - describe("when the caller is the sender of the stream", () => { - beforeEach(() => { - //this.opts = { from: this.sender }; - }); - - runTests(_this); - }); - - /*describe("when the caller is the recipient of the stream", () => { - beforeEach(() => { - this.opts = { from: this.recipient }; - }); - - runTests(); - });*/ - - /*describe("when the caller is not the sender or the recipient of the stream", () => { - const opts = { from: eve }; - - it("reverts", async () => { - await truffleAssert.reverts( - this.sablier.withdrawFromStream(this.streamId, FIVE_UNITS, opts), - "caller is not the sender or the recipient of the stream", - ); - }); - });*/ - }); - - describe("when the stream does not exist", () => { - const recipient = bob; - //const opts = { from: recipient }; - - it("reverts", async () => { - const streamId = new BigNumber(419863); - await truffleAssert.reverts(_this.sablier.withdrawFromStream({ streamId, amount: FIVE_UNITS }), "stream does not exist"); - }); - }); -} - -module.exports = shouldBehaveLikeERC1620WithdrawFromStream; diff --git a/tests/sablier/sablier.behavior.js b/tests/sablier/sablier.behavior.js deleted file mode 100644 index f33d6fa8..00000000 --- a/tests/sablier/sablier.behavior.js +++ /dev/null @@ -1,107 +0,0 @@ -//const { devConstants } = require("@sablier/dev-utils"); -const project_root = process.cwd(); -const { devConstants } = require(project_root + "/src/sablier/dev-utils"); - -const truffleAssert = require("truffle-assertions"); - -const shouldBehaveLikeUpdateFee = require("./admin/UpdateFee"); -const shouldBehaveLikeTakeEarnings = require("./admin/TakeEarnings"); - -const shouldBehaveLikeDeltaOf = require("./view/DeltaOf"); -const shouldBehaveLikeBalanceOf = require("./view/BalanceOf"); -const shouldBehaveLikeGetStream = require("./view/GetStream"); -const shouldBehaveLikeGetCompoundingStream = require("./view/GetCompoundingStream"); -const shouldBehaveLikeInterestOf = require("./view/InterestOf"); -const shouldBehaveLikeGetEarnings = require("./view/GetEarnings"); -const shouldBehaveLikeIsCompoundingStream = require("./view/IsCompoundingStream"); - -const shouldBehaveLikeERC1620CreateStream = require("./effects/stream/CreateStream"); -const shouldBehaveLikeCreateCompoundingStream = require("./effects/compoundingStream/CreateCompoundingStream"); -const shouldBehaveLikeERC1620WithdrawFromStream = require("./effects/stream/WithdrawFromStream"); -// eslint-disable-next-line max-len -const shouldBehaveLikeWithdrawFromCompoundingStream = require("./effects/compoundingStream/WithdrawFromCompoundingStream"); -const shouldBehaveLikeERC1620CancelStream = require("./effects/stream/CancelStream"); -const shouldBehaveLikeCancelCompoundingStream = require("./effects/compoundingStream/CancelCompoundingStream"); - -//const Sablier = artifacts.require("./Sablier.sol"); -//const { ZERO_ADDRESS } = devConstants; - -function shouldBehaveLikeSablier(_this) { //alice, bob, carol, eve) { -//const shouldBehaveLikeSablier = (_this) => { - /*describe("initialization", function() { - it("reverts when the cTokenManager contract is the zero address", async function() { - const opts = { from: alice }; - await truffleAssert.reverts(Sablier.new(ZERO_ADDRESS, opts), "cTokenManager contract is the zero address"); - }); - });*/ - //const sablier = _this.sablier; - //const erc20Contract = _this.erc20Contract; - - describe("admin functions", () => { - describe("updateFee", () => { - shouldBehaveLikeUpdateFee(_this); //alice, eve); - }); - - describe("takeEarnings", () => { - shouldBehaveLikeTakeEarnings(_this); //alice, bob, eve); - }); - }); - - describe("view functions", () => { //function() { - describe("getStream", () => { //function() { - shouldBehaveLikeGetStream(_this); //alice); - }); - - describe("deltaOf", () => { //function() { - shouldBehaveLikeDeltaOf(_this); //alice, bob); - }); - - describe("balanceOf", () => { //function() { - shouldBehaveLikeBalanceOf(_this); //alice, bob, carol); - }); - - describe("isCompoundingStream", () => { //function() { - shouldBehaveLikeIsCompoundingStream(_this); //alice, bob); - }); - - describe("getCompoundingStream", () => { //function() { - shouldBehaveLikeGetCompoundingStream(_this); //alice, bob); - }); - - describe("interestOf", () => { //function() { - shouldBehaveLikeInterestOf(_this); //alice, bob); - }); - - describe("getEarnings", () => { //function() { - shouldBehaveLikeGetEarnings(_this); //alice); - }); - }); - - describe("effects & interactions functions", () => { //function() { - describe("createStream", () => { //function() { - shouldBehaveLikeERC1620CreateStream(_this); //alice, bob); - }); - - describe("createCompoundingStream", () => { //function() { - shouldBehaveLikeCreateCompoundingStream(_this); //alice, bob); - }); - - describe("withdrawFromStream", () => { //function() { - shouldBehaveLikeERC1620WithdrawFromStream(_this); //alice, bob, eve); - }); - - describe("withdrawFromCompoundingStream", () => { //function() { - shouldBehaveLikeWithdrawFromCompoundingStream(_this); //alice, bob, eve); - }); - - describe("cancelStream", () => { //function() { - shouldBehaveLikeERC1620CancelStream(_this); //alice, bob, eve); - }); - - describe("cancelCompoundingStream", () => { //function() { - shouldBehaveLikeCancelCompoundingStream(_this); //alice, bob, eve); - }); - }); -} - -module.exports = shouldBehaveLikeSablier; diff --git a/tests/sablier/sablier.js b/tests/sablier/sablier.js deleted file mode 100644 index a36a6993..00000000 --- a/tests/sablier/sablier.js +++ /dev/null @@ -1,246 +0,0 @@ -//const { devConstants } = require("@sablier/dev-utils"); -//const project_root = process.cwd(); -const { dappConstants, devConstants } = require("../../src/sablier/dev-utils"); - -import { expect, assert } from "chai"; -import moment from "moment"; -import delay from "delay"; -import { mochaAsync, mochaContextAsync } from "../utils"; -import { ERC20Contract, Sablier } from "../../build"; -import CERC20Mock from '../../build/models/mocks/CERC20Mock'; -import ERC20Mock from '../../build/models/mocks/ERC20Mock'; -import Numbers from "../../build/utils/Numbers"; - -const BigNumber = require("bignumber.js"); -const truffleAssert = require("truffle-assertions"); - - -/*const { chaiPlugin } = require(project_root + "/src/sablier/dev-utils"); -const chai = require("chai"); -const chaiBigNumber = require("chai-bignumber"); - -chai.should(); -chai.use(chaiBigNumber(BigNumber)); -chai.use(chaiPlugin); -*/ - -import Web3Connection from "../../build/Web3Connection"; - -const shouldBehaveLikeSablier = require("./sablier.behavior"); -//const shouldBehaveLikeUpdateFee = require("./admin/UpdateFee"); - -const { INITIAL_EXCHANGE_RATE, STANDARD_SALARY } = dappConstants; -const { STANDARD_SABLIER_FEE } = dappConstants; - -var deployed_tokenAddress; -const ethAmount = 0.1; -let contractAddress = "0x949d274F63127bEd53e21Ed1Dd83dD6ACAfF7f64"; -// this is already deployed on rinkeby network for testing -// var deployed_contractAddress = '0xf7177df4a4797304cf59aa1e2dd4718cb390cbad'; -let deployed_contractAddress = "0xeAE93A3C4d74C469B898C345DEAD456C8Db06194"; - -//const lockSeconds = 30; // lock tokens for x amount of seconds -//let endDate = moment().add(lockSeconds, "seconds"); -const testConfig = { - test: true, - localtest: true, //ganache local blockchain -}; - -//let _this = {}; -//const web3Conn = new Web3Connection(testConfig); -global.web3 = undefined;// = web3Conn.web3; -//const web3 = web3Conn.web3; -//console.log('---sablier.web3', web3Conn); - - -const { chaiPlugin } = require("../../src/sablier/dev-utils"); -const traveler = require("ganache-time-traveler"); - -//const BigNumber = require("bignumber.js"); -const chai = require("chai"); -const chaiBigNumber = require("chai-bignumber"); - -chai.should(); -chai.use(chaiBigNumber(BigNumber)); -chai.use(chaiPlugin); - - -let snapshotId; - - - -context("Sablier contract", () => { -//const setup = () => { - let _this = {}; - let alice; - const bob = "0x000000000000000000000000000000000000000A"; - const carol = "0x000000000000000000000000000000000000000B"; - const eve = "0x000000000000000000000000000000000000000C"; - - let erc20Contract; - let sablier; - let userAddress; - - - /// works fine - //let c = 0; - //beforeEach(async () => { - // console.log('+++sablier.beforeEach.', c); - // c = c + 1; - //}); - /// - - before(async () => { - //const snapshot = await traveler.takeSnapshot(); - //snapshotId = snapshot.result; - console.log('+++sablier.before.'); - //this.test = 3; - }); - - it( - "should start the Sablier contract", - async () => {//async function() { - sablier = new Sablier(testConfig); - expect(sablier).to.not.equal(null); - } - ); - - it( - "should deploy Sablier Contract", - async () => {//async function () { - // Create Contract - /*let testConfig2 = { ...testConfig, tokenAddress: deployed_tokenAddress }; - console.log( - "---should deploy sablier.testConfig2: " + JSON.stringify(testConfig2) - );*/ - sablier = new Sablier(testConfig); - // Deploy - let res = await sablier.deploy(); - await sablier.__assert(); - contractAddress = sablier.getAddress(); - deployed_contractAddress = sablier.getAddress(); - console.log( - "Deployed Sablier address: " + deployed_contractAddress - ); - expect(res).to.not.equal(false); - //_this.sablier = sablier; - //_this.userAddress = await sablier.getUserAddress(); - //_this.alice = _this.userAddress; - console.log('---sablier.userAddress: ', await sablier.getUserAddress()); - } - ); - - it( - "Sablier Contract should have expected initial values", - async () => {//async function () { - console.log("***init.sablier.bp0"); - const res = await sablier.nextStreamId(); - //const res2 = await sablier.fee().mantissa; - console.log("***init.sablier.bp1"); - console.log("***init.nextStreamId : ", res); - //console.log("***init.fee [0 to 100] : " + res2); - expect(Number(res)).to.equal(1); //"nextStreamId should be one by default"); - //expect(Number(res2)).to.equal(0); - } - ); - - - - //after('Sablier after hook', async () => { - describe('Sablier shouldBehaveLikeSablier...', async () => { - - beforeEach('Sablier beforeEach hook', async () => { - - //this.token = await ERC20Mock.new(opts); - //await this.token.mint(this.userAddress, STANDARD_SALARY.multipliedBy(3).toString(10), opts); - - _this.token = new ERC20Mock(testConfig); - expect(_this.token).to.not.equal(null); - console.log('---sablier.before hook.bp0'); - let res = await _this.token.deploy(); - console.log('---sablier.before hook.bp1'); - await _this.token.__assert(); - console.log('---sablier.before hook.bp2'); - userAddress = await _this.token.getUserAddress(); - _this.userAddress = userAddress; - await _this.token.mint({ to: userAddress, amount: STANDARD_SALARY.multipliedBy(100).toString(10) }); - - console.log('---sablier.ERC20Mock.balance: ', await _this.token.balanceOf(userAddress)); - console.log('---sablier.before hook.bp3'); - console.log('---STANDARD_SALARY: ', STANDARD_SALARY); - - - sablier = new Sablier(testConfig); - //userAddress = await sablier.getUserAddress(); //local test with ganache - alice = userAddress; - - res = await sablier.deploy(); - await sablier.__assert(); - contractAddress = sablier.getAddress(); - deployed_contractAddress = sablier.getAddress(); - console.log("Deployed Sablier address: " + deployed_contractAddress); - expect(res).to.not.equal(false); - - /// set global web3 object for ganache time traveler testing - web3 = sablier.web3Connection.web3; - console.log('---sablier.before hook: ', await userAddress); - console.log('---sablier.before hook.web3: ', (web3 != null)); - - _this.sablier = sablier; - _this.userAddress = userAddress; - //_this.testme = 7; - _this.alice = alice; - _this.bob = bob; - _this.carol = carol; - _this.eve = eve; - - - const cTokenDecimals = 8; - //this.cToken = await CERC20Mock.new(this.token.address, INITIAL_EXCHANGE_RATE.toString(10), cTokenDecimals, opts); - //await this.token.approve(this.cToken.address, STANDARD_SALARY.toString(10), opts); - //await this.cToken.mint(STANDARD_SALARY.toString(10), opts); - let testConfig2 = { ...testConfig, tokenAddress: _this.token.getAddress() }; - _this.cToken = new CERC20Mock(testConfig2); - console.log('---cToken.bp0.devConstants.INITIAL_EXCHANGE_RATE: ', devConstants.INITIAL_EXCHANGE_RATE.toString(10)); - expect(_this.cToken).to.not.equal(null); - res = await _this.cToken.deploy({ - //underlying: _this.token.getAddress(), - initialExchangeRate: devConstants.INITIAL_EXCHANGE_RATE.toString(10), - decimals: cTokenDecimals, - }); - //console.log('---cToken.bp1'); - await _this.cToken.__assert(); - //console.log('---cToken.bp2'); - await _this.token.approve({ address: _this.cToken.getAddress(), amount: STANDARD_SALARY.toString(10) }); - //console.log('---cToken.bp3.devConstants.STANDARD_SALARY: ', devConstants.STANDARD_SALARY.toString(10)); - await _this.cToken.mint(STANDARD_SALARY.toString(10)); //devConstants.STANDARD_SALARY.toString(10)); - //console.log('---cToken.bp4'); - - //this.nonStandardERC20Token = await NonStandardERC20.new(opts); - //this.nonStandardERC20Token.nonStandardMint(alice, STANDARD_SALARY.toString(10), opts); - - //this.cTokenManager = await CTokenManager.new(opts); - //this.sablier = await Sablier.new(this.cTokenManager.address, opts); - }); - - - //shouldBehaveLikeUpdateFee(_this); //alice, bob, carol, eve); - - it("Sablier shouldBehaveLikeSablier", async () => { - shouldBehaveLikeSablier(_this); - console.log('---Sablier shouldBehaveLikeSablier finished.'); - }); - - }); - - - after(async () => { - //await traveler.revertToSnapshot(snapshotId); - console.log('+++sablier.after.'); - }); -}); - -/*context("Sablier contract", () => { - setup(); - shouldBehaveLikeSablier(_this); -});*/ diff --git a/tests/sablier/view/BalanceOf.js b/tests/sablier/view/BalanceOf.js deleted file mode 100644 index 75459728..00000000 --- a/tests/sablier/view/BalanceOf.js +++ /dev/null @@ -1,119 +0,0 @@ -//const { devConstants, mochaContexts } = require("@sablier/dev-utils"); -const project_root = process.cwd(); -const { dappConstants, devConstants, mochaContexts } = require(project_root + "/src/sablier/dev-utils"); -const BigNumber = require("bignumber.js"); -const dayjs = require("dayjs"); -const truffleAssert = require("truffle-assertions"); -import Numbers from "../../../build/utils/Numbers"; - -const { FIVE_UNITS, STANDARD_SALARY, STANDARD_SCALE, STANDARD_TIME_OFFSET, STANDARD_TIME_DELTA } = dappConstants; -const { contextForStreamDidEnd, contextForStreamDidStartButNotEnd } = mochaContexts; - -import { expect, assert } from "chai"; - -function shouldBehaveLikeBalanceOf(_this) { //alice, bob, carol) { - const sender = _this.alice; - //const opts = { from: sender }; - const now = new BigNumber(dayjs().unix()); - - describe("when the stream exists", () => { //function() { - const alice = _this.alice; - const bob = _this.bob; - const carol = _this.carol; - - console.log('---sablier.BalanceOf. alice: ', alice); - - let streamId; - const recipient = bob; - console.log('---sablier.BalanceOf. recipient: ', recipient); - const deposit = STANDARD_SALARY.toString(10); - const startTime = now.plus(STANDARD_TIME_OFFSET); - const stopTime = startTime.plus(STANDARD_TIME_DELTA); - console.log('---sablier.BalanceOf.startTime: ', startTime); - - beforeEach(async () => { //async function() { - console.log('---sablier.balanceOf.beforeEach.bp0'); - await _this.token.approve({ address: _this.sablier.getAddress(), amount: deposit }); - console.log('---sablier.balanceOf.beforeEach.bp1'); - const result = await _this.sablier.createStream({ recipient, deposit, tokenAddress: _this.token.getAddress(), startTime, stopTime }); - // streamId = Number(result.logs[0].args.streamId); - streamId = Number(result.events.CreateStream.returnValues.streamId); - console.log('---BalanceOf.streamId: ', streamId); - }); - - describe("when the stream did not start", () => { //function() { - it("returns the whole deposit for the sender of the stream", async () => { //async function() { - //console.log('---sablier.balanceOf.sender: ', sender); - const balance = await _this.sablier.balanceOf({ streamId, who: sender }); - //console.log('---sablier.balanceOf.balance: ', balance); - balance.should.be.bignumber.equal(deposit); - }); - - it("returns 0 for the recipient of the stream", async () => { //async function() { - const balance = await _this.sablier.balanceOf({ streamId, who: recipient }); - balance.should.be.bignumber.equal(new BigNumber(0)); - }); - - it("returns 0 for anyone else", async () => { //async function() { - const balance = await _this.sablier.balanceOf({ streamId, who: carol }); - balance.should.be.bignumber.equal(new BigNumber(0)); - }); - }); - - contextForStreamDidStartButNotEnd( () => { - const streamedAmount = FIVE_UNITS.toString(10); - - it("returns the pro rata balance for the sender of the stream", async () => { - const balance = await _this.sablier.balanceOf({ streamId, who: sender }); - //console.log('---sablier.balanceOf.balance: ', balance); - //expect(balance.toString()).to.equal(STANDARD_SALARY.minus(streamedAmount).toString()); - /*const tolerateByAddition = false; - balance.should.tolerateTheBlockTimeVariation( - STANDARD_SALARY.minus(streamedAmount), - STANDARD_SCALE, - tolerateByAddition, - );*/ - const decimals = 18; - const devStreamedAmount = devConstants.FIVE_UNITS.toString(10); - expect(Numbers.toSmartContractDecimals(balance, decimals).toString()).to.equal( - Numbers.fromExponential(devConstants.STANDARD_SALARY.minus(devStreamedAmount)).toString()); - }); - - it("returns the pro rata balance for the recipient of the stream", async () => { - const balance = await _this.sablier.balanceOf({ streamId, who: recipient }); - balance.should.tolerateTheBlockTimeVariation(streamedAmount, STANDARD_SCALE); - }); - - it("returns 0 for anyone else", async () => { - const balance = await _this.sablier.balanceOf({ streamId, who: carol }); - balance.should.be.bignumber.equal(new BigNumber(0)); - }); - }); - - contextForStreamDidEnd( () => { - it("returns 0 for the sender of the stream", async () => { - const balance = await _this.sablier.balanceOf({ streamId, who: sender }); - balance.should.be.bignumber.equal(new BigNumber(0)); - }); - - it("returns the whole deposit for the recipient of the stream", async () => { - const balance = await _this.sablier.balanceOf({ streamId, who: recipient }); - balance.should.be.bignumber.equal(STANDARD_SALARY); - }); - - it("returns 0 for anyone else", async () => { - const balance = await _this.sablier.balanceOf({ streamId, who: carol }); - balance.should.be.bignumber.equal(new BigNumber(0)); - }); - }); - }); - - describe("when the stream does not exist", () => { - it("reverts", async () => { - const streamId = new BigNumber(419863); - await truffleAssert.reverts(_this.sablier.balanceOf({ streamId, who: sender }), "stream does not exist"); - }); - }); -} - -module.exports = shouldBehaveLikeBalanceOf; diff --git a/tests/sablier/view/DeltaOf.js b/tests/sablier/view/DeltaOf.js deleted file mode 100644 index 7f5576d5..00000000 --- a/tests/sablier/view/DeltaOf.js +++ /dev/null @@ -1,71 +0,0 @@ -//const { dappConstants, mochaContexts } = require("@sablier/dev-utils"); -const project_root = process.cwd(); -const { dappConstants, mochaContexts } = require(project_root + "/src/sablier/dev-utils"); -const BigNumber = require("bignumber.js"); -const dayjs = require("dayjs"); -const truffleAssert = require("truffle-assertions"); - -const { STANDARD_SALARY, STANDARD_TIME_OFFSET, STANDARD_TIME_DELTA } = dappConstants; -const { contextForStreamDidEnd, contextForStreamDidStartButNotEnd } = mochaContexts; - -import { expect, assert } from "chai"; - -function shouldBehaveLikeDeltaOf(_this) { //alice, bob) { - //const sender = alice; - //const opts = { from: sender }; - const now = new BigNumber(dayjs().unix()); - - describe("when the stream exists", () => { //function() { - let streamId; - const recipient = _this.bob; - const deposit = STANDARD_SALARY.toString(10); - const startTime = now.plus(STANDARD_TIME_OFFSET); - const stopTime = startTime.plus(STANDARD_TIME_DELTA); - - beforeEach(async () => { //async function() { - await _this.token.approve({ address: _this.sablier.getAddress(), amount: deposit }); - console.log('---DeltaOf.bp0'); - const result = await _this.sablier.createStream({ recipient, deposit, tokenAddress: _this.token.getAddress(), startTime, stopTime }); - //console.log('---DeltaOf.streamId.bp0: ', result); //.events[0].returnValues); - // streamId = Number(result.logs[0].args.streamId); - streamId = Number(result.events.CreateStream.returnValues.streamId); - console.log('---DeltaOf.streamId: ', streamId); - }); - - describe("when the stream did not start", () => { //function() { - it("returns 0", async () => { //async function() { - const delta = await _this.sablier.deltaOf({ streamId }); - delta.should.be.bignumber.equal(new BigNumber(0)); - //expect(delta).to.equal((0).toString()); - }); - }); - - contextForStreamDidStartButNotEnd(() => { - it("returns the time the number of seconds that passed since the start time", async () => { - const delta = await _this.sablier.deltaOf({ streamId }); - console.log('---DeltaOf.bp2'); - delta.should.bignumber.satisfy(function(num) { - //return num.isEqualTo(new BigNumber(5)) || num.isEqualTo(new BigNumber(5).plus(1)); - return new BigNumber(num).isEqualTo(new BigNumber(5)) || new BigNumber(num).isEqualTo(new BigNumber(5).plus(1)); - }); - console.log('---DeltaOf.bp3'); - }); - }); - - contextForStreamDidEnd(() => { - it("returns the difference between the stop time and the start time", async () => { - const delta = await _this.sablier.deltaOf({ streamId }); - delta.should.be.bignumber.equal(stopTime.minus(startTime)); - }); - }); - }); - - describe("when the stream does not exist", () => { - it("reverts", async () => { - const streamId = new BigNumber(419863); - await truffleAssert.reverts(_this.sablier.deltaOf({ streamId }), "stream does not exist"); - }); - }); -} - -module.exports = shouldBehaveLikeDeltaOf; diff --git a/tests/sablier/view/GetCompoundingStream.js b/tests/sablier/view/GetCompoundingStream.js deleted file mode 100644 index 8fc2a804..00000000 --- a/tests/sablier/view/GetCompoundingStream.js +++ /dev/null @@ -1,48 +0,0 @@ -//const { dappConstants } = require("@sablier/dev-utils"); -const project_root = process.cwd(); -const { dappConstants } = require(project_root + "/src/sablier/dev-utils"); -const BigNumber = require("bignumber.js"); -const dayjs = require("dayjs"); -const truffleAssert = require("truffle-assertions"); - -const { STANDARD_SALARY, STANDARD_TIME_OFFSET, STANDARD_TIME_DELTA } = dappConstants; - -function shouldBehaveLikeGetCompoundingStream(_this) { //alice, bob) { - const alice = _this.alice; - const bob = _this.bob; - const sender = alice; - //const opts = { from: sender }; - const now = new BigNumber(dayjs().unix()); - - describe("when the stream exists but is not compounding", () => { - let streamId; - const recipient = bob; - const deposit = STANDARD_SALARY.toString(10); - const startTime = now.plus(STANDARD_TIME_OFFSET); - const stopTime = startTime.plus(STANDARD_TIME_DELTA); - - beforeEach(async () => { - await _this.token.approve({ address: _this.sablier.getAddress(), amount: deposit }); - const result = await _this.sablier.createStream({ recipient, deposit, tokenAddress: _this.token.getAddress(), startTime, stopTime }); - //streamId = Number(result.logs[0].args.streamId); - streamId = Number(result.events.CreateStream.returnValues.streamId); - console.log('---GetCompoundingStream.streamId: ', streamId); - }); - - it("reverts", async () => { - await truffleAssert.reverts( - _this.sablier.getCompoundingStream({ streamId }), - "compounding stream does not exist", - ); - }); - }); - - describe("when the stream does not exist", () => { - it("reverts", async () => { - const streamId = new BigNumber(419863); - await truffleAssert.reverts(_this.sablier.getCompoundingStream({ streamId }), "stream does not exist"); - }); - }); -} - -module.exports = shouldBehaveLikeGetCompoundingStream; diff --git a/tests/sablier/view/GetEarnings.js b/tests/sablier/view/GetEarnings.js deleted file mode 100644 index e285e9a5..00000000 --- a/tests/sablier/view/GetEarnings.js +++ /dev/null @@ -1,15 +0,0 @@ -const truffleAssert = require("truffle-assertions"); - -function shouldBehaveLikeGetEarnings(_this) { //alice) { - const alice = _this.alice; - const sender = alice; - //const opts = { from: sender }; - - /*describe("when the ctoken is not whitelisted", () => { //function() { - it("reverts", async () => { //async function() { - await truffleAssert.reverts(_this.sablier.getEarnings({ tokenAddress: _this.token.getAddress() }), "token is not cToken"); - }); - });*/ -} - -module.exports = shouldBehaveLikeGetEarnings; diff --git a/tests/sablier/view/GetStream.js b/tests/sablier/view/GetStream.js deleted file mode 100644 index 7c45f4b1..00000000 --- a/tests/sablier/view/GetStream.js +++ /dev/null @@ -1,16 +0,0 @@ -const BigNumber = require("bignumber.js"); -const truffleAssert = require("truffle-assertions"); - -function shouldBehaveLikeGetStream(_this) { //alice) { - //const sender = alice; - //const opts = { from: sender }; - - describe("when the stream does not exist", () => { - it("reverts", async () => { - const streamId = new BigNumber(419863); - await truffleAssert.reverts(_this.sablier.getStream({ streamId }), "stream does not exist"); - }); - }); -} - -module.exports = shouldBehaveLikeGetStream; diff --git a/tests/sablier/view/InterestOf.js b/tests/sablier/view/InterestOf.js deleted file mode 100644 index ca056311..00000000 --- a/tests/sablier/view/InterestOf.js +++ /dev/null @@ -1,48 +0,0 @@ -//const { dappConstants } = require("@sablier/dev-utils"); -const project_root = process.cwd(); -const { dappConstants } = require(project_root + "/src/sablier/dev-utils"); -const BigNumber = require("bignumber.js"); -const dayjs = require("dayjs"); -const truffleAssert = require("truffle-assertions"); - -const { STANDARD_SALARY, STANDARD_TIME_OFFSET, STANDARD_TIME_DELTA } = dappConstants; - -function shouldBehaveLikeInterestOf(_this) { //alice, bob) { - const alice = _this.alice; - const bob = _this.bob; - const sender = alice; - const deposit = STANDARD_SALARY.toString(10); - //const opts = { from: sender }; - const now = new BigNumber(dayjs().unix()); - - describe("when the compounding stream does not exist", () => { - let streamId; - const recipient = bob; - const startTime = now.plus(STANDARD_TIME_OFFSET); - const stopTime = startTime.plus(STANDARD_TIME_DELTA); - - beforeEach(async () => { - await _this.token.approve({ address: _this.sablier.getAddress(), amount: deposit }); - const result = await _this.sablier.createStream({ recipient, deposit, tokenAddress: _this.token.getAddress(), startTime, stopTime }); - //streamId = Number(result.logs[0].args.streamId); - streamId = Number(result.events.CreateStream.returnValues.streamId); - console.log('---InterestOf.streamId: ', streamId); - }); - - it("returns 0", async () => { - const result = await _this.sablier.interestOf({ streamId, amount: deposit }); - result.senderInterest.should.be.bignumber.equal(new BigNumber(0)); - result.recipientInterest.should.be.bignumber.equal(new BigNumber(0)); - result.sablierInterest.should.be.bignumber.equal(new BigNumber(0)); - }); - }); - - describe("when the stream does not exist", () => { - it("reverts", async () => { - const streamId = new BigNumber(419863); - await truffleAssert.reverts(_this.sablier.interestOf({ streamId, amount: deposit }), "stream does not exist"); - }); - }); -} - -module.exports = shouldBehaveLikeInterestOf; diff --git a/tests/sablier/view/IsCompoundingStream.js b/tests/sablier/view/IsCompoundingStream.js deleted file mode 100644 index efb75005..00000000 --- a/tests/sablier/view/IsCompoundingStream.js +++ /dev/null @@ -1,85 +0,0 @@ -//const { dappConstants } = require("@sablier/dev-utils"); -const project_root = process.cwd(); -const { dappConstants } = require(project_root + "/src/sablier/dev-utils"); -const BigNumber = require("bignumber.js"); -const dayjs = require("dayjs"); -const truffleAssert = require("truffle-assertions"); - -const { - STANDARD_RECIPIENT_SHARE_PERCENTAGE, - STANDARD_SALARY, - STANDARD_SALARY_CTOKEN, - STANDARD_SENDER_SHARE_PERCENTAGE, - STANDARD_TIME_OFFSET, - STANDARD_TIME_DELTA, -} = dappConstants; - -function shouldBehaveLikeIsCompoundingStream(_this) { //alice, bob) { - const alice = _this.alice; - const bob = _this.bob; - const sender = _this.alice; - //const opts = { from: sender }; - const now = new BigNumber(dayjs().unix()); - - describe("when the compounding stream exists", () => { - let streamId; - const recipient = bob; - const deposit = STANDARD_SALARY_CTOKEN.toString(10); - const startTime = now.plus(STANDARD_TIME_OFFSET); - const stopTime = startTime.plus(STANDARD_TIME_DELTA); - const senderSharePercentage = STANDARD_SENDER_SHARE_PERCENTAGE; - const recipientSharePercentage = STANDARD_RECIPIENT_SHARE_PERCENTAGE; - - beforeEach(async () => { - //await this.cTokenManager.whitelistCToken(this.cToken.address); - await _this.cToken.approve({ address: _this.sablier.getAddress(), amount: deposit }); - const result = await _this.sablier.createCompoundingStream({ - recipient, - deposit, - tokenAddress: _this.cToken.getAddress(), - startTime, - stopTime, - senderSharePercentage, - recipientSharePercentage, - }); - //streamId = Number(result.logs[0].args.streamId); - streamId = Number(result.events.CreateStream.returnValues.streamId); - console.log('---IsCompoundingStream.streamId.bp0: ', streamId); - }); - - it("returns true", async () => { - const result = await _this.sablier.isCompoundingStream({ streamId }); - result.should.be.equal(true); - }); - }); - - describe("when the stream exists but is not compounding", () => { - let streamId; - const recipient = bob; - const deposit = STANDARD_SALARY.toString(10); - const startTime = now.plus(STANDARD_TIME_OFFSET); - const stopTime = startTime.plus(STANDARD_TIME_DELTA); - - beforeEach(async () => { - await _this.token.approve({ address: _this.sablier.getAddress(), amount: deposit }); - const result = await _this.sablier.createStream({ recipient, deposit, tokenAddress: _this.token.getAddress(), startTime, stopTime }); - //streamId = Number(result.logs[0].args.streamId); - streamId = Number(result.events.CreateStream.returnValues.streamId); - console.log('---IsCompoundingStream.streamId.bp1: ', streamId); - }); - - it("returns false", async () => { - const result = await _this.sablier.isCompoundingStream({ streamId }); - result.should.be.equal(false); - }); - }); - - describe("when the stream does not exist", () => { - it("reverts", async () => { - const streamId = new BigNumber(419863); - await truffleAssert.reverts(_this.sablier.getCompoundingStream({ streamId }), "stream does not exist"); - }); - }); -} - -module.exports = shouldBehaveLikeIsCompoundingStream; From 09705c8447f9190dae09495075dd1120246b0ee2 Mon Sep 17 00:00:00 2001 From: SamG Date: Thu, 2 Dec 2021 01:30:52 +0000 Subject: [PATCH 4/5] [FIX] removed migrations/2_deploy_sablier.js file related to sablier branch. --- migrations/2_deploy_sablier.js | 33 --------------------------------- 1 file changed, 33 deletions(-) delete mode 100644 migrations/2_deploy_sablier.js diff --git a/migrations/2_deploy_sablier.js b/migrations/2_deploy_sablier.js deleted file mode 100644 index a75728d5..00000000 --- a/migrations/2_deploy_sablier.js +++ /dev/null @@ -1,33 +0,0 @@ -/* global artifacts, web3 */ -const BigNumber = require("bignumber.js"); - -const ERC20Mock = artifacts.require("./ERC20Mock.sol"); -//const CTokenManager = artifacts.require("./CTokenManager.sol"); -const Sablier = artifacts.require("./Sablier.sol"); - -module.exports = async (deployer, network, accounts) => { - //await deployer.deploy(CTokenManager); - - await deployer.deploy(Sablier); - const sablier = await Sablier.deployed(); - - if (network !== "development") { - return; - } - - const allowance = new BigNumber(3600).multipliedBy(1e18).toString(10); - - await deployer.deploy(ERC20Mock); - const erc20 = await ERC20Mock.deployed(); - await erc20.mint(accounts[0], allowance); - await erc20.approve(sablier.address, allowance, { from: accounts[0] }); - - const recipient = accounts[1]; - const deposit = allowance; - const tokenAddress = erc20.address; - const { timestamp } = await web3.eth.getBlock("latest"); - const startTime = new BigNumber(timestamp).plus(300); - const stopTime = startTime.plus(3600); - - await sablier.createStream(recipient, deposit, tokenAddress, startTime, stopTime, { from: accounts[0] }); -}; From 6975b15cc3e855671ad633b95e0b3b343d14f1d8 Mon Sep 17 00:00:00 2001 From: SamG Date: Fri, 3 Dec 2021 11:57:46 +0000 Subject: [PATCH 5/5] [FIX] -removed sablier json interface files dependencies as they are in its own branch. --- src/interfaces/index.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/interfaces/index.js b/src/interfaces/index.js index b9a0f710..b301cc37 100644 --- a/src/interfaces/index.js +++ b/src/interfaces/index.js @@ -10,8 +10,6 @@ const index = { network: require('../contracts/Network.json'), networkFactory: require('../contracts/NetworkFactory.json'), openerRealFvr: require('../contracts/OpenerRealFvr.json'), - sablier: require('../contracts/Sablier.json'), - cerc20mock: require('../contracts/CERC20Mock.json'), erc20mock: require('../contracts/ERC20Mock.json'), ethutils: require('../contracts/ETHUtils.json'), loophole: require('../contracts/Loophole.json'),