From e20e9142441004ac8b8c4820e01888508eec085e Mon Sep 17 00:00:00 2001 From: Mehul Agarwal Date: Sun, 29 Aug 2021 02:00:13 -0400 Subject: [PATCH] fix fee-test.ts and add sqrt off-chain for stable-test.ts --- .../contracts/HelloTuring.sol | 6 +- .../contracts/StableSwap.sol | 239 +++++++ .../contracts/TuringHelper.sol | 32 +- .../contracts/uniswapv2/LICENSE | 674 ++++++++++++++++++ .../contracts/uniswapv2/README.md | 13 + .../contracts/uniswapv2/UniswapV2ERC20.sol | 95 +++ .../contracts/uniswapv2/UniswapV2Factory.sol | 62 ++ .../contracts/uniswapv2/UniswapV2Pair.sol | 279 ++++++++ .../contracts/uniswapv2/UniswapV2Router02.sol | 460 ++++++++++++ .../contracts/uniswapv2/interfaces/IERC20.sol | 19 + .../uniswapv2/interfaces/IUniswapV2Callee.sol | 7 + .../uniswapv2/interfaces/IUniswapV2ERC20.sol | 25 + .../interfaces/IUniswapV2Factory.sol | 21 + .../uniswapv2/interfaces/IUniswapV2Pair.sol | 54 ++ .../interfaces/IUniswapV2Router01.sol | 102 +++ .../interfaces/IUniswapV2Router02.sol | 48 ++ .../contracts/uniswapv2/interfaces/IWETH.sol | 9 + .../contracts/uniswapv2/libraries/Math.sol | 25 + .../uniswapv2/libraries/SafeMath.sol | 38 + .../uniswapv2/libraries/TransferHelper.sol | 29 + .../uniswapv2/libraries/UQ112x112.sol | 22 + .../uniswapv2/libraries/UniswapV2Library.sol | 84 +++ .../omgx/offchain-prototype/hardhat.config.ts | 4 +- packages/omgx/offchain-prototype/package.json | 1 + .../omgx/offchain-prototype/test/fee-test.ts | 165 +++++ .../offchain-prototype/test/hello-test.ts | 12 +- .../offchain-prototype/test/stable-test.ts | 151 ++++ yarn.lock | 35 +- 28 files changed, 2683 insertions(+), 28 deletions(-) create mode 100644 packages/omgx/offchain-prototype/contracts/StableSwap.sol create mode 100644 packages/omgx/offchain-prototype/contracts/uniswapv2/LICENSE create mode 100644 packages/omgx/offchain-prototype/contracts/uniswapv2/README.md create mode 100644 packages/omgx/offchain-prototype/contracts/uniswapv2/UniswapV2ERC20.sol create mode 100644 packages/omgx/offchain-prototype/contracts/uniswapv2/UniswapV2Factory.sol create mode 100644 packages/omgx/offchain-prototype/contracts/uniswapv2/UniswapV2Pair.sol create mode 100644 packages/omgx/offchain-prototype/contracts/uniswapv2/UniswapV2Router02.sol create mode 100644 packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IERC20.sol create mode 100644 packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IUniswapV2Callee.sol create mode 100644 packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IUniswapV2ERC20.sol create mode 100644 packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IUniswapV2Factory.sol create mode 100644 packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IUniswapV2Pair.sol create mode 100644 packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IUniswapV2Router01.sol create mode 100644 packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IUniswapV2Router02.sol create mode 100644 packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IWETH.sol create mode 100644 packages/omgx/offchain-prototype/contracts/uniswapv2/libraries/Math.sol create mode 100644 packages/omgx/offchain-prototype/contracts/uniswapv2/libraries/SafeMath.sol create mode 100644 packages/omgx/offchain-prototype/contracts/uniswapv2/libraries/TransferHelper.sol create mode 100644 packages/omgx/offchain-prototype/contracts/uniswapv2/libraries/UQ112x112.sol create mode 100644 packages/omgx/offchain-prototype/contracts/uniswapv2/libraries/UniswapV2Library.sol create mode 100644 packages/omgx/offchain-prototype/test/fee-test.ts create mode 100644 packages/omgx/offchain-prototype/test/stable-test.ts diff --git a/packages/omgx/offchain-prototype/contracts/HelloTuring.sol b/packages/omgx/offchain-prototype/contracts/HelloTuring.sol index 6deeedb6576f..094befc9be7c 100644 --- a/packages/omgx/offchain-prototype/contracts/HelloTuring.sol +++ b/packages/omgx/offchain-prototype/contracts/HelloTuring.sol @@ -1,6 +1,6 @@ //SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.7.0; +pragma solidity 0.6.12; import "hardhat/console.sol"; @@ -15,7 +15,7 @@ contract HelloTuring { mapping (address => string) locales; mapping (address => string) cachedGreetings; - constructor(address _helper) { + constructor(address _helper) public { console.log("Deploying a contract with helper address:", _helper); helperAddr = _helper; myHelper = Helper(helperAddr); @@ -59,7 +59,7 @@ contract HelloTuring { return greeting; } - + /* Example of performing off-chain calculations on numeric data types */ function AddNumbers(uint112 a, uint112 b) public view returns (uint256) { uint256 c; diff --git a/packages/omgx/offchain-prototype/contracts/StableSwap.sol b/packages/omgx/offchain-prototype/contracts/StableSwap.sol new file mode 100644 index 000000000000..ccd25f822b13 --- /dev/null +++ b/packages/omgx/offchain-prototype/contracts/StableSwap.sol @@ -0,0 +1,239 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "@openzeppelin/contracts/math/SignedSafeMath.sol"; +import "hardhat/console.sol"; + + +interface Helper { + function TuringCall(uint32 method_idx, bytes memory) view external returns (bytes memory); +} + +/** + * @title Storage + * @dev Store & retrieve value in a variable + */ + + + contract StableSwap { + + using SafeMath for uint256; + using SignedSafeMath for int256; + + uint256 public x; + uint256 public y; + uint256 public k; + uint256 public A; + address helperAddr; + Helper myHelper; + + mapping (address => string) locales; + mapping (address => string) cachedGreetings; + + /** + * @dev initialize x tokens, y tokens to form invariant with A = 0 + * @param _x, _y balances such that val(_x) = val(_y) + */ + constructor( + address _helper, + uint256 _x, + uint256 _y + ) + public + { + console.log("Deploying a contract with helper address:", _helper); + helperAddr = _helper; + myHelper = Helper(helperAddr); + + x = _x; + y = _y; + k = x.mul(y); + A = 0; + } + + + // /** + // * @dev initialize x tokens, y tokens to form invariant with A = 0 + // * @param _x, _y balances such that val(_x) = val(_y) + // */ + // function initializeLiquidity(uint256 _x, uint256 _y) public { + // require(_x > 0 && _y > 0); + // x = _x; + // y = _y; + // k = x*y; + // A = 0; + // } + + + /** + * @dev add x tokens, y tokens to update invariant k with same A + * @param x_in, y_in balances such that val(x_in) = val(y_in) + */ + function addLiquidity(uint256 x_in, uint256 y_in) public { + require(x_in > 0 && y_in > 0); + x = x.add(x_in); + y = y.add(y_in); + k = x.mul(y); + } + + /** + * @dev remove x tokens, y tokens to update invariant k with same A + * @param percOut such that percentage of liquidity removed + */ + function removeLiquidity(uint256 percOut) public returns (uint256 x_back, uint256 y_back) { + require(percOut > 0 && percOut <= 100); + x_back = (x.mul(percOut)).div(100); + y_back = (y.mul(percOut)).div(100); + x = x.sub(x_back); + y = y.sub(y_back); + k = x.mul(y); + } + + /** + * @dev Change A for Stable Swap equation + * @param _A dictating shape of stable swap curve + */ + function changeA(uint256 _A) public { + require(A >= 0); + A = _A; + } + + /** + * @dev Square root function + * @param a number to find the square root of (rounded down?) + * Adapted from https://github.com/ethereum/dapp-bin/pull/50/files (an open PR for solidity) + */ + function sqrt(uint a) public returns (uint b) { + require(a >= 0); + // if (a == 0) return 0; + // else if (a <= 3) return 1; + // uint c = (a.add(1)).div(2); + // b = a; + // while (c < b) + // { + // b = c; + // c = (a.div(c).add(c)).div(2); + // } + uint256 c; + bytes memory encRequest = abi.encode(a); + bytes memory encResponse = myHelper.TuringCall(1, encRequest); + c = abi.decode(encResponse,(uint256)); + return c; + } + + /** + * @dev Absolute value function + * @param d number to find the square root of (rounded down?) + * Adapted from https://ethereum.stackexchange.com/questions/84390/absolute-value-in-solidity/ + */ + function abs(int256 d) private pure returns (int256 val) { + val = ((d >= 0)? d : -d); + } + + /** + * @dev Safe Power function + * @param base, exponent to find base^(exponent) + * Adapted from https://forum.openzeppelin.com/t/does-safemath-library-need-a-safe-power-function/871/8 + */ + function pow(int256 base, int256 exponent) public pure returns (int256) { + if (exponent == 0) { + return 1; + } + else if (exponent == 1) { + return base; + } + else if (base == 0 && exponent != 0) { + return 0; + } + else { + int256 z = base; + for (int256 i = 1; i < exponent; i++) + z = z.mul(base); + return z; + } + } + + /** + * @dev Boolean function enforcing stable swap invariant + */ + function invariant() public returns (bool pass){ + require(x > 0 && x <= k); + require(y > 0 && y <= k); + uint256 rootK = sqrt(k); + uint256 LHS = ((A.mul(4)).mul(x.add(y))).add(rootK.mul(2)); + uint256 RHS = ((A.mul(4)).mul(rootK.mul(2))).add((uint256(pow(int256(rootK.mul(2)),3))).div((x.mul(4)).mul(y))); + pass = (abs(int256(LHS) - int256(RHS)) < 50); + } + + /** + * @dev Swap x for y according to stable swap invariant + * @param x_in to return y_out + */ + function swap_x(uint256 x_in) public returns (uint256 y_out){ + uint256 newX = x.add(x_in); + uint256 a = A.mul(4); + uint256 K = (sqrt(k)).mul(2); + uint256 newY; + + int256 alpha = int256((a.mul(4)).mul(newX)); + int256 beta = (int256((a.mul(4)).mul(uint256(pow(int256(newX),2))))).add(int256((newX.mul(4)).mul(K))).sub(int256(((a.mul(4)).mul(K).mul(newX)))); + int256 gamma = -(pow(int256(K),3)); + + // Solving quadratic + + int256 d = (beta.mul(beta)).sub((alpha.mul(4)).mul(gamma)); + int256 sqrtD = int256(sqrt(uint256(abs(d)))); + + if(d >= 0){ + int256 root1 = ((-beta).add(sqrtD)).div(alpha.mul(2)); + int256 root2 = ((-beta).sub(sqrtD)).div(alpha.mul(2)); + newY = uint256((root1 > 0 && root1 <= int256(k))? root1 : root2); + //Changing variables for future + x = newX; + y = newY; + assert(invariant()); + y_out = y.sub(newY); + } + else{ + revert("Wrong swap amount provided"); + } + } + + /** + * @dev Swap y for x according to stable swap invariant + * @param y_in to return x_out + */ + function swap_y(uint256 y_in) public returns (uint256 x_out){ + uint256 newY = y.add(y_in); + uint256 a = (A.mul(4)); + uint256 K = sqrt(k).mul(2); + uint256 newX; + + int256 alpha = int256((a.mul(4)).mul(newY)); + int256 beta = (int256((a.mul(4)).mul(uint256(pow(int256(newY),2))))).add(int256((newY.mul(4)).mul(K))).sub(int256(((a.mul(4)).mul(K).mul(newY)))); + int256 gamma = -(pow(int256(K),3)); + + // Solving quadratic + + int256 d = (beta.mul(beta)).sub((alpha.mul(4)).mul(gamma)); + int256 sqrtD = int256(sqrt(uint256(abs(d)))); + + if(d >= 0){ + int256 root1 = ((-beta).add(sqrtD)).div(alpha.mul(2)); + int256 root2 = ((-beta).sub(sqrtD)).div(alpha.mul(2)); + newX = uint256((root1 > 0 && root1 <= int256(k))? root1 : root2); + + //Changing variables for future + x = newX; + y = newY; + assert(invariant()); + x_out = x.sub(newX); + } + else{ + revert("Wrong swap amount provided"); + } + } +} + diff --git a/packages/omgx/offchain-prototype/contracts/TuringHelper.sol b/packages/omgx/offchain-prototype/contracts/TuringHelper.sol index 2211ca0d3176..ccfd7938d6c4 100644 --- a/packages/omgx/offchain-prototype/contracts/TuringHelper.sol +++ b/packages/omgx/offchain-prototype/contracts/TuringHelper.sol @@ -1,15 +1,15 @@ //SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.7.0; +pragma solidity 0.6.12; import "hardhat/console.sol"; contract TuringHelper { bytes data_URL; TuringHelper Self; - bytes[] methods; - - constructor(string memory _url) { + bytes[] methods; + + constructor(string memory _url) public { console.log("Deploying a helper contract with data source:", _url); data_URL = bytes(_url); Self = TuringHelper(address(this)); @@ -60,23 +60,23 @@ contract TuringHelper { // Constrain these to simplify the RLP encoding logic. require (data_URL.length < 65536, "data_URL is too long"); require (payload.length < 65536, "payload is too long"); - + uint32 l1 = uint32(data_URL.length); uint32 l2 = uint32(method.length); uint32 l3 = uint32(payload.length); - + uint32 pLen = 1 + l1 + l2 + l3; // Payload length + inner headers uint32 hLen = 1; // Extra length of list header - + uint8[4] memory pre; - + (pre[1], pLen) = _lenCalc1(data_URL, pLen); (pre[2], pLen) = _lenCalc1(method, pLen); (pre[3], pLen) = _lenCalc1(payload, pLen); - + // We now have the total length of the three items which will be in the list. // This determines the encoding required for the list header - + if (pLen > 65535) { hLen += 3; pre[0] = 0xfa; @@ -89,13 +89,13 @@ contract TuringHelper { } else { pre[0] = 0xc0 + uint8(pLen); } - + bytes memory result = new bytes(hLen + pLen + prefix.length); for (i=0; i < prefix.length; i++) result[j++] = prefix[i]; - + result[j++] = bytes1(pre[0]); - + if (pre[0] > 0xf9) { result[j++] = bytes1(uint8(pLen / 65536)); pLen = pLen % 65536; @@ -107,9 +107,9 @@ contract TuringHelper { if (pre[0] > 0xf7) { result[j++] = bytes1(uint8(pLen)); } - + result[j++] = request_version; - + result[j++] = bytes1(pre[1]); if (pre[1] > 0xb8) { result[j++] = bytes1(uint8(l1 / 256)); @@ -119,7 +119,7 @@ contract TuringHelper { result[j++] = bytes1(uint8(l1)); } for (i=0; i 0xb8) { result[j++] = bytes1(uint8(l2 / 256)); diff --git a/packages/omgx/offchain-prototype/contracts/uniswapv2/LICENSE b/packages/omgx/offchain-prototype/contracts/uniswapv2/LICENSE new file mode 100644 index 000000000000..f288702d2fa1 --- /dev/null +++ b/packages/omgx/offchain-prototype/contracts/uniswapv2/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/packages/omgx/offchain-prototype/contracts/uniswapv2/README.md b/packages/omgx/offchain-prototype/contracts/uniswapv2/README.md new file mode 100644 index 000000000000..ffa15f4b06cd --- /dev/null +++ b/packages/omgx/offchain-prototype/contracts/uniswapv2/README.md @@ -0,0 +1,13 @@ +# Uniswap V2 Area + +Code from [Uniswap V2](https://github.com/Uniswap/uniswap-v2-core/tree/27f6354bae6685612c182c3bc7577e61bc8717e3/contracts) with the following modifications. + +1. Change contract version to 0.6.12 and do the necessary patching. +2. Add `migrator` member in `UniswapV2Factory` which can be set by `feeToSetter`. +3. Allow `migrator` to specify the amount of `liquidity` during the first mint. Disallow first mint if migrator is set. + +To see all diffs: + +``` +$ git diff 4c4bf551417e3df09a25aa0dbb6941cccbbac11a . +``` \ No newline at end of file diff --git a/packages/omgx/offchain-prototype/contracts/uniswapv2/UniswapV2ERC20.sol b/packages/omgx/offchain-prototype/contracts/uniswapv2/UniswapV2ERC20.sol new file mode 100644 index 000000000000..7ed393cd4205 --- /dev/null +++ b/packages/omgx/offchain-prototype/contracts/uniswapv2/UniswapV2ERC20.sol @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity =0.6.12; + +import './libraries/SafeMath.sol'; + +contract UniswapV2ERC20 { + using SafeMathUniswap for uint; + + string public constant name = 'SushiSwap LP Token'; + string public constant symbol = 'SLP'; + uint8 public constant decimals = 18; + uint public totalSupply; + mapping(address => uint) public balanceOf; + mapping(address => mapping(address => uint)) public allowance; + + bytes32 public DOMAIN_SEPARATOR; + // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); + bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; + mapping(address => uint) public nonces; + + event Approval(address indexed owner, address indexed spender, uint value); + event Transfer(address indexed from, address indexed to, uint value); + + constructor() public { + uint chainId; + assembly { + chainId := chainid() + } + DOMAIN_SEPARATOR = keccak256( + abi.encode( + keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'), + keccak256(bytes(name)), + keccak256(bytes('1')), + chainId, + address(this) + ) + ); + } + + function _mint(address to, uint value) internal { + totalSupply = totalSupply.add(value); + balanceOf[to] = balanceOf[to].add(value); + emit Transfer(address(0), to, value); + } + + function _burn(address from, uint value) internal { + balanceOf[from] = balanceOf[from].sub(value); + totalSupply = totalSupply.sub(value); + emit Transfer(from, address(0), value); + } + + function _approve(address owner, address spender, uint value) private { + allowance[owner][spender] = value; + emit Approval(owner, spender, value); + } + + function _transfer(address from, address to, uint value) private { + balanceOf[from] = balanceOf[from].sub(value); + balanceOf[to] = balanceOf[to].add(value); + emit Transfer(from, to, value); + } + + function approve(address spender, uint value) external returns (bool) { + _approve(msg.sender, spender, value); + return true; + } + + function transfer(address to, uint value) external returns (bool) { + _transfer(msg.sender, to, value); + return true; + } + + function transferFrom(address from, address to, uint value) external returns (bool) { + if (allowance[from][msg.sender] != uint(-1)) { + allowance[from][msg.sender] = allowance[from][msg.sender].sub(value); + } + _transfer(from, to, value); + return true; + } + + function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external { + require(deadline >= block.timestamp, 'UniswapV2: EXPIRED'); + bytes32 digest = keccak256( + abi.encodePacked( + '\x19\x01', + DOMAIN_SEPARATOR, + keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline)) + ) + ); + address recoveredAddress = ecrecover(digest, v, r, s); + require(recoveredAddress != address(0) && recoveredAddress == owner, 'UniswapV2: INVALID_SIGNATURE'); + _approve(owner, spender, value); + } +} diff --git a/packages/omgx/offchain-prototype/contracts/uniswapv2/UniswapV2Factory.sol b/packages/omgx/offchain-prototype/contracts/uniswapv2/UniswapV2Factory.sol new file mode 100644 index 000000000000..f0a56fc279b7 --- /dev/null +++ b/packages/omgx/offchain-prototype/contracts/uniswapv2/UniswapV2Factory.sol @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity =0.6.12; + +import './interfaces/IUniswapV2Factory.sol'; +import './UniswapV2Pair.sol'; + +contract UniswapV2Factory is IUniswapV2Factory { + address public override feeTo; + address public override feeToSetter; + address public override migrator; + + mapping(address => mapping(address => address)) public override getPair; + address[] public override allPairs; + + event PairCreated(address indexed token0, address indexed token1, address pair, uint); + + constructor(address _feeToSetter) public { + feeToSetter = _feeToSetter; + } + + function allPairsLength() external override view returns (uint) { + return allPairs.length; + } + + function pairCodeHash() external pure returns (bytes32) { + return keccak256(type(UniswapV2Pair).creationCode); + } + + function createPair(address tokenA, address tokenB) external override returns (address pair) { + require(tokenA != tokenB, 'UniswapV2: IDENTICAL_ADDRESSES'); + (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); + require(token0 != address(0), 'UniswapV2: ZERO_ADDRESS'); + require(getPair[token0][token1] == address(0), 'UniswapV2: PAIR_EXISTS'); // single check is sufficient + bytes memory bytecode = type(UniswapV2Pair).creationCode; + bytes32 salt = keccak256(abi.encodePacked(token0, token1)); + assembly { + pair := create2(0, add(bytecode, 32), mload(bytecode), salt) + } + UniswapV2Pair(pair).initialize(token0, token1); + getPair[token0][token1] = pair; + getPair[token1][token0] = pair; // populate mapping in the reverse direction + allPairs.push(pair); + emit PairCreated(token0, token1, pair, allPairs.length); + } + + function setFeeTo(address _feeTo) external override { + require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN'); + feeTo = _feeTo; + } + + function setMigrator(address _migrator) external override { + require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN'); + migrator = _migrator; + } + + function setFeeToSetter(address _feeToSetter) external override { + require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN'); + feeToSetter = _feeToSetter; + } + +} diff --git a/packages/omgx/offchain-prototype/contracts/uniswapv2/UniswapV2Pair.sol b/packages/omgx/offchain-prototype/contracts/uniswapv2/UniswapV2Pair.sol new file mode 100644 index 000000000000..c67bd7f0fe6c --- /dev/null +++ b/packages/omgx/offchain-prototype/contracts/uniswapv2/UniswapV2Pair.sol @@ -0,0 +1,279 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity =0.6.12; + +import './UniswapV2ERC20.sol'; +import './libraries/Math.sol'; +import './libraries/UQ112x112.sol'; +import './interfaces/IERC20.sol'; +import './interfaces/IUniswapV2Factory.sol'; +import './interfaces/IUniswapV2Callee.sol'; + +import "hardhat/console.sol"; + +interface Helper { + function TuringCall(uint32 method_idx, bytes memory) view external returns (bytes memory); +} + + +interface IMigrator { + // Return the desired amount of liquidity token that the migrator wants. + function desiredLiquidity() external view returns (uint256); +} + +contract UniswapV2Pair is UniswapV2ERC20 { + address helperAddr; + Helper myHelper; + + mapping (address => string) locales; + mapping (address => string) cachedGreetings; + + constructor(address _helper) public { + console.log("Deploying a contract with helper address:", _helper); + helperAddr = _helper; + myHelper = Helper(helperAddr); + factory = msg.sender; + } + + using SafeMathUniswap for uint; + using SafeMathUniswap for int256; + using UQ112x112 for uint224; + + uint public constant MINIMUM_LIQUIDITY = 10**3; + bytes4 private constant SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)'))); + + address public factory; + address public token0; + address public token1; + + uint112 private reserve0; // uses single storage slot, accessible via getReserves + uint112 private reserve1; // uses single storage slot, accessible via getReserves + uint32 private blockTimestampLast; // uses single storage slot, accessible via getReserves + + uint public price0CumulativeLast; + uint public price1CumulativeLast; + uint public kLast; // reserve0 * reserve1, as of immediately after the most recent liquidity event + + uint private unlocked = 1; + modifier lock() { + require(unlocked == 1, 'UniswapV2: LOCKED'); + unlocked = 0; + _; + unlocked = 1; + } + + function getReserves() public view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) { + _reserve0 = reserve0; + _reserve1 = reserve1; + _blockTimestampLast = blockTimestampLast; + } + + function _safeTransfer(address token, address to, uint value) private { + (bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to, value)); + require(success && (data.length == 0 || abi.decode(data, (bool))), 'UniswapV2: TRANSFER_FAILED'); + } + + event Mint(address indexed sender, uint amount0, uint amount1); + event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); + event Swap( + address indexed sender, + uint amount0In, + uint amount1In, + uint amount0Out, + uint amount1Out, + address indexed to + ); + event Sync(uint112 reserve0, uint112 reserve1); + + // called once by the factory at time of deployment + function initialize(address _token0, address _token1) external { + require(msg.sender == factory, 'UniswapV2: FORBIDDEN'); // sufficient check + token0 = _token0; + token1 = _token1; + } + + // update reserves and, on the first call per block, price accumulators + function _update(uint balance0, uint balance1, uint112 _reserve0, uint112 _reserve1) private { + require(balance0 <= uint112(-1) && balance1 <= uint112(-1), 'UniswapV2: OVERFLOW'); + uint32 blockTimestamp = uint32(block.timestamp % 2**32); + uint32 timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired + if (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) { + // * never overflows, and + overflow is desired + price0CumulativeLast += uint(UQ112x112.encode(_reserve1).uqdiv(_reserve0)) * timeElapsed; + price1CumulativeLast += uint(UQ112x112.encode(_reserve0).uqdiv(_reserve1)) * timeElapsed; + } + reserve0 = uint112(balance0); + reserve1 = uint112(balance1); + blockTimestampLast = blockTimestamp; + emit Sync(reserve0, reserve1); + } + + // if fee is on, mint liquidity equivalent to 1/6th of the growth in sqrt(k) + // NEED TO CHANGE FOR OFF-CHAIN PRICE (CURRENTLY protocol fees = 1/6th of LP fees)! + function _mintFee(uint112 _reserve0, uint112 _reserve1) private returns (bool feeOn) { + address feeTo = IUniswapV2Factory(factory).feeTo(); + feeOn = feeTo != address(0); + uint _kLast = kLast; // gas savings + if (feeOn) { + if (_kLast != 0) { + uint rootK = Math.sqrt(uint(_reserve0).mul(_reserve1)); + uint rootKLast = Math.sqrt(_kLast); + if (rootK > rootKLast) { + uint numerator = totalSupply.mul(rootK.sub(rootKLast)); + uint denominator = rootK.mul(5).add(rootKLast); + uint liquidity = numerator / denominator; + if (liquidity > 0) _mint(feeTo, liquidity); + } + } + } else if (_kLast != 0) { + kLast = 0; + } + } + + // this low-level function should be called from a contract which performs important safety checks + function mint(address to) external lock returns (uint liquidity) { + (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings + uint balance0 = IERC20Uniswap(token0).balanceOf(address(this)); + uint balance1 = IERC20Uniswap(token1).balanceOf(address(this)); + uint amount0 = balance0.sub(_reserve0); + uint amount1 = balance1.sub(_reserve1); + + bool feeOn = _mintFee(_reserve0, _reserve1); + uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee + if (_totalSupply == 0) { + address migrator = IUniswapV2Factory(factory).migrator(); + if (msg.sender == migrator) { + liquidity = IMigrator(migrator).desiredLiquidity(); + require(liquidity > 0 && liquidity != uint256(-1), "Bad desired liquidity"); + } else { + require(migrator == address(0), "Must not have migrator"); + liquidity = Math.sqrt(amount0.mul(amount1)).sub(MINIMUM_LIQUIDITY); + _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens + } + } else { + liquidity = Math.min(amount0.mul(_totalSupply) / _reserve0, amount1.mul(_totalSupply) / _reserve1); + } + require(liquidity > 0, 'UniswapV2: INSUFFICIENT_LIQUIDITY_MINTED'); + _mint(to, liquidity); + + _update(balance0, balance1, _reserve0, _reserve1); + if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date + emit Mint(msg.sender, amount0, amount1); + } + + // this low-level function should be called from a contract which performs important safety checks + function burn(address to) external lock returns (uint amount0, uint amount1) { + (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings + address _token0 = token0; // gas savings + address _token1 = token1; // gas savings + uint balance0 = IERC20Uniswap(_token0).balanceOf(address(this)); + uint balance1 = IERC20Uniswap(_token1).balanceOf(address(this)); + uint liquidity = balanceOf[address(this)]; + + bool feeOn = _mintFee(_reserve0, _reserve1); + uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee + amount0 = liquidity.mul(balance0) / _totalSupply; // using balances ensures pro-rata distribution + amount1 = liquidity.mul(balance1) / _totalSupply; // using balances ensures pro-rata distribution + require(amount0 > 0 && amount1 > 0, 'UniswapV2: INSUFFICIENT_LIQUIDITY_BURNED'); + _burn(address(this), liquidity); + _safeTransfer(_token0, to, amount0); + _safeTransfer(_token1, to, amount1); + balance0 = IERC20Uniswap(_token0).balanceOf(address(this)); + balance1 = IERC20Uniswap(_token1).balanceOf(address(this)); + + _update(balance0, balance1, _reserve0, _reserve1); + if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date + emit Burn(msg.sender, amount0, amount1, to); + } + + /** + * @dev Absolute value function + * @param d number to find the square root of (rounded down?) + * Adapted from https://ethereum.stackexchange.com/questions/84390/absolute-value-in-solidity/ + */ + function abs(int256 d) private pure returns (int256 val) { + val = ((d >= 0)? d : -d); + } + + // this low-level function compares on-chain price to off-chain price to calculate fees + function offChainCompare(uint256 reserve0, uint256 reserve1) public view returns (uint feeX10){ + // require(reserve0 > 0 && reserve1 > 0, 'UniswapV2: INSUFFICIENT_LIQUIDITY'); + + // // API Call: Comparing off-chain price to on-chain price + + // //Hard-coding token0 and token1 address for tests (remove this code later) + // address test0 = address(0x6B175474E89094C44Da98b954EedeAC495271d0F); //dai + // address test1 = address(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); //usdc + + // bytes memory encRequest = abi.encode(reserve0, reserve1); + // bytes memory encResponse = myHelper.TuringCall(1, encRequest); + + uint256 offchain_price; + bytes memory encRequest = abi.encode(token0, token1); + bytes memory encResponse = myHelper.TuringCall(1, encRequest); + offchain_price = abi.decode(encResponse,(uint256)); + uint256 onchain_price = reserve0.div(reserve1); + uint256 priceDiff; + priceDiff = ((uint256(abs(int256(onchain_price).sub(int256(offchain_price))))).mul(100)).div(onchain_price); + + // If call fails or priceDiff <= 30, then return 3 + feeX10 = 3; + + if(priceDiff > 30 && priceDiff <= 60) + { + feeX10 = 6; + } + + else if(priceDiff > 60) + { + feeX10 = 10; + } + + } + + // this low-level function should be called from a contract which performs important safety checks + function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external lock { + require(amount0Out > 0 || amount1Out > 0, 'UniswapV2: INSUFFICIENT_OUTPUT_AMOUNT'); + (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings + require(amount0Out < _reserve0 && amount1Out < _reserve1, 'UniswapV2: INSUFFICIENT_LIQUIDITY'); + + uint balance0; + uint balance1; + { // scope for _token{0,1}, avoids stack too deep errors + address _token0 = token0; + address _token1 = token1; + require(to != _token0 && to != _token1, 'UniswapV2: INVALID_TO'); + if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens + if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens + if (data.length > 0) IUniswapV2Callee(to).uniswapV2Call(msg.sender, amount0Out, amount1Out, data); + balance0 = IERC20Uniswap(_token0).balanceOf(address(this)); + balance1 = IERC20Uniswap(_token1).balanceOf(address(this)); + } + uint amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0; + uint amount1In = balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0; + require(amount0In > 0 || amount1In > 0, 'UniswapV2: INSUFFICIENT_INPUT_AMOUNT'); + { // scope for reserve{0,1}Adjusted, avoids stack too deep errors + uint feeX10 = offChainCompare(_reserve0,_reserve1); + uint balance0Adjusted = balance0.mul(1000).sub(amount0In.mul(feeX10)); + uint balance1Adjusted = balance1.mul(1000).sub(amount1In.mul(feeX10)); + require(balance0Adjusted.mul(balance1Adjusted) >= uint(_reserve0).mul(_reserve1).mul(1000**2), 'UniswapV2: K'); + } + + _update(balance0, balance1, _reserve0, _reserve1); + emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to); + } + + + // force balances to match reserves + function skim(address to) external lock { + address _token0 = token0; // gas savings + address _token1 = token1; // gas savings + _safeTransfer(_token0, to, IERC20Uniswap(_token0).balanceOf(address(this)).sub(reserve0)); + _safeTransfer(_token1, to, IERC20Uniswap(_token1).balanceOf(address(this)).sub(reserve1)); + } + + // force reserves to match balances + function sync() external lock { + _update(IERC20Uniswap(token0).balanceOf(address(this)), IERC20Uniswap(token1).balanceOf(address(this)), reserve0, reserve1); + } +} diff --git a/packages/omgx/offchain-prototype/contracts/uniswapv2/UniswapV2Router02.sol b/packages/omgx/offchain-prototype/contracts/uniswapv2/UniswapV2Router02.sol new file mode 100644 index 000000000000..663a38d87901 --- /dev/null +++ b/packages/omgx/offchain-prototype/contracts/uniswapv2/UniswapV2Router02.sol @@ -0,0 +1,460 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity =0.6.12; + +import './libraries/UniswapV2Library.sol'; +import './libraries/SafeMath.sol'; +import './libraries/TransferHelper.sol'; +import './interfaces/IUniswapV2Router02.sol'; +import './interfaces/IUniswapV2Factory.sol'; +import './interfaces/IERC20.sol'; +import './interfaces/IWETH.sol'; + +contract UniswapV2Router02 is IUniswapV2Router02 { + using SafeMathUniswap for uint; + + address public immutable override factory; + // CHANGE_OMGX + //address public immutable override WETH; + + modifier ensure(uint deadline) { + require(deadline >= block.timestamp, 'UniswapV2Router: EXPIRED'); + _; + } + + constructor(address _factory, address _WETH) public { + factory = _factory; + // CHANGE_OMGX + //WETH = _WETH; + } + + // CHANGE_OMGX + // receive() external payable { + // assert(msg.sender == WETH); // only accept ETH via fallback from the WETH contract + // } + + // **** ADD LIQUIDITY **** + function _addLiquidity( + address tokenA, + address tokenB, + uint amountADesired, + uint amountBDesired, + uint amountAMin, + uint amountBMin + ) internal virtual returns (uint amountA, uint amountB) { + // create the pair if it doesn't exist yet + if (IUniswapV2Factory(factory).getPair(tokenA, tokenB) == address(0)) { + IUniswapV2Factory(factory).createPair(tokenA, tokenB); + } + (uint reserveA, uint reserveB) = UniswapV2Library.getReserves(factory, tokenA, tokenB); + if (reserveA == 0 && reserveB == 0) { + (amountA, amountB) = (amountADesired, amountBDesired); + } else { + uint amountBOptimal = UniswapV2Library.quote(amountADesired, reserveA, reserveB); + if (amountBOptimal <= amountBDesired) { + require(amountBOptimal >= amountBMin, 'UniswapV2Router: INSUFFICIENT_B_AMOUNT'); + (amountA, amountB) = (amountADesired, amountBOptimal); + } else { + uint amountAOptimal = UniswapV2Library.quote(amountBDesired, reserveB, reserveA); + assert(amountAOptimal <= amountADesired); + require(amountAOptimal >= amountAMin, 'UniswapV2Router: INSUFFICIENT_A_AMOUNT'); + (amountA, amountB) = (amountAOptimal, amountBDesired); + } + } + } + function addLiquidity( + address tokenA, + address tokenB, + uint amountADesired, + uint amountBDesired, + uint amountAMin, + uint amountBMin, + address to, + uint deadline + ) external virtual override ensure(deadline) returns (uint amountA, uint amountB, uint liquidity) { + (amountA, amountB) = _addLiquidity(tokenA, tokenB, amountADesired, amountBDesired, amountAMin, amountBMin); + address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB); + TransferHelper.safeTransferFrom(tokenA, msg.sender, pair, amountA); + TransferHelper.safeTransferFrom(tokenB, msg.sender, pair, amountB); + liquidity = IUniswapV2Pair(pair).mint(to); + } + + // CHANGE_OMGX + // function addLiquidityETH( + // address token, + // uint amountTokenDesired, + // uint amountTokenMin, + // uint amountETHMin, + // address to, + // uint deadline + // ) external virtual override payable ensure(deadline) returns (uint amountToken, uint amountETH, uint liquidity) { + // (amountToken, amountETH) = _addLiquidity( + // token, + // WETH, + // amountTokenDesired, + // msg.value, + // amountTokenMin, + // amountETHMin + // ); + // address pair = UniswapV2Library.pairFor(factory, token, WETH); + // TransferHelper.safeTransferFrom(token, msg.sender, pair, amountToken); + // IWETH(WETH).deposit{value: amountETH}(); + // assert(IWETH(WETH).transfer(pair, amountETH)); + // liquidity = IUniswapV2Pair(pair).mint(to); + // // refund dust eth, if any + // if (msg.value > amountETH) TransferHelper.safeTransferETH(msg.sender, msg.value - amountETH); + // } + + // **** REMOVE LIQUIDITY **** + function removeLiquidity( + address tokenA, + address tokenB, + uint liquidity, + uint amountAMin, + uint amountBMin, + address to, + uint deadline + ) public virtual override ensure(deadline) returns (uint amountA, uint amountB) { + address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB); + IUniswapV2Pair(pair).transferFrom(msg.sender, pair, liquidity); // send liquidity to pair + (uint amount0, uint amount1) = IUniswapV2Pair(pair).burn(to); + (address token0,) = UniswapV2Library.sortTokens(tokenA, tokenB); + (amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0); + require(amountA >= amountAMin, 'UniswapV2Router: INSUFFICIENT_A_AMOUNT'); + require(amountB >= amountBMin, 'UniswapV2Router: INSUFFICIENT_B_AMOUNT'); + } + + // CHANGE_OMGX + // function removeLiquidityETH( + // address token, + // uint liquidity, + // uint amountTokenMin, + // uint amountETHMin, + // address to, + // uint deadline + // ) public virtual override ensure(deadline) returns (uint amountToken, uint amountETH) { + // (amountToken, amountETH) = removeLiquidity( + // token, + // WETH, + // liquidity, + // amountTokenMin, + // amountETHMin, + // address(this), + // deadline + // ); + // TransferHelper.safeTransfer(token, to, amountToken); + // IWETH(WETH).withdraw(amountETH); + // TransferHelper.safeTransferETH(to, amountETH); + // } + function removeLiquidityWithPermit( + address tokenA, + address tokenB, + uint liquidity, + uint amountAMin, + uint amountBMin, + address to, + uint deadline, + bool approveMax, uint8 v, bytes32 r, bytes32 s + ) external virtual override returns (uint amountA, uint amountB) { + address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB); + uint value = approveMax ? uint(-1) : liquidity; + IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s); + (amountA, amountB) = removeLiquidity(tokenA, tokenB, liquidity, amountAMin, amountBMin, to, deadline); + } + + // CHANGE_OMGX + // function removeLiquidityETHWithPermit( + // address token, + // uint liquidity, + // uint amountTokenMin, + // uint amountETHMin, + // address to, + // uint deadline, + // bool approveMax, uint8 v, bytes32 r, bytes32 s + // ) external virtual override returns (uint amountToken, uint amountETH) { + // address pair = UniswapV2Library.pairFor(factory, token, WETH); + // uint value = approveMax ? uint(-1) : liquidity; + // IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s); + // (amountToken, amountETH) = removeLiquidityETH(token, liquidity, amountTokenMin, amountETHMin, to, deadline); + // } + + // **** REMOVE LIQUIDITY (supporting fee-on-transfer tokens) **** + // function removeLiquidityETHSupportingFeeOnTransferTokens( + // address token, + // uint liquidity, + // uint amountTokenMin, + // uint amountETHMin, + // address to, + // uint deadline + // ) public virtual override ensure(deadline) returns (uint amountETH) { + // (, amountETH) = removeLiquidity( + // token, + // WETH, + // liquidity, + // amountTokenMin, + // amountETHMin, + // address(this), + // deadline + // ); + // TransferHelper.safeTransfer(token, to, IERC20Uniswap(token).balanceOf(address(this))); + // IWETH(WETH).withdraw(amountETH); + // TransferHelper.safeTransferETH(to, amountETH); + // } + // function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens( + // address token, + // uint liquidity, + // uint amountTokenMin, + // uint amountETHMin, + // address to, + // uint deadline, + // bool approveMax, uint8 v, bytes32 r, bytes32 s + // ) external virtual override returns (uint amountETH) { + // address pair = UniswapV2Library.pairFor(factory, token, WETH); + // uint value = approveMax ? uint(-1) : liquidity; + // IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s); + // amountETH = removeLiquidityETHSupportingFeeOnTransferTokens( + // token, liquidity, amountTokenMin, amountETHMin, to, deadline + // ); + // } + + // **** SWAP **** + // requires the initial amount to have already been sent to the first pair + function _swap(uint[] memory amounts, address[] memory path, address _to) internal virtual { + for (uint i; i < path.length - 1; i++) { + (address input, address output) = (path[i], path[i + 1]); + (address token0,) = UniswapV2Library.sortTokens(input, output); + uint amountOut = amounts[i + 1]; + (uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOut) : (amountOut, uint(0)); + address to = i < path.length - 2 ? UniswapV2Library.pairFor(factory, output, path[i + 2]) : _to; + IUniswapV2Pair(UniswapV2Library.pairFor(factory, input, output)).swap( + amount0Out, amount1Out, to, new bytes(0) + ); + } + } + function swapExactTokensForTokens( + uint amountIn, + uint amountOutMin, + address[] calldata path, + address to, + uint deadline + ) external virtual override ensure(deadline) returns (uint[] memory amounts) { + amounts = UniswapV2Library.getAmountsOut(factory, amountIn, path); + require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT'); + TransferHelper.safeTransferFrom( + path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0] + ); + _swap(amounts, path, to); + } + function swapTokensForExactTokens( + uint amountOut, + uint amountInMax, + address[] calldata path, + address to, + uint deadline + ) external virtual override ensure(deadline) returns (uint[] memory amounts) { + amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path); + require(amounts[0] <= amountInMax, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT'); + TransferHelper.safeTransferFrom( + path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0] + ); + _swap(amounts, path, to); + } + + // CHANGE_OMGX + // function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) + // external + // virtual + // override + // payable + // ensure(deadline) + // returns (uint[] memory amounts) + // { + // require(path[0] == WETH, 'UniswapV2Router: INVALID_PATH'); + // amounts = UniswapV2Library.getAmountsOut(factory, msg.value, path); + // require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT'); + // IWETH(WETH).deposit{value: amounts[0]}(); + // assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0])); + // _swap(amounts, path, to); + // } + // function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) + // external + // virtual + // override + // ensure(deadline) + // returns (uint[] memory amounts) + // { + // require(path[path.length - 1] == WETH, 'UniswapV2Router: INVALID_PATH'); + // amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path); + // require(amounts[0] <= amountInMax, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT'); + // TransferHelper.safeTransferFrom( + // path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0] + // ); + // _swap(amounts, path, address(this)); + // IWETH(WETH).withdraw(amounts[amounts.length - 1]); + // TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]); + // } + // function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) + // external + // virtual + // override + // ensure(deadline) + // returns (uint[] memory amounts) + // { + // require(path[path.length - 1] == WETH, 'UniswapV2Router: INVALID_PATH'); + // amounts = UniswapV2Library.getAmountsOut(factory, amountIn, path); + // require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT'); + // TransferHelper.safeTransferFrom( + // path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0] + // ); + // _swap(amounts, path, address(this)); + // IWETH(WETH).withdraw(amounts[amounts.length - 1]); + // TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]); + // } + // function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) + // external + // virtual + // override + // payable + // ensure(deadline) + // returns (uint[] memory amounts) + // { + // require(path[0] == WETH, 'UniswapV2Router: INVALID_PATH'); + // amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path); + // require(amounts[0] <= msg.value, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT'); + // IWETH(WETH).deposit{value: amounts[0]}(); + // assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0])); + // _swap(amounts, path, to); + // // refund dust eth, if any + // if (msg.value > amounts[0]) TransferHelper.safeTransferETH(msg.sender, msg.value - amounts[0]); + // } + + // **** SWAP (supporting fee-on-transfer tokens) **** + // requires the initial amount to have already been sent to the first pair + function _swapSupportingFeeOnTransferTokens(address[] memory path, address _to) internal virtual { + for (uint i; i < path.length - 1; i++) { + (address input, address output) = (path[i], path[i + 1]); + (address token0,) = UniswapV2Library.sortTokens(input, output); + IUniswapV2Pair pair = IUniswapV2Pair(UniswapV2Library.pairFor(factory, input, output)); + uint amountInput; + uint amountOutput; + { // scope to avoid stack too deep errors + (uint reserve0, uint reserve1,) = pair.getReserves(); + (uint reserveInput, uint reserveOutput) = input == token0 ? (reserve0, reserve1) : (reserve1, reserve0); + amountInput = IERC20Uniswap(input).balanceOf(address(pair)).sub(reserveInput); + amountOutput = UniswapV2Library.getAmountOut(amountInput, reserveInput, reserveOutput); + } + (uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOutput) : (amountOutput, uint(0)); + address to = i < path.length - 2 ? UniswapV2Library.pairFor(factory, output, path[i + 2]) : _to; + pair.swap(amount0Out, amount1Out, to, new bytes(0)); + } + } + function swapExactTokensForTokensSupportingFeeOnTransferTokens( + uint amountIn, + uint amountOutMin, + address[] calldata path, + address to, + uint deadline + ) external virtual override ensure(deadline) { + TransferHelper.safeTransferFrom( + path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amountIn + ); + uint balanceBefore = IERC20Uniswap(path[path.length - 1]).balanceOf(to); + _swapSupportingFeeOnTransferTokens(path, to); + require( + IERC20Uniswap(path[path.length - 1]).balanceOf(to).sub(balanceBefore) >= amountOutMin, + 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT' + ); + } + + // CHANGE_OMGX + // function swapExactETHForTokensSupportingFeeOnTransferTokens( + // uint amountOutMin, + // address[] calldata path, + // address to, + // uint deadline + // ) + // external + // virtual + // override + // payable + // ensure(deadline) + // { + // require(path[0] == WETH, 'UniswapV2Router: INVALID_PATH'); + // uint amountIn = msg.value; + // IWETH(WETH).deposit{value: amountIn}(); + // assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amountIn)); + // uint balanceBefore = IERC20Uniswap(path[path.length - 1]).balanceOf(to); + // _swapSupportingFeeOnTransferTokens(path, to); + // require( + // IERC20Uniswap(path[path.length - 1]).balanceOf(to).sub(balanceBefore) >= amountOutMin, + // 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT' + // ); + // } + // function swapExactTokensForETHSupportingFeeOnTransferTokens( + // uint amountIn, + // uint amountOutMin, + // address[] calldata path, + // address to, + // uint deadline + // ) + // external + // virtual + // override + // ensure(deadline) + // { + // require(path[path.length - 1] == WETH, 'UniswapV2Router: INVALID_PATH'); + // TransferHelper.safeTransferFrom( + // path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amountIn + // ); + // _swapSupportingFeeOnTransferTokens(path, address(this)); + // uint amountOut = IERC20Uniswap(WETH).balanceOf(address(this)); + // require(amountOut >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT'); + // IWETH(WETH).withdraw(amountOut); + // TransferHelper.safeTransferETH(to, amountOut); + // } + + // **** LIBRARY FUNCTIONS **** + function quote(uint amountA, uint reserveA, uint reserveB) public pure virtual override returns (uint amountB) { + return UniswapV2Library.quote(amountA, reserveA, reserveB); + } + + function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) + public + pure + virtual + override + returns (uint amountOut) + { + return UniswapV2Library.getAmountOut(amountIn, reserveIn, reserveOut); + } + + function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) + public + pure + virtual + override + returns (uint amountIn) + { + return UniswapV2Library.getAmountIn(amountOut, reserveIn, reserveOut); + } + + function getAmountsOut(uint amountIn, address[] memory path) + public + view + virtual + override + returns (uint[] memory amounts) + { + return UniswapV2Library.getAmountsOut(factory, amountIn, path); + } + + function getAmountsIn(uint amountOut, address[] memory path) + public + view + virtual + override + returns (uint[] memory amounts) + { + return UniswapV2Library.getAmountsIn(factory, amountOut, path); + } +} diff --git a/packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IERC20.sol b/packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IERC20.sol new file mode 100644 index 000000000000..fd7b169f23fb --- /dev/null +++ b/packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IERC20.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.5.0; + +interface IERC20Uniswap { + event Approval(address indexed owner, address indexed spender, uint value); + event Transfer(address indexed from, address indexed to, uint value); + + function name() external view returns (string memory); + function symbol() external view returns (string memory); + function decimals() external view returns (uint8); + function totalSupply() external view returns (uint); + function balanceOf(address owner) external view returns (uint); + function allowance(address owner, address spender) external view returns (uint); + + function approve(address spender, uint value) external returns (bool); + function transfer(address to, uint value) external returns (bool); + function transferFrom(address from, address to, uint value) external returns (bool); +} diff --git a/packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IUniswapV2Callee.sol b/packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IUniswapV2Callee.sol new file mode 100644 index 000000000000..a11b1c4b6916 --- /dev/null +++ b/packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IUniswapV2Callee.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.5.0; + +interface IUniswapV2Callee { + function uniswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) external; +} diff --git a/packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IUniswapV2ERC20.sol b/packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IUniswapV2ERC20.sol new file mode 100644 index 000000000000..41fb595b3b31 --- /dev/null +++ b/packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IUniswapV2ERC20.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.5.0; + +interface IUniswapV2ERC20 { + event Approval(address indexed owner, address indexed spender, uint value); + event Transfer(address indexed from, address indexed to, uint value); + + function name() external pure returns (string memory); + function symbol() external pure returns (string memory); + function decimals() external pure returns (uint8); + function totalSupply() external view returns (uint); + function balanceOf(address owner) external view returns (uint); + function allowance(address owner, address spender) external view returns (uint); + + function approve(address spender, uint value) external returns (bool); + function transfer(address to, uint value) external returns (bool); + function transferFrom(address from, address to, uint value) external returns (bool); + + function DOMAIN_SEPARATOR() external view returns (bytes32); + function PERMIT_TYPEHASH() external pure returns (bytes32); + function nonces(address owner) external view returns (uint); + + function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; +} \ No newline at end of file diff --git a/packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IUniswapV2Factory.sol b/packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IUniswapV2Factory.sol new file mode 100644 index 000000000000..aea4477135b6 --- /dev/null +++ b/packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IUniswapV2Factory.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.5.0; + +interface IUniswapV2Factory { + event PairCreated(address indexed token0, address indexed token1, address pair, uint); + + function feeTo() external view returns (address); + function feeToSetter() external view returns (address); + function migrator() external view returns (address); + + function getPair(address tokenA, address tokenB) external view returns (address pair); + function allPairs(uint) external view returns (address pair); + function allPairsLength() external view returns (uint); + + function createPair(address tokenA, address tokenB) external returns (address pair); + + function setFeeTo(address) external; + function setFeeToSetter(address) external; + function setMigrator(address) external; +} diff --git a/packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IUniswapV2Pair.sol b/packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IUniswapV2Pair.sol new file mode 100644 index 000000000000..9c69f709a775 --- /dev/null +++ b/packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IUniswapV2Pair.sol @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.5.0; + +interface IUniswapV2Pair { + event Approval(address indexed owner, address indexed spender, uint value); + event Transfer(address indexed from, address indexed to, uint value); + + function name() external pure returns (string memory); + function symbol() external pure returns (string memory); + function decimals() external pure returns (uint8); + function totalSupply() external view returns (uint); + function balanceOf(address owner) external view returns (uint); + function allowance(address owner, address spender) external view returns (uint); + + function approve(address spender, uint value) external returns (bool); + function transfer(address to, uint value) external returns (bool); + function transferFrom(address from, address to, uint value) external returns (bool); + + function DOMAIN_SEPARATOR() external view returns (bytes32); + function PERMIT_TYPEHASH() external pure returns (bytes32); + function nonces(address owner) external view returns (uint); + + function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; + + event Mint(address indexed sender, uint amount0, uint amount1); + event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); + event Swap( + address indexed sender, + uint amount0In, + uint amount1In, + uint amount0Out, + uint amount1Out, + address indexed to + ); + event Sync(uint112 reserve0, uint112 reserve1); + + function MINIMUM_LIQUIDITY() external pure returns (uint); + function factory() external view returns (address); + function token0() external view returns (address); + function token1() external view returns (address); + function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); + function price0CumulativeLast() external view returns (uint); + function price1CumulativeLast() external view returns (uint); + function kLast() external view returns (uint); + + function mint(address to) external returns (uint liquidity); + function burn(address to) external returns (uint amount0, uint amount1); + function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; + function skim(address to) external; + function sync() external; + + function initialize(address, address) external; +} \ No newline at end of file diff --git a/packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IUniswapV2Router01.sol b/packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IUniswapV2Router01.sol new file mode 100644 index 000000000000..0058a03607cd --- /dev/null +++ b/packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IUniswapV2Router01.sol @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.2; + +interface IUniswapV2Router01 { + function factory() external pure returns (address); + // CHANGE_OMGX + //function WETH() external view returns (address); + + function addLiquidity( + address tokenA, + address tokenB, + uint amountADesired, + uint amountBDesired, + uint amountAMin, + uint amountBMin, + address to, + uint deadline + ) external returns (uint amountA, uint amountB, uint liquidity); + // CHANGE_OMGX + // function addLiquidityETH( + // address token, + // uint amountTokenDesired, + // uint amountTokenMin, + // uint amountETHMin, + // address to, + // uint deadline + // ) external payable returns (uint amountToken, uint amountETH, uint liquidity); + function removeLiquidity( + address tokenA, + address tokenB, + uint liquidity, + uint amountAMin, + uint amountBMin, + address to, + uint deadline + ) external returns (uint amountA, uint amountB); + // CHANGE_OMGX + // function removeLiquidityETH( + // address token, + // uint liquidity, + // uint amountTokenMin, + // uint amountETHMin, + // address to, + // uint deadline + // ) external returns (uint amountToken, uint amountETH); + function removeLiquidityWithPermit( + address tokenA, + address tokenB, + uint liquidity, + uint amountAMin, + uint amountBMin, + address to, + uint deadline, + bool approveMax, uint8 v, bytes32 r, bytes32 s + ) external returns (uint amountA, uint amountB); + // CHANGE_OMGX + // function removeLiquidityETHWithPermit( + // address token, + // uint liquidity, + // uint amountTokenMin, + // uint amountETHMin, + // address to, + // uint deadline, + // bool approveMax, uint8 v, bytes32 r, bytes32 s + // ) external returns (uint amountToken, uint amountETH); + function swapExactTokensForTokens( + uint amountIn, + uint amountOutMin, + address[] calldata path, + address to, + uint deadline + ) external returns (uint[] memory amounts); + function swapTokensForExactTokens( + uint amountOut, + uint amountInMax, + address[] calldata path, + address to, + uint deadline + ) external returns (uint[] memory amounts); + // CHANGE_OMGX + // function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) + // external + // payable + // returns (uint[] memory amounts); + // function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) + // external + // returns (uint[] memory amounts); + // function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) + // external + // returns (uint[] memory amounts); + // function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) + // external + // payable + // returns (uint[] memory amounts); + + function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB); + function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut); + function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn); + function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); + function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts); +} \ No newline at end of file diff --git a/packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IUniswapV2Router02.sol b/packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IUniswapV2Router02.sol new file mode 100644 index 000000000000..9c5c95dc33cb --- /dev/null +++ b/packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IUniswapV2Router02.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.2; + +import './IUniswapV2Router01.sol'; + +interface IUniswapV2Router02 is IUniswapV2Router01 { + // CHANGE_OMGX + // function removeLiquidityETHSupportingFeeOnTransferTokens( + // address token, + // uint liquidity, + // uint amountTokenMin, + // uint amountETHMin, + // address to, + // uint deadline + // ) external returns (uint amountETH); + // function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens( + // address token, + // uint liquidity, + // uint amountTokenMin, + // uint amountETHMin, + // address to, + // uint deadline, + // bool approveMax, uint8 v, bytes32 r, bytes32 s + // ) external returns (uint amountETH); + + function swapExactTokensForTokensSupportingFeeOnTransferTokens( + uint amountIn, + uint amountOutMin, + address[] calldata path, + address to, + uint deadline + ) external; + // CHANGE_OMGX + // function swapExactETHForTokensSupportingFeeOnTransferTokens( + // uint amountOutMin, + // address[] calldata path, + // address to, + // uint deadline + // ) external payable; + // function swapExactTokensForETHSupportingFeeOnTransferTokens( + // uint amountIn, + // uint amountOutMin, + // address[] calldata path, + // address to, + // uint deadline + // ) external; +} \ No newline at end of file diff --git a/packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IWETH.sol b/packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IWETH.sol new file mode 100644 index 000000000000..96b77b74204d --- /dev/null +++ b/packages/omgx/offchain-prototype/contracts/uniswapv2/interfaces/IWETH.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.5.0; +// CHANGE_OMGX +// interface IWETH { +// function deposit() external payable; +// function transfer(address to, uint value) external returns (bool); +// function withdraw(uint) external; +// } \ No newline at end of file diff --git a/packages/omgx/offchain-prototype/contracts/uniswapv2/libraries/Math.sol b/packages/omgx/offchain-prototype/contracts/uniswapv2/libraries/Math.sol new file mode 100644 index 000000000000..d183d80ba13a --- /dev/null +++ b/packages/omgx/offchain-prototype/contracts/uniswapv2/libraries/Math.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity =0.6.12; + +// a library for performing various math operations + +library Math { + function min(uint x, uint y) internal pure returns (uint z) { + z = x < y ? x : y; + } + + // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method) + function sqrt(uint y) internal pure returns (uint z) { + if (y > 3) { + z = y; + uint x = y / 2 + 1; + while (x < z) { + z = x; + x = (y / x + x) / 2; + } + } else if (y != 0) { + z = 1; + } + } +} diff --git a/packages/omgx/offchain-prototype/contracts/uniswapv2/libraries/SafeMath.sol b/packages/omgx/offchain-prototype/contracts/uniswapv2/libraries/SafeMath.sol new file mode 100644 index 000000000000..c472bfa025ce --- /dev/null +++ b/packages/omgx/offchain-prototype/contracts/uniswapv2/libraries/SafeMath.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity =0.6.12; + +// a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math) + +library SafeMathUniswap { + function add(uint x, uint y) internal pure returns (uint z) { + require((z = x + y) >= x, 'ds-math-add-overflow'); + } + + function sub(uint x, uint y) internal pure returns (uint z) { + require((z = x - y) <= x, 'ds-math-sub-underflow'); + } + + function mul(uint x, uint y) internal pure returns (uint z) { + require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow'); + } + + function div(uint256 a, uint256 b) internal pure returns (uint256) { + return div(a, b, "SafeMath: division by zero"); + } + + function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + // Solidity only automatically asserts when dividing by 0 + require(b > 0, errorMessage); + uint256 c = a / b; + // assert(a == b * c + a % b); // There is no case in which this doesn't hold + + return c; + } + + function sub(int256 a, int256 b) internal pure returns (int256) { + int256 c = a - b; + require((b >= 0 && c <= a) || (b < 0 && c > a), "SignedSafeMath: subtraction overflow"); + return c; + } +} diff --git a/packages/omgx/offchain-prototype/contracts/uniswapv2/libraries/TransferHelper.sol b/packages/omgx/offchain-prototype/contracts/uniswapv2/libraries/TransferHelper.sol new file mode 100644 index 000000000000..d179a67a9648 --- /dev/null +++ b/packages/omgx/offchain-prototype/contracts/uniswapv2/libraries/TransferHelper.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0; + +// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false +library TransferHelper { + function safeApprove(address token, address to, uint value) internal { + // bytes4(keccak256(bytes('approve(address,uint256)'))); + (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value)); + require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED'); + } + + function safeTransfer(address token, address to, uint value) internal { + // bytes4(keccak256(bytes('transfer(address,uint256)'))); + (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value)); + require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED'); + } + + function safeTransferFrom(address token, address from, address to, uint value) internal { + // bytes4(keccak256(bytes('transferFrom(address,address,uint256)'))); + (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value)); + require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED'); + } + + function safeTransferETH(address to, uint value) internal { + (bool success,) = to.call{value:value}(new bytes(0)); + require(success, 'TransferHelper: ETH_TRANSFER_FAILED'); + } +} diff --git a/packages/omgx/offchain-prototype/contracts/uniswapv2/libraries/UQ112x112.sol b/packages/omgx/offchain-prototype/contracts/uniswapv2/libraries/UQ112x112.sol new file mode 100644 index 000000000000..9af8f74975b3 --- /dev/null +++ b/packages/omgx/offchain-prototype/contracts/uniswapv2/libraries/UQ112x112.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity =0.6.12; + +// a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format)) + +// range: [0, 2**112 - 1] +// resolution: 1 / 2**112 + +library UQ112x112 { + uint224 constant Q112 = 2**112; + + // encode a uint112 as a UQ112x112 + function encode(uint112 y) internal pure returns (uint224 z) { + z = uint224(y) * Q112; // never overflows + } + + // divide a UQ112x112 by a uint112, returning a UQ112x112 + function uqdiv(uint224 x, uint112 y) internal pure returns (uint224 z) { + z = x / uint224(y); + } +} diff --git a/packages/omgx/offchain-prototype/contracts/uniswapv2/libraries/UniswapV2Library.sol b/packages/omgx/offchain-prototype/contracts/uniswapv2/libraries/UniswapV2Library.sol new file mode 100644 index 000000000000..14cffb0583f6 --- /dev/null +++ b/packages/omgx/offchain-prototype/contracts/uniswapv2/libraries/UniswapV2Library.sol @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.5.0; + +import '../interfaces/IUniswapV2Pair.sol'; + +import "./SafeMath.sol"; + +library UniswapV2Library { + using SafeMathUniswap for uint; + + // returns sorted token addresses, used to handle return values from pairs sorted in this order + function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) { + require(tokenA != tokenB, 'UniswapV2Library: IDENTICAL_ADDRESSES'); + (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); + require(token0 != address(0), 'UniswapV2Library: ZERO_ADDRESS'); + } + + // calculates the CREATE2 address for a pair without making any external calls + function pairFor(address factory, address tokenA, address tokenB) internal pure returns (address pair) { + (address token0, address token1) = sortTokens(tokenA, tokenB); + pair = address(uint(keccak256(abi.encodePacked( + hex'ff', + factory, + keccak256(abi.encodePacked(token0, token1)), + hex'e18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c6303' // init code hash + )))); + } + + // fetches and sorts the reserves for a pair + function getReserves(address factory, address tokenA, address tokenB) internal view returns (uint reserveA, uint reserveB) { + (address token0,) = sortTokens(tokenA, tokenB); + (uint reserve0, uint reserve1,) = IUniswapV2Pair(pairFor(factory, tokenA, tokenB)).getReserves(); + (reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0); + } + + // given some amount of an asset and pair reserves, returns an equivalent amount of the other asset + function quote(uint amountA, uint reserveA, uint reserveB) internal pure returns (uint amountB) { + require(amountA > 0, 'UniswapV2Library: INSUFFICIENT_AMOUNT'); + require(reserveA > 0 && reserveB > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY'); + amountB = amountA.mul(reserveB) / reserveA; + } + + // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset + function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint amountOut) { + require(amountIn > 0, 'UniswapV2Library: INSUFFICIENT_INPUT_AMOUNT'); + require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY'); + uint amountInWithFee = amountIn.mul(997); + uint numerator = amountInWithFee.mul(reserveOut); + uint denominator = reserveIn.mul(1000).add(amountInWithFee); + amountOut = numerator / denominator; + } + + // given an output amount of an asset and pair reserves, returns a required input amount of the other asset + function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) internal pure returns (uint amountIn) { + require(amountOut > 0, 'UniswapV2Library: INSUFFICIENT_OUTPUT_AMOUNT'); + require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY'); + uint numerator = reserveIn.mul(amountOut).mul(1000); + uint denominator = reserveOut.sub(amountOut).mul(997); + amountIn = (numerator / denominator).add(1); + } + + // performs chained getAmountOut calculations on any number of pairs + function getAmountsOut(address factory, uint amountIn, address[] memory path) internal view returns (uint[] memory amounts) { + require(path.length >= 2, 'UniswapV2Library: INVALID_PATH'); + amounts = new uint[](path.length); + amounts[0] = amountIn; + for (uint i; i < path.length - 1; i++) { + (uint reserveIn, uint reserveOut) = getReserves(factory, path[i], path[i + 1]); + amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut); + } + } + + // performs chained getAmountIn calculations on any number of pairs + function getAmountsIn(address factory, uint amountOut, address[] memory path) internal view returns (uint[] memory amounts) { + require(path.length >= 2, 'UniswapV2Library: INVALID_PATH'); + amounts = new uint[](path.length); + amounts[amounts.length - 1] = amountOut; + for (uint i = path.length - 1; i > 0; i--) { + (uint reserveIn, uint reserveOut) = getReserves(factory, path[i - 1], path[i]); + amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut); + } + } +} diff --git a/packages/omgx/offchain-prototype/hardhat.config.ts b/packages/omgx/offchain-prototype/hardhat.config.ts index 29e18f48a74d..674765b44ed7 100644 --- a/packages/omgx/offchain-prototype/hardhat.config.ts +++ b/packages/omgx/offchain-prototype/hardhat.config.ts @@ -18,9 +18,9 @@ const config: HardhatUserConfig = { ovm: false, }, }, - solidity: '0.7.6', + solidity: '0.6.12', ovm: { - solcVersion: '0.7.6', + solcVersion: '0.6.12', }, } diff --git a/packages/omgx/offchain-prototype/package.json b/packages/omgx/offchain-prototype/package.json index c52b4e4612f1..de8145cd0a67 100644 --- a/packages/omgx/offchain-prototype/package.json +++ b/packages/omgx/offchain-prototype/package.json @@ -27,6 +27,7 @@ "typescript": "^4.2.3" }, "dependencies": { + "@uniswap/sdk": "^3.0.3", "ip": "^1.1.5" } } diff --git a/packages/omgx/offchain-prototype/test/fee-test.ts b/packages/omgx/offchain-prototype/test/fee-test.ts new file mode 100644 index 000000000000..e08eb33da08b --- /dev/null +++ b/packages/omgx/offchain-prototype/test/fee-test.ts @@ -0,0 +1,165 @@ +import { BigNumber, Contract, ContractFactory, providers, Wallet } from 'ethers' +import { ethers } from 'hardhat' +import chai, { expect } from 'chai' +import { solidity } from 'ethereum-waffle' +chai.use(solidity) +const abiDecoder = require('web3-eth-abi') + +import hre from 'hardhat' +const cfg = hre.network.config +const hPort = 5678 // Port for local HTTP server +var urlStr +const gasOverride = {} // Can specify e.g. {gasPrice:0, gasLimit:999999} if needed + +// import HelloTuringJson_1 from "../artifacts/contracts/HelloTuring.sol/HelloTuring.json" +// import HelloTuringJson_2 from "../artifacts-ovm/contracts/HelloTuring.sol/HelloTuring.json" +// import TuringHelper_1 from "../artifacts/contracts/TuringHelper.sol/TuringHelper.json" +// import TuringHelper_2 from "../artifacts-ovm/contracts/TuringHelper.sol/TuringHelper.json" +import UniswapV2PairJSON from "../artifacts-ovm/contracts/uniswapv2/UniswapV2Pair.sol/UniswapV2Pair.json" +import TuringHelper_2 from "../artifacts-ovm/contracts/TuringHelper.sol/TuringHelper.json" + +let Factory__Uni: ContractFactory +let uni: Contract +let Factory__Helper: ContractFactory +let helper: Contract + + +const local_provider = new providers.JsonRpcProvider(cfg['url']) + +// Key for Hardhat test account #13 (0x1cbd3b2770909d4e10f157cabc84c7264073c9ec) +const testPrivateKey = '0x47c99abed3324a2707c28affff1267e45918ec8c3f20b8aa892e8b065d2942dd' +const testWallet = new Wallet(testPrivateKey, local_provider) +const L1 = !cfg['ovm'] + +describe("L2_Only", function() { + // It is no longer feasible to mock out enough of the l2geth functionality to support + // an L1 version of these tests. + + it("should not be run on an L1 chain", async() => { + expect(L1).to.be.false + }) +}) + +describe("feeTest", function() { + + before(async () => { + var http = require('http'); + var ip = require("ip") + + var server = module.exports = http.createServer(function (req, res) { + if (req.headers['content-type'] === 'application/json') { + var body = ''; + req.on('data', function (chunk) { + body += chunk.toString(); + }); + + req.on('end', async function () { + + var jBody = JSON.parse(body) + //console.log ("jBody", jBody) + + // if (jBody.method === "hello") { + // res.writeHead(200, {'Content-Type': 'application/json'}); + // var answer = "(UNDEFINED)" + // var v3=jBody.params[0] + // var v4 = abiDecoder.decodeParameter('string',v3) + + // switch(v4) { + // case 'EN_US': + // answer = "Hello World" + // break; + // case 'EN_GB': + // answer = "Top of the Morning" + // break; + // case 'FR': + // answer = "Bonjour le monde" + // break; + // default: + // answer = "(UNDEFINED)" // FIXME This should return an error. + // break; + // } + // console.log (" (HTTP) Returning off-chain response:", v4, "->", answer) + // var jResp = { + // "jsonrpc": "2.0", + // "id": jBody.id, + // "result": abiDecoder.encodeParameter('string',answer) + // } + // res.end(JSON.stringify(jResp)) + // server.emit('success', body); + // } + if (jBody.method === "add2") { + + let v1 = jBody.params[0] + + const args = abiDecoder.decodeParameters(['address','address'], v1) + var tokenAddress0 = String(args[0]); + var tokenAddress1 = String(args[1]); + + + const { ChainId, Fetcher, WETH, Route } = require('@uniswap/sdk'); + const chainId = ChainId.MAINNET; + // Hardcoding for test purposes + tokenAddress0 = '0x6B175474E89094C44Da98b954EedeAC495271d0F'; // DAI + tokenAddress1 = '0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce'; // SHIB + const init = async () => { + const token0 = await Fetcher.fetchTokenData(chainId, tokenAddress0); + const token1 = await Fetcher.fetchTokenData(chainId, tokenAddress1); + // const weth = WETH[chainId]; + const pair = await Fetcher.fetchPairData(token0, token1); + const route = new Route([pair], token0); + console.log(Math.trunc(route.midPrice.toSignificant(6))); + const sum = Math.trunc(route.midPrice.toSignificant(6)); + return sum; + } + let sum = await init(); + + res.writeHead(200, {'Content-Type': 'application/json'}); + console.log (" (HTTP) Returning off-chain response:", args, "->", sum) + var jResp2 = { + "jsonrpc": "2.0", + "id": jBody.id, + "result": abiDecoder.encodeParameter('uint256', sum) + } + res.end(JSON.stringify(jResp2)) + server.emit('success', body); + } else { + res.writeHead(400, {'Content-Type': 'text/plain'}); + res.end('Unknown method'); + } + + }); + + } else { + res.writeHead(400, {'Content-Type': 'text/plain'}); + res.end('Expected content-type: application/json'); + }; + }).listen(hPort); + + // Get a non-localhost IP address of the local machine, as the target for the off-chain request + urlStr = "http://" + ip.address() + ":" + hPort + console.log(" Created local HTTP server at", urlStr) + + Factory__Helper = new ContractFactory( + (TuringHelper_2.abi), + (TuringHelper_2.bytecode), + testWallet) + + helper = await Factory__Helper.deploy(urlStr, gasOverride) + console.log(" Helper contract deployed as", helper.address, "on","L2") + + await(helper.RegisterMethod(ethers.utils.toUtf8Bytes("hello"))); + await(helper.RegisterMethod(ethers.utils.toUtf8Bytes("add2"))); + + Factory__Uni = new ContractFactory( + (UniswapV2PairJSON.abi), + (UniswapV2PairJSON.bytecode), + testWallet) + + uni = await Factory__Uni.deploy(helper.address, gasOverride) + console.log(" Test contract deployed as", uni.address) + }) + + it("run uniswap with proper fees", async() => { + let sum = await uni.offChainCompare(1000, 1000) + }) +}) diff --git a/packages/omgx/offchain-prototype/test/hello-test.ts b/packages/omgx/offchain-prototype/test/hello-test.ts index 33acd1701792..69175c6c6e52 100644 --- a/packages/omgx/offchain-prototype/test/hello-test.ts +++ b/packages/omgx/offchain-prototype/test/hello-test.ts @@ -31,7 +31,7 @@ const L1 = !cfg['ovm'] describe("L2_Only", function() { // It is no longer feasible to mock out enough of the l2geth functionality to support - // an L1 version of these tests. + // an L1 version of these tests. it("should not be run on an L1 chain", async() => { expect(L1).to.be.false @@ -61,7 +61,7 @@ describe("HelloTest", function() { var answer = "(UNDEFINED)" var v3=jBody.params[0] var v4 = abiDecoder.decodeParameter('string',v3) - + switch(v4) { case 'EN_US': answer = "Hello World" @@ -85,13 +85,13 @@ describe("HelloTest", function() { res.end(JSON.stringify(jResp)) server.emit('success', body); } else if (jBody.method === "add2") { - + let v1 = jBody.params[0] const args = abiDecoder.decodeParameters(['uint256','uint256'], v1) - + let sum = Number(args['0']) + Number(args['1']) - + res.writeHead(200, {'Content-Type': 'application/json'}); console.log (" (HTTP) Returning off-chain response:", args, "->", sum) var jResp2 = { @@ -162,7 +162,7 @@ describe("HelloTest", function() { let msg2 = hello.PersonalGreeting(gasOverride) expect (await msg2).to.equal("Top of the Morning") }) - + it("should support numerical datatypes", async() => { let sum = hello.AddNumbers(20, 22) expect (await sum).to.equal(42) diff --git a/packages/omgx/offchain-prototype/test/stable-test.ts b/packages/omgx/offchain-prototype/test/stable-test.ts new file mode 100644 index 000000000000..894d5231b618 --- /dev/null +++ b/packages/omgx/offchain-prototype/test/stable-test.ts @@ -0,0 +1,151 @@ +import { BigNumber, Contract, ContractFactory, providers, Wallet } from 'ethers' +import { ethers } from 'hardhat' +import chai, { expect } from 'chai' +import { solidity } from 'ethereum-waffle' +chai.use(solidity) +const abiDecoder = require('web3-eth-abi') + +import hre from 'hardhat' +const cfg = hre.network.config +const hPort = 9009 // Port for local HTTP server +var urlStr +const gasOverride = {} // Can specify e.g. {gasPrice:0, gasLimit:999999} if needed + +// import HelloTuringJson_1 from "../artifacts/contracts/HelloTuring.sol/HelloTuring.json" +// import HelloTuringJson_2 from "../artifacts-ovm/contracts/HelloTuring.sol/HelloTuring.json" +// import TuringHelper_1 from "../artifacts/contracts/TuringHelper.sol/TuringHelper.json" +// import TuringHelper_2 from "../artifacts-ovm/contracts/TuringHelper.sol/TuringHelper.json" +import StableSwapJSON from "../artifacts-ovm/contracts/StableSwap.sol/StableSwap.json" +import TuringHelper_2 from "../artifacts-ovm/contracts/TuringHelper.sol/TuringHelper.json" + +let Factory__Stable: ContractFactory +let Stable: Contract +let Factory__Helper: ContractFactory +let helper: Contract + + +const local_provider = new providers.JsonRpcProvider(cfg['url']) + +// Key for Hardhat test account #13 (0x1cbd3b2770909d4e10f157cabc84c7264073c9ec) +const testPrivateKey = '0x47c99abed3324a2707c28affff1267e45918ec8c3f20b8aa892e8b065d2942dd' +const testWallet = new Wallet(testPrivateKey, local_provider) +const L1 = !cfg['ovm'] + +describe("L2_Only", function() { + // It is no longer feasible to mock out enough of the l2geth functionality to support + // an L1 version of these tests. + + it("should not be run on an L1 chain", async() => { + expect(L1).to.be.false + }) +}) + +describe("StableTest", function() { + + before(async () => { + var http = require('http'); + var ip = require("ip") + + var server = module.exports = http.createServer(function (req, res) { + if (req.headers['content-type'] === 'application/json') { + var body = ''; + req.on('data', function (chunk) { + body += chunk.toString(); + }); + + req.on('end', async function () { + + var jBody = JSON.parse(body) + //console.log ("jBody", jBody) + + // if (jBody.method === "hello") { + // res.writeHead(200, {'Content-Type': 'application/json'}); + // var answer = "(UNDEFINED)" + // var v3=jBody.params[0] + // var v4 = abiDecoder.decodeParameter('string',v3) + + // switch(v4) { + // case 'EN_US': + // answer = "Hello World" + // break; + // case 'EN_GB': + // answer = "Top of the Morning" + // break; + // case 'FR': + // answer = "Bonjour le monde" + // break; + // default: + // answer = "(UNDEFINED)" // FIXME This should return an error. + // break; + // } + // console.log (" (HTTP) Returning off-chain response:", v4, "->", answer) + // var jResp = { + // "jsonrpc": "2.0", + // "id": jBody.id, + // "result": abiDecoder.encodeParameter('string',answer) + // } + // res.end(JSON.stringify(jResp)) + // server.emit('success', body); + // } + if (jBody.method === "add2") { + + let v1 = jBody.params[0] + + const args = abiDecoder.decodeParameters(['uint256'], v1) + var argNum = Number(args[0]); + + // argNum = 9009 + + let sum = Math.trunc(Math.sqrt(argNum)); + + + res.writeHead(200, {'Content-Type': 'application/json'}); + console.log (" (HTTP) Returning off-chain response:", args, "->", sum) + var jResp2 = { + "jsonrpc": "2.0", + "id": jBody.id, + "result": abiDecoder.encodeParameter('uint256', sum) + } + res.end(JSON.stringify(jResp2)) + server.emit('success', body); + } else { + res.writeHead(400, {'Content-Type': 'text/plain'}); + res.end('Unknown method'); + } + + }); + + } else { + res.writeHead(400, {'Content-Type': 'text/plain'}); + res.end('Expected content-type: application/json'); + }; + }).listen(hPort); + + // Get a non-localhost IP address of the local machine, as the target for the off-chain request + urlStr = "http://" + ip.address() + ":" + hPort + console.log(" Created local HTTP server at", urlStr) + + Factory__Helper = new ContractFactory( + (TuringHelper_2.abi), + (TuringHelper_2.bytecode), + testWallet) + + helper = await Factory__Helper.deploy(urlStr, gasOverride) + console.log(" Helper contract deployed as", helper.address, "on","L2") + + await(helper.RegisterMethod(ethers.utils.toUtf8Bytes("hello"))); + await(helper.RegisterMethod(ethers.utils.toUtf8Bytes("add2"))); + + Factory__Stable = new ContractFactory( + (StableSwapJSON.abi), + (StableSwapJSON.bytecode), + testWallet) + + Stable = await Factory__Stable.deploy(helper.address,1000,1000, gasOverride) + console.log(" Test contract deployed as", Stable.address) + }) + + it("calculate square root off-chain", async() => { + let sum = await Stable.sqrt(9009) + }) +}) diff --git a/yarn.lock b/yarn.lock index 34ef6a139984..3597e56bc54a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4958,6 +4958,24 @@ resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== +"@uniswap/sdk@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@uniswap/sdk/-/sdk-3.0.3.tgz#8201c7c72215d0030cb99acc7e661eff895c18a9" + integrity sha512-t4s8bvzaCFSiqD2qfXIm3rWhbdnXp+QjD3/mRaeVDHK7zWevs6RGEb1ohMiNgOCTZANvBayb4j8p+XFdnMBadQ== + dependencies: + "@uniswap/v2-core" "^1.0.0" + big.js "^5.2.2" + decimal.js-light "^2.5.0" + jsbi "^3.1.1" + tiny-invariant "^1.1.0" + tiny-warning "^1.0.3" + toformat "^2.0.0" + +"@uniswap/v2-core@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@uniswap/v2-core/-/v2-core-1.0.1.tgz#af8f508bf183204779938969e2e54043e147d425" + integrity sha512-MtybtkUPSyysqLY2U210NBDeCHX+ltHt3oADGdjqoThZaFRDKwM6k1Nb3F0A3hk5hwuQvytFWhrWHOEq6nVJ8Q== + "@webassemblyjs/ast@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.8.5.tgz#51b1c5fe6576a34953bf4b253df9f0d490d9e359" @@ -8795,6 +8813,11 @@ decamelize@^4.0.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== +decimal.js-light@^2.5.0: + version "2.5.1" + resolved "https://registry.yarnpkg.com/decimal.js-light/-/decimal.js-light-2.5.1.tgz#134fd32508f19e208f4fb2f8dac0d2626a867934" + integrity sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg== + decode-uri-component@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" @@ -14059,6 +14082,11 @@ js-yaml@4.0.0: dependencies: argparse "^2.0.1" +jsbi@^3.1.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/jsbi/-/jsbi-3.2.1.tgz#513a8f404abb9d5ba725f5265265b688215ee9f0" + integrity sha512-NzcT09wuJReIO829enrY3yRdHFz+ciVIq01PCGPkHlwIv5Dj9v2F4daQ4akwuPHf6xO/oii4Jrd3BsPepOxXrg== + jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" @@ -21680,7 +21708,7 @@ timsort@^0.3.0: resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= -tiny-invariant@^1.0.2: +tiny-invariant@^1.0.2, tiny-invariant@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875" integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw== @@ -21761,6 +21789,11 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" +toformat@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/toformat/-/toformat-2.0.0.tgz#7a043fd2dfbe9021a4e36e508835ba32056739d8" + integrity sha512-03SWBVop6nU8bpyZCx7SodpYznbZF5R4ljwNLBcTQzKOD9xuihRo/psX58llS1BMFhhAI08H3luot5GoXJz2pQ== + toggle-selection@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32"