From a1579ddb6697c59ead27ac9ec2a82e2a95d28ae4 Mon Sep 17 00:00:00 2001 From: mingda Date: Fri, 26 Jun 2020 00:31:25 +0800 Subject: [PATCH 001/118] first commit --- .babelrc | 3 + .env | 4 + .eslintrc.yaml | 17 + .gitattributes | 1 + .gitignore | 16 + .prettierrc | 15 + .solcover.js | 16 + LICENSE | 201 + README.md | 7 + contracts/DODOEthProxy.sol | 128 + contracts/DODOZoo.sol | 78 + contracts/dodo.sol | 61 + contracts/helper/Migrations.sol | 34 + contracts/helper/NaiveOracle.sol | 25 + contracts/helper/TestERC20.sol | 65 + contracts/helper/TestWETH.sol | 77 + contracts/impl/Admin.sol | 83 + contracts/impl/DODOLpToken.sol | 118 + contracts/impl/LiquidityProvider.sol | 309 + contracts/impl/Pricing.sol | 186 + contracts/impl/Settlement.sol | 143 + contracts/impl/Storage.sol | 106 + contracts/impl/Trader.sol | 243 + contracts/intf/IDODO.sol | 46 + contracts/intf/IDODOLpToken.sol | 20 + contracts/intf/IDODOZoo.sol | 14 + contracts/intf/IERC20.sol | 84 + contracts/intf/IOracle.sol | 14 + contracts/intf/IWETH.sol | 32 + contracts/lib/DODOMath.sol | 117 + contracts/lib/DecimalMath.sol | 35 + contracts/lib/Ownable.sol | 43 + contracts/lib/ReentrancyGuard.sol | 32 + contracts/lib/SafeERC20.sol | 74 + contracts/lib/SafeMath.sol | 63 + contracts/lib/Types.sol | 14 + coverage.json | 1 + migrations/1_initial_migration.js | 5 + migrations/2_deploy.js | 27 + package-lock.json | 10691 +++++++++++++++++++++++++ package.json | 55 + test/Admin.test.ts | 340 + test/Attacks.test.ts | 157 + test/DODOEthProxy.test.ts | 104 + test/DODOZoo.test.ts | 68 + test/LiquidityProvider.test.ts | 446 ++ test/LongTailTokenlMode.test.ts | 94 + test/StableCoinMode.test.ts | 103 + test/Trader.test.ts | 281 + test/utils/Context.ts | 127 + test/utils/Contracts.ts | 112 + test/utils/Converter.ts | 11 + test/utils/EVM.ts | 83 + test/utils/Log.ts | 29 + test/utils/SlippageFormula.ts | 11 + tsconfig.json | 21 + tslint.json | 13 + yarn.lock | 5667 +++++++++++++ 58 files changed, 20970 insertions(+) create mode 100644 .babelrc create mode 100644 .env create mode 100644 .eslintrc.yaml create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .prettierrc create mode 100644 .solcover.js create mode 100644 LICENSE create mode 100644 README.md create mode 100644 contracts/DODOEthProxy.sol create mode 100644 contracts/DODOZoo.sol create mode 100644 contracts/dodo.sol create mode 100644 contracts/helper/Migrations.sol create mode 100644 contracts/helper/NaiveOracle.sol create mode 100644 contracts/helper/TestERC20.sol create mode 100644 contracts/helper/TestWETH.sol create mode 100644 contracts/impl/Admin.sol create mode 100644 contracts/impl/DODOLpToken.sol create mode 100644 contracts/impl/LiquidityProvider.sol create mode 100644 contracts/impl/Pricing.sol create mode 100644 contracts/impl/Settlement.sol create mode 100644 contracts/impl/Storage.sol create mode 100644 contracts/impl/Trader.sol create mode 100644 contracts/intf/IDODO.sol create mode 100644 contracts/intf/IDODOLpToken.sol create mode 100644 contracts/intf/IDODOZoo.sol create mode 100644 contracts/intf/IERC20.sol create mode 100644 contracts/intf/IOracle.sol create mode 100644 contracts/intf/IWETH.sol create mode 100644 contracts/lib/DODOMath.sol create mode 100644 contracts/lib/DecimalMath.sol create mode 100644 contracts/lib/Ownable.sol create mode 100644 contracts/lib/ReentrancyGuard.sol create mode 100644 contracts/lib/SafeERC20.sol create mode 100644 contracts/lib/SafeMath.sol create mode 100644 contracts/lib/Types.sol create mode 100644 coverage.json create mode 100644 migrations/1_initial_migration.js create mode 100644 migrations/2_deploy.js create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 test/Admin.test.ts create mode 100644 test/Attacks.test.ts create mode 100644 test/DODOEthProxy.test.ts create mode 100644 test/DODOZoo.test.ts create mode 100644 test/LiquidityProvider.test.ts create mode 100644 test/LongTailTokenlMode.test.ts create mode 100644 test/StableCoinMode.test.ts create mode 100644 test/Trader.test.ts create mode 100644 test/utils/Context.ts create mode 100644 test/utils/Contracts.ts create mode 100644 test/utils/Converter.ts create mode 100644 test/utils/EVM.ts create mode 100644 test/utils/Log.ts create mode 100644 test/utils/SlippageFormula.ts create mode 100644 tsconfig.json create mode 100644 tslint.json create mode 100644 yarn.lock diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..ce6eb60 --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["es2015", "stage-2", "stage-3"] +} diff --git a/.env b/.env new file mode 100644 index 0000000..c237685 --- /dev/null +++ b/.env @@ -0,0 +1,4 @@ +RPC_NODE_URI=http://127.0.0.1:8545 +RESET_SNAPSHOT_ID=0x2 +NETWORK_ID=5777 +GAS_PRICE=1 diff --git a/.eslintrc.yaml b/.eslintrc.yaml new file mode 100644 index 0000000..2f13d88 --- /dev/null +++ b/.eslintrc.yaml @@ -0,0 +1,17 @@ +extends: airbnb-base +parser: babel-eslint + +env: + node: true + es6: true + +globals: + artifacts: true + +rules: + no-use-before-define: 0 + class-methods-use-this: 0 + no-underscore-dangle: 0 + max-len: + - error + - 100 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..7cc88f0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.sol linguist-language=Solidity \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6b61b66 --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +.coverage* +.DS_Store +.env.local +.idea + +build/ +dist/ +docs/ +node_modules/ +coverage/ +lint/ + +# VIM +*.swo +*.swp + diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..2bf0ebc --- /dev/null +++ b/.prettierrc @@ -0,0 +1,15 @@ +{ + "overrides": [ + { + "files": "*.sol", + "options": { + "printWidth": 100, + "tabWidth": 4, + "useTabs": false, + "singleQuote": false, + "bracketSpacing": false, + "explicitTypes": "always" + } + } + ] +} diff --git a/.solcover.js b/.solcover.js new file mode 100644 index 0000000..8c8ae1d --- /dev/null +++ b/.solcover.js @@ -0,0 +1,16 @@ +module.exports = { + client: require("ganache-cli"), + port: 6545, + testrpcOptions: + "--port 6545 -l 0x1fffffffffffff -i 1002 -g 1 --allowUnlimitedContractSize", + skipFiles: [ + "lib/SafeMath.sol", + "lib/DecimalMath.sol", + "lib/Types.sol", + "lib/ReentrancyGuard.sol", + "lib/Ownable.sol", + "impl/DODOLpToken.sol", + "intf", + "helper", + ], +}; diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..ba0539c --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# DODO:10x better liquidity than uniswap + +✍️[Introducing DODO](https://medium.com/@dodo.in.the.zoo/introducing-dodo-10x-better-liquidity-than-uniswap-852ce2137c57) + +- Current AMM failed in providing comparable liquidity in mainstream trading pairs because AMM cannot really work as human market makers. +- DODO is based on a brand new market maker algorithm with an essential idea of risk neutrality to keep liquidity providers’ portfolio stable. +- Compared with AMMs, DODO will perform 10x better in liquidity. diff --git a/contracts/DODOEthProxy.sol b/contracts/DODOEthProxy.sol new file mode 100644 index 0000000..5961f14 --- /dev/null +++ b/contracts/DODOEthProxy.sol @@ -0,0 +1,128 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {ReentrancyGuard} from "./lib/ReentrancyGuard.sol"; +import {SafeERC20} from "./lib/SafeERC20.sol"; +import {IDODO} from "./intf/IDODO.sol"; +import {IDODOZoo} from "./intf/IDODOZoo.sol"; +import {IERC20} from "./intf/IERC20.sol"; +import {IWETH} from "./intf/IWETH.sol"; + + +/** + * @title DODO Eth Proxy + * @author DODO Breeder + * + * @notice Handle ETH-WETH converting for users + */ +contract DODOEthProxy is ReentrancyGuard { + using SafeERC20 for IERC20; + + address public _DODO_ZOO_; + address payable public _WETH_; + + // ============ Events ============ + + event ProxySellEth( + address indexed seller, + address indexed quoteToken, + uint256 payEth, + uint256 receiveQuote + ); + + event ProxyBuyEth( + address indexed buyer, + address indexed quoteToken, + uint256 receiveEth, + uint256 payQuote + ); + + event ProxyDepositEth(address indexed lp, address indexed quoteToken, uint256 ethAmount); + + // ============ Functions ============ + + constructor(address dodoZoo, address payable weth) public { + _DODO_ZOO_ = dodoZoo; + _WETH_ = weth; + } + + fallback() external payable { + require(msg.sender == _WETH_, "WE_SAVED_YOUR_ETH_:)"); + } + + receive() external payable { + require(msg.sender == _WETH_, "WE_SAVED_YOUR_ETH_:)"); + } + + function sellEthTo( + address quoteTokenAddress, + uint256 ethAmount, + uint256 minReceiveTokenAmount + ) external payable preventReentrant returns (uint256 receiveTokenAmount) { + require(msg.value == ethAmount, "ETH_AMOUNT_NOT_MATCH"); + address DODO = IDODOZoo(_DODO_ZOO_).getDODO(_WETH_, quoteTokenAddress); + receiveTokenAmount = IDODO(DODO).querySellBaseToken(ethAmount); + require(receiveTokenAmount >= minReceiveTokenAmount, "RECEIVE_NOT_ENOUGH"); + IWETH(_WETH_).deposit{value: ethAmount}(); + IWETH(_WETH_).approve(DODO, ethAmount); + IDODO(DODO).sellBaseToken(ethAmount, minReceiveTokenAmount); + _transferOut(quoteTokenAddress, msg.sender, receiveTokenAmount); + emit ProxySellEth(msg.sender, quoteTokenAddress, ethAmount, receiveTokenAmount); + return receiveTokenAmount; + } + + function buyEthWith( + address quoteTokenAddress, + uint256 ethAmount, + uint256 maxPayTokenAmount + ) external preventReentrant returns (uint256 payTokenAmount) { + address DODO = IDODOZoo(_DODO_ZOO_).getDODO(_WETH_, quoteTokenAddress); + payTokenAmount = IDODO(DODO).queryBuyBaseToken(ethAmount); + require(payTokenAmount <= maxPayTokenAmount, "PAY_TOO_MUCH"); + _transferIn(quoteTokenAddress, msg.sender, payTokenAmount); + IERC20(quoteTokenAddress).approve(DODO, payTokenAmount); + IDODO(DODO).buyBaseToken(ethAmount, maxPayTokenAmount); + IWETH(_WETH_).withdraw(ethAmount); + msg.sender.transfer(ethAmount); + emit ProxyBuyEth(msg.sender, quoteTokenAddress, ethAmount, payTokenAmount); + return payTokenAmount; + } + + function depositEth(uint256 ethAmount, address quoteTokenAddress) + external + payable + preventReentrant + { + require(msg.value == ethAmount, "ETH_AMOUNT_NOT_MATCH"); + address DODO = IDODOZoo(_DODO_ZOO_).getDODO(_WETH_, quoteTokenAddress); + IWETH(_WETH_).deposit{value: ethAmount}(); + IWETH(_WETH_).approve(DODO, ethAmount); + IDODO(DODO).depositBaseTo(msg.sender, ethAmount); + emit ProxyDepositEth(msg.sender, quoteTokenAddress, ethAmount); + } + + // ============ Helper Functions ============ + + function _transferIn( + address tokenAddress, + address from, + uint256 amount + ) internal { + IERC20(tokenAddress).safeTransferFrom(from, address(this), amount); + } + + function _transferOut( + address tokenAddress, + address to, + uint256 amount + ) internal { + IERC20(tokenAddress).safeTransfer(to, amount); + } +} diff --git a/contracts/DODOZoo.sol b/contracts/DODOZoo.sol new file mode 100644 index 0000000..1025a21 --- /dev/null +++ b/contracts/DODOZoo.sol @@ -0,0 +1,78 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {Ownable} from "./lib/Ownable.sol"; +import {IDODO} from "./intf/IDODO.sol"; +import {DODO} from "./DODO.sol"; + + +/** + * @title DODOZoo + * @author DODO Breeder + * + * @notice Register of All DODO + */ +contract DODOZoo is Ownable { + mapping(address => mapping(address => address)) internal _DODO_REGISTER_; + + // ============ Events ============ + + event DODOBirth(address newBorn); + + // ============ Breed DODO Function ============ + + function breedDODO( + address supervisor, + address maintainer, + address baseToken, + address quoteToken, + address oracle, + uint256 lpFeeRate, + uint256 mtFeeRate, + uint256 k, + uint256 gasPriceLimit + ) public onlyOwner returns (address) { + require(!isDODORegistered(baseToken, quoteToken), "DODO_IS_REGISTERED"); + require(baseToken != quoteToken, "BASE_IS_SAME_WITH_QUOTE"); + address newBornDODO = address(new DODO()); + IDODO(newBornDODO).init( + supervisor, + maintainer, + baseToken, + quoteToken, + oracle, + lpFeeRate, + mtFeeRate, + k, + gasPriceLimit + ); + IDODO(newBornDODO).transferOwnership(_OWNER_); + _DODO_REGISTER_[baseToken][quoteToken] = newBornDODO; + emit DODOBirth(newBornDODO); + return newBornDODO; + } + + // ============ View Functions ============ + + function isDODORegistered(address baseToken, address quoteToken) public view returns (bool) { + if ( + _DODO_REGISTER_[baseToken][quoteToken] == address(0) && + _DODO_REGISTER_[quoteToken][baseToken] == address(0) + ) { + return false; + } else { + return true; + } + } + + function getDODO(address baseToken, address quoteToken) external view returns (address) { + return _DODO_REGISTER_[baseToken][quoteToken]; + } +} diff --git a/contracts/dodo.sol b/contracts/dodo.sol new file mode 100644 index 0000000..f62d664 --- /dev/null +++ b/contracts/dodo.sol @@ -0,0 +1,61 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {Types} from "./lib/Types.sol"; +import {Storage} from "./impl/Storage.sol"; +import {Trader} from "./impl/Trader.sol"; +import {LiquidityProvider} from "./impl/LiquidityProvider.sol"; +import {Admin} from "./impl/Admin.sol"; +import {DODOLpToken} from "./impl/DODOLpToken.sol"; + + +/** + * @title DODO + * @author DODO Breeder + * + * @notice Entrance for users + */ +contract DODO is Admin, Trader, LiquidityProvider { + function init( + address supervisor, + address maintainer, + address baseToken, + address quoteToken, + address oracle, + uint256 lpFeeRate, + uint256 mtFeeRate, + uint256 k, + uint256 gasPriceLimit + ) external onlyOwner preventReentrant { + require(!_INITIALIZED_, "DODO_ALREADY_INITIALIZED"); + _INITIALIZED_ = true; + + _SUPERVISOR_ = supervisor; + _MAINTAINER_ = maintainer; + _BASE_TOKEN_ = baseToken; + _QUOTE_TOKEN_ = quoteToken; + _ORACLE_ = oracle; + + _DEPOSIT_BASE_ALLOWED_ = true; + _DEPOSIT_QUOTE_ALLOWED_ = true; + _TRADE_ALLOWED_ = true; + _GAS_PRICE_LIMIT_ = gasPriceLimit; + + _LP_FEE_RATE_ = lpFeeRate; + _MT_FEE_RATE_ = mtFeeRate; + _K_ = k; + _R_STATUS_ = Types.RStatus.ONE; + + _BASE_CAPITAL_TOKEN_ = address(new DODOLpToken()); + _QUOTE_CAPITAL_TOKEN_ = address(new DODOLpToken()); + + _checkDODOParameters(); + } +} diff --git a/contracts/helper/Migrations.sol b/contracts/helper/Migrations.sol new file mode 100644 index 0000000..c8f809e --- /dev/null +++ b/contracts/helper/Migrations.sol @@ -0,0 +1,34 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + + +contract Migrations { + address public owner; + uint256 public last_completed_migration; + + modifier restricted() { + if (msg.sender == owner) { + _; + } + } + + constructor() public { + owner = msg.sender; + } + + function setCompleted(uint256 completed) public restricted { + last_completed_migration = completed; + } + + function upgrade(address newAddress) public restricted { + Migrations upgraded = Migrations(newAddress); + upgraded.setCompleted(last_completed_migration); + } +} diff --git a/contracts/helper/NaiveOracle.sol b/contracts/helper/NaiveOracle.sol new file mode 100644 index 0000000..b472960 --- /dev/null +++ b/contracts/helper/NaiveOracle.sol @@ -0,0 +1,25 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {Ownable} from "../lib/Ownable.sol"; + + +// Oracle only for test +contract NaiveOracle is Ownable { + uint256 public tokenPrice; + + function setPrice(uint256 newPrice) external onlyOwner { + tokenPrice = newPrice; + } + + function getPrice() external view returns (uint256) { + return tokenPrice; + } +} diff --git a/contracts/helper/TestERC20.sol b/contracts/helper/TestERC20.sol new file mode 100644 index 0000000..85acc3b --- /dev/null +++ b/contracts/helper/TestERC20.sol @@ -0,0 +1,65 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; + +import {SafeMath} from "../lib/SafeMath.sol"; + + +contract TestERC20 { + using SafeMath for uint256; + + mapping(address => uint256) balances; + mapping(address => mapping(address => uint256)) internal allowed; + + event Transfer(address indexed from, address indexed to, uint256 amount); + event Approval(address indexed owner, address indexed spender, uint256 amount); + + function transfer(address to, uint256 amount) public returns (bool) { + require(to != address(0), "TO_ADDRESS_IS_EMPTY"); + require(amount <= balances[msg.sender], "BALANCE_NOT_ENOUGH"); + + balances[msg.sender] = balances[msg.sender].sub(amount); + balances[to] = balances[to].add(amount); + emit Transfer(msg.sender, to, amount); + return true; + } + + function balanceOf(address owner) public view returns (uint256 balance) { + return balances[owner]; + } + + function transferFrom( + address from, + address to, + uint256 amount + ) public returns (bool) { + require(to != address(0), "TO_ADDRESS_IS_EMPTY"); + require(amount <= balances[from], "BALANCE_NOT_ENOUGH"); + require(amount <= allowed[from][msg.sender], "ALLOWANCE_NOT_ENOUGH"); + + balances[from] = balances[from].sub(amount); + balances[to] = balances[to].add(amount); + allowed[from][msg.sender] = allowed[from][msg.sender].sub(amount); + emit Transfer(from, to, amount); + return true; + } + + function approve(address spender, uint256 amount) public returns (bool) { + allowed[msg.sender][spender] = amount; + emit Approval(msg.sender, spender, amount); + return true; + } + + function allowance(address owner, address spender) public view returns (uint256) { + return allowed[owner][spender]; + } + + function mint(address account, uint256 amount) external { + balances[account] = balances[account].add(amount); + } +} diff --git a/contracts/helper/TestWETH.sol b/contracts/helper/TestWETH.sol new file mode 100644 index 0000000..4ebf56c --- /dev/null +++ b/contracts/helper/TestWETH.sol @@ -0,0 +1,77 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; + + +contract WETH9 { + string public name = "Wrapped Ether"; + string public symbol = "WETH"; + uint8 public decimals = 18; + + event Approval(address indexed src, address indexed guy, uint256 wad); + event Transfer(address indexed src, address indexed dst, uint256 wad); + event Deposit(address indexed dst, uint256 wad); + event Withdrawal(address indexed src, uint256 wad); + + mapping(address => uint256) public balanceOf; + mapping(address => mapping(address => uint256)) public allowance; + + fallback() external payable { + deposit(); + } + + receive() external payable { + deposit(); + } + + function deposit() public payable { + balanceOf[msg.sender] += msg.value; + emit Deposit(msg.sender, msg.value); + } + + function withdraw(uint256 wad) public { + require(balanceOf[msg.sender] >= wad); + balanceOf[msg.sender] -= wad; + msg.sender.transfer(wad); + emit Withdrawal(msg.sender, wad); + } + + function totalSupply() public view returns (uint256) { + return address(this).balance; + } + + function approve(address guy, uint256 wad) public returns (bool) { + allowance[msg.sender][guy] = wad; + emit Approval(msg.sender, guy, wad); + return true; + } + + function transfer(address dst, uint256 wad) public returns (bool) { + return transferFrom(msg.sender, dst, wad); + } + + function transferFrom( + address src, + address dst, + uint256 wad + ) public returns (bool) { + require(balanceOf[src] >= wad); + + if (src != msg.sender && allowance[src][msg.sender] != uint256(-1)) { + require(allowance[src][msg.sender] >= wad); + allowance[src][msg.sender] -= wad; + } + + balanceOf[src] -= wad; + balanceOf[dst] += wad; + + Transfer(src, dst, wad); + + return true; + } +} diff --git a/contracts/impl/Admin.sol b/contracts/impl/Admin.sol new file mode 100644 index 0000000..9e0a7a1 --- /dev/null +++ b/contracts/impl/Admin.sol @@ -0,0 +1,83 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {Storage} from "./Storage.sol"; + +/** + * @title Admin + * @author DODO Breeder + * + * @notice Functions for admin operations + */ +contract Admin is Storage { + // ============ Events ============ + + event UpdateGasPriceLimit(uint256 newGasPriceLimit); + + // ============ Params Setting Functions ============ + + function setOracle(address newOracle) external onlyOwner { + _ORACLE_ = newOracle; + } + + function setSupervisor(address newSupervisor) external onlyOwner { + _SUPERVISOR_ = newSupervisor; + } + + function setMaintainer(address newMaintainer) external onlyOwner { + _MAINTAINER_ = newMaintainer; + } + + function setLiquidityProviderFeeRate(uint256 newLiquidityPorviderFeeRate) external onlyOwner { + _LP_FEE_RATE_ = newLiquidityPorviderFeeRate; + _checkDODOParameters(); + } + + function setMaintainerFeeRate(uint256 newMaintainerFeeRate) external onlyOwner { + _MT_FEE_RATE_ = newMaintainerFeeRate; + _checkDODOParameters(); + } + + function setK(uint256 newK) external onlyOwner { + _K_ = newK; + _checkDODOParameters(); + } + + function setGasPriceLimit(uint256 newGasPriceLimit) external onlySupervisorOrOwner { + _GAS_PRICE_LIMIT_ = newGasPriceLimit; + emit UpdateGasPriceLimit(newGasPriceLimit); + } + + // ============ System Control Functions ============ + + function disableTrading() external onlySupervisorOrOwner { + _TRADE_ALLOWED_ = false; + } + + function enableTrading() external onlyOwner notClosed { + _TRADE_ALLOWED_ = true; + } + + function disableQuoteDeposit() external onlySupervisorOrOwner { + _DEPOSIT_QUOTE_ALLOWED_ = false; + } + + function enableQuoteDeposit() external onlyOwner notClosed { + _DEPOSIT_QUOTE_ALLOWED_ = true; + } + + function disableBaseDeposit() external onlySupervisorOrOwner { + _DEPOSIT_BASE_ALLOWED_ = false; + } + + function enableBaseDeposit() external onlyOwner notClosed { + _DEPOSIT_BASE_ALLOWED_ = true; + } +} diff --git a/contracts/impl/DODOLpToken.sol b/contracts/impl/DODOLpToken.sol new file mode 100644 index 0000000..6268b4f --- /dev/null +++ b/contracts/impl/DODOLpToken.sol @@ -0,0 +1,118 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {SafeMath} from "../lib/SafeMath.sol"; +import {Ownable} from "../lib/Ownable.sol"; + +/** + * @title DODOLpToken + * @author DODO Breeder + * + * @notice Tokenize liquidity pool assets. An ordinary ERC20 contract with mint and burn functions + */ +contract DODOLpToken is Ownable { + using SafeMath for uint256; + + uint256 public totalSupply; + mapping(address => uint256) internal balances; + mapping(address => mapping(address => uint256)) internal allowed; + + // ============ Events ============ + + event Transfer(address indexed from, address indexed to, uint256 amount); + + event Approval(address indexed owner, address indexed spender, uint256 amount); + + event Mint(address indexed user, uint256 value); + + event Burn(address indexed user, uint256 value); + + // ============ Functions ============ + + /** + * @dev transfer token for a specified address + * @param to The address to transfer to. + * @param amount The amount to be transferred. + */ + function transfer(address to, uint256 amount) public returns (bool) { + require(to != address(0), "TO_ADDRESS_IS_EMPTY"); + require(amount <= balances[msg.sender], "BALANCE_NOT_ENOUGH"); + + balances[msg.sender] = balances[msg.sender].sub(amount); + balances[to] = balances[to].add(amount); + emit Transfer(msg.sender, to, amount); + return true; + } + + /** + * @dev Gets the balance of the specified address. + * @param owner The address to query the the balance of. + * @return balance An uint256 representing the amount owned by the passed address. + */ + function balanceOf(address owner) external view returns (uint256 balance) { + return balances[owner]; + } + + /** + * @dev Transfer tokens from one address to another + * @param from address The address which you want to send tokens from + * @param to address The address which you want to transfer to + * @param amount uint256 the amount of tokens to be transferred + */ + function transferFrom( + address from, + address to, + uint256 amount + ) public returns (bool) { + require(to != address(0), "TO_ADDRESS_IS_EMPTY"); + require(amount <= balances[from], "BALANCE_NOT_ENOUGH"); + require(amount <= allowed[from][msg.sender], "ALLOWANCE_NOT_ENOUGH"); + + balances[from] = balances[from].sub(amount); + balances[to] = balances[to].add(amount); + allowed[from][msg.sender] = allowed[from][msg.sender].sub(amount); + emit Transfer(from, to, amount); + return true; + } + + /** + * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. + * @param spender The address which will spend the funds. + * @param amount The amount of tokens to be spent. + */ + function approve(address spender, uint256 amount) public returns (bool) { + allowed[msg.sender][spender] = amount; + emit Approval(msg.sender, spender, amount); + return true; + } + + /** + * @dev Function to check the amount of tokens that an owner allowed to a spender. + * @param owner address The address which owns the funds. + * @param spender address The address which will spend the funds. + * @return A uint256 specifying the amount of tokens still available for the spender. + */ + function allowance(address owner, address spender) public view returns (uint256) { + return allowed[owner][spender]; + } + + function mint(address user, uint256 value) external onlyOwner { + balances[user] = balances[user].add(value); + totalSupply = totalSupply.add(value); + emit Mint(address(0), value); + emit Transfer(address(0), user, value); + } + + function burn(address user, uint256 value) external onlyOwner { + balances[user] = balances[user].sub(value); + totalSupply = totalSupply.sub(value); + emit Burn(user, value); + } +} diff --git a/contracts/impl/LiquidityProvider.sol b/contracts/impl/LiquidityProvider.sol new file mode 100644 index 0000000..9f84e3b --- /dev/null +++ b/contracts/impl/LiquidityProvider.sol @@ -0,0 +1,309 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {SafeMath} from "../lib/SafeMath.sol"; +import {DecimalMath} from "../lib/DecimalMath.sol"; +import {DODOMath} from "../lib/DODOMath.sol"; +import {Types} from "../lib/Types.sol"; +import {IDODOLpToken} from "../intf/IDODOLpToken.sol"; +import {Storage} from "./Storage.sol"; +import {Settlement} from "./Settlement.sol"; +import {Pricing} from "./Pricing.sol"; + + +/** + * @title LiquidityProvider + * @author DODO Breeder + * + * @notice Functions for liquidity provider operations + */ +contract LiquidityProvider is Storage, Pricing, Settlement { + using SafeMath for uint256; + + // ============ Events ============ + + event DepositBaseToken(address indexed payer, address indexed receiver, uint256 amount); + + event DepositQuoteToken(address indexed payer, address indexed receiver, uint256 amount); + + event WithdrawBaseToken(address indexed payer, address indexed receiver, uint256 amount); + + event WithdrawQuoteToken(address indexed payer, address indexed receiver, uint256 amount); + + event ChargeBasePenalty(address indexed payer, uint256 amount); + + event ChargeQuotePenalty(address indexed payer, uint256 amount); + + // ============ Modifiers ============ + + modifier depositQuoteAllowed() { + require(_DEPOSIT_QUOTE_ALLOWED_, "DEPOSIT_QUOTE_NOT_ALLOWED"); + _; + } + + modifier depositBaseAllowed() { + require(_DEPOSIT_BASE_ALLOWED_, "DEPOSIT_BASE_NOT_ALLOWED"); + _; + } + + // ============ Routine Functions ============ + + function withdrawBase(uint256 amount) external returns (uint256) { + return withdrawBaseTo(msg.sender, amount); + } + + function depositBase(uint256 amount) external { + depositBaseTo(msg.sender, amount); + } + + function withdrawQuote(uint256 amount) external returns (uint256) { + return withdrawQuoteTo(msg.sender, amount); + } + + function depositQuote(uint256 amount) external { + depositQuoteTo(msg.sender, amount); + } + + function withdrawAllBase() external returns (uint256) { + return withdrawAllBaseTo(msg.sender); + } + + function withdrawAllQuote() external returns (uint256) { + return withdrawAllQuoteTo(msg.sender); + } + + // ============ Deposit Functions ============ + + function depositQuoteTo(address to, uint256 amount) + public + preventReentrant + depositQuoteAllowed + { + (, uint256 quoteTarget) = _getExpectedTarget(); + uint256 capital = amount; + uint256 totalQuoteCapital = getTotalQuoteCapital(); + if (totalQuoteCapital == 0) { + capital = amount.add(quoteTarget); // give remaining quote token to lp as a gift + } + if (quoteTarget > 0 && totalQuoteCapital > 0) { + capital = amount.mul(totalQuoteCapital).div(quoteTarget); + } + // settlement + _quoteTokenTransferIn(msg.sender, amount); + _mintQuoteTokenCapital(to, capital); + _TARGET_QUOTE_TOKEN_AMOUNT_ = _TARGET_QUOTE_TOKEN_AMOUNT_.add(amount); + + emit DepositQuoteToken(msg.sender, to, amount); + } + + function depositBaseTo(address to, uint256 amount) public preventReentrant depositBaseAllowed { + (uint256 baseTarget, ) = _getExpectedTarget(); + uint256 capital = amount; + uint256 totalBaseCapital = getTotalBaseCapital(); + if (totalBaseCapital == 0) { + capital = amount.add(baseTarget); // give remaining base token to lp as a gift + } + if (baseTarget > 0 && totalBaseCapital > 0) { + capital = amount.mul(totalBaseCapital).div(baseTarget); + } + // settlement + _baseTokenTransferIn(msg.sender, amount); + _mintBaseTokenCapital(to, capital); + _TARGET_BASE_TOKEN_AMOUNT_ = _TARGET_BASE_TOKEN_AMOUNT_.add(amount); + + emit DepositBaseToken(msg.sender, to, amount); + } + + // ============ Withdraw Functions ============ + + function withdrawQuoteTo(address to, uint256 amount) public preventReentrant returns (uint256) { + uint256 Q = _QUOTE_BALANCE_; + require(amount <= Q, "DODO_QUOTE_TOKEN_BALANCE_NOT_ENOUGH"); + + // calculate capital + (, uint256 quoteTarget) = _getExpectedTarget(); + uint256 requireQuoteCapital = amount.mul(getTotalQuoteCapital()).divCeil(quoteTarget); + require( + requireQuoteCapital <= getQuoteCapitalBalanceOf(msg.sender), + "LP_QUOTE_CAPITAL_BALANCE_NOT_ENOUGH" + ); + + // handle penalty, penalty may exceed amount + uint256 penalty = getWithdrawQuotePenalty(amount); + require(penalty <= amount, "COULD_NOT_AFFORD_LIQUIDITY_PENALTY"); + + // settlement + _TARGET_QUOTE_TOKEN_AMOUNT_ = _TARGET_QUOTE_TOKEN_AMOUNT_.sub(amount); + _burnQuoteTokenCapital(msg.sender, requireQuoteCapital); + _quoteTokenTransferOut(to, amount.sub(penalty)); + _donateQuoteToken(penalty); + + emit WithdrawQuoteToken(msg.sender, to, amount.sub(penalty)); + emit ChargeQuotePenalty(msg.sender, penalty); + + return amount.sub(penalty); + } + + function withdrawBaseTo(address to, uint256 amount) public preventReentrant returns (uint256) { + uint256 B = _BASE_BALANCE_; + require(amount <= B, "DODO_BASE_TOKEN_BALANCE_NOT_ENOUGH"); + + // calculate capital + (uint256 baseTarget, ) = _getExpectedTarget(); + uint256 requireBaseCapital = amount.mul(getTotalBaseCapital()).divCeil(baseTarget); + require( + requireBaseCapital <= getBaseCapitalBalanceOf(msg.sender), + "LP_BASE_CAPITAL_BALANCE_NOT_ENOUGH" + ); + + // handle penalty, penalty may exceed amount + uint256 penalty = getWithdrawBasePenalty(amount); + require(penalty <= amount, "COULD_NOT_AFFORD_LIQUIDITY_PENALTY"); + + // settlement + _TARGET_BASE_TOKEN_AMOUNT_ = _TARGET_BASE_TOKEN_AMOUNT_.sub(amount); + _burnBaseTokenCapital(msg.sender, requireBaseCapital); + _baseTokenTransferOut(to, amount.sub(penalty)); + _donateBaseToken(penalty); + + emit WithdrawBaseToken(msg.sender, to, amount.sub(penalty)); + emit ChargeBasePenalty(msg.sender, penalty); + + return amount.sub(penalty); + } + + // ============ Withdraw all Functions ============ + + function withdrawAllQuoteTo(address to) public preventReentrant returns (uint256) { + uint256 Q = _QUOTE_BALANCE_; + uint256 withdrawAmount = getLpQuoteBalance(msg.sender); + require(withdrawAmount <= Q, "DODO_QUOTE_TOKEN_BALANCE_NOT_ENOUGH"); + + // handle penalty, penalty may exceed amount + uint256 penalty = getWithdrawQuotePenalty(withdrawAmount); + require(penalty <= withdrawAmount, "COULD_NOT_AFFORD_LIQUIDITY_PENALTY"); + + // settlement + _TARGET_QUOTE_TOKEN_AMOUNT_ = _TARGET_QUOTE_TOKEN_AMOUNT_.sub(withdrawAmount); + _burnQuoteTokenCapital(msg.sender, getQuoteCapitalBalanceOf(msg.sender)); + _quoteTokenTransferOut(to, withdrawAmount.sub(penalty)); + _donateQuoteToken(penalty); + + emit WithdrawQuoteToken(msg.sender, to, withdrawAmount); + emit ChargeQuotePenalty(msg.sender, penalty); + + return withdrawAmount.sub(penalty); + } + + function withdrawAllBaseTo(address to) public preventReentrant returns (uint256) { + uint256 B = _BASE_BALANCE_; + uint256 withdrawAmount = getLpBaseBalance(msg.sender); + require(withdrawAmount <= B, "DODO_BASE_TOKEN_BALANCE_NOT_ENOUGH"); + + // handle penalty, penalty may exceed amount + uint256 penalty = getWithdrawBasePenalty(withdrawAmount); + require(penalty <= withdrawAmount, "COULD_NOT_AFFORD_LIQUIDITY_PENALTY"); + + // settlement + _TARGET_BASE_TOKEN_AMOUNT_ = _TARGET_BASE_TOKEN_AMOUNT_.sub(withdrawAmount); + _burnBaseTokenCapital(msg.sender, getBaseCapitalBalanceOf(msg.sender)); + _baseTokenTransferOut(to, withdrawAmount.sub(penalty)); + _donateBaseToken(penalty); + + emit WithdrawBaseToken(msg.sender, to, withdrawAmount); + emit ChargeBasePenalty(msg.sender, penalty); + + return withdrawAmount.sub(penalty); + } + + // ============ Helper Functions ============ + + function _mintBaseTokenCapital(address user, uint256 amount) internal { + IDODOLpToken(_BASE_CAPITAL_TOKEN_).mint(user, amount); + } + + function _mintQuoteTokenCapital(address user, uint256 amount) internal { + IDODOLpToken(_QUOTE_CAPITAL_TOKEN_).mint(user, amount); + } + + function _burnBaseTokenCapital(address user, uint256 amount) internal { + IDODOLpToken(_BASE_CAPITAL_TOKEN_).burn(user, amount); + } + + function _burnQuoteTokenCapital(address user, uint256 amount) internal { + IDODOLpToken(_QUOTE_CAPITAL_TOKEN_).burn(user, amount); + } + + // ============ Getter Functions ============ + + function getLpBaseBalance(address lp) public view returns (uint256 lpBalance) { + uint256 totalBaseCapital = getTotalBaseCapital(); + (uint256 baseTarget, ) = _getExpectedTarget(); + if (totalBaseCapital == 0) { + return 0; + } + lpBalance = getBaseCapitalBalanceOf(lp).mul(baseTarget).div(totalBaseCapital); + return lpBalance; + } + + function getLpQuoteBalance(address lp) public view returns (uint256 lpBalance) { + uint256 totalQuoteCapital = getTotalQuoteCapital(); + (, uint256 quoteTarget) = _getExpectedTarget(); + if (totalQuoteCapital == 0) { + return 0; + } + lpBalance = getQuoteCapitalBalanceOf(lp).mul(quoteTarget).div(totalQuoteCapital); + return lpBalance; + } + + function getWithdrawQuotePenalty(uint256 amount) public view returns (uint256 penalty) { + if (_R_STATUS_ == Types.RStatus.BELOW_ONE) { + require(amount < _QUOTE_BALANCE_, "DODO_QUOTE_BALANCE_NOT_ENOUGH"); + uint256 spareBase = _BASE_BALANCE_.sub(_TARGET_BASE_TOKEN_AMOUNT_); + uint256 price = getOraclePrice(); + uint256 fairAmount = DecimalMath.mul(spareBase, price); + uint256 targetQuote = DODOMath._SolveQuadraticFunctionForTarget( + _QUOTE_BALANCE_, + _K_, + fairAmount + ); + uint256 targetQuoteWithWithdraw = DODOMath._SolveQuadraticFunctionForTarget( + _QUOTE_BALANCE_.sub(amount), + _K_, + fairAmount + ); + return targetQuote.sub(targetQuoteWithWithdraw.add(amount)); + } else { + return 0; + } + } + + function getWithdrawBasePenalty(uint256 amount) public view returns (uint256 penalty) { + if (_R_STATUS_ == Types.RStatus.ABOVE_ONE) { + require(amount < _BASE_BALANCE_, "DODO_BASE_BALANCE_NOT_ENOUGH"); + uint256 spareQuote = _QUOTE_BALANCE_.sub(_TARGET_QUOTE_TOKEN_AMOUNT_); + uint256 price = getOraclePrice(); + uint256 fairAmount = DecimalMath.divFloor(spareQuote, price); + uint256 targetBase = DODOMath._SolveQuadraticFunctionForTarget( + _BASE_BALANCE_, + _K_, + fairAmount + ); + uint256 targetBaseWithWithdraw = DODOMath._SolveQuadraticFunctionForTarget( + _BASE_BALANCE_.sub(amount), + _K_, + fairAmount + ); + return targetBase.sub(targetBaseWithWithdraw.add(amount)); + } else { + return 0; + } + } +} diff --git a/contracts/impl/Pricing.sol b/contracts/impl/Pricing.sol new file mode 100644 index 0000000..d959941 --- /dev/null +++ b/contracts/impl/Pricing.sol @@ -0,0 +1,186 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {SafeMath} from "../lib/SafeMath.sol"; +import {DecimalMath} from "../lib/DecimalMath.sol"; +import {DODOMath} from "../lib/DODOMath.sol"; +import {Types} from "../lib/Types.sol"; +import {Storage} from "./Storage.sol"; + +/** + * @title Pricing + * @author DODO Breeder + * + * @notice DODO Pricing model + */ +contract Pricing is Storage { + using SafeMath for uint256; + + // ============ R = 1 cases ============ + + function _ROneSellBaseToken(uint256 amount, uint256 targetQuoteTokenAmount) + internal + view + returns (uint256 receiveQuoteToken) + { + uint256 i = getOraclePrice(); + uint256 Q2 = DODOMath._SolveQuadraticFunctionForTrade( + targetQuoteTokenAmount, + targetQuoteTokenAmount, + DecimalMath.mul(i, amount), + false, + _K_ + ); + // in theory Q2 <= targetQuoteTokenAmount + // however when amount is close to 0, precision problems may cause Q2 > targetQuoteTokenAmount + return targetQuoteTokenAmount.sub(Q2); + } + + function _ROneBuyBaseToken(uint256 amount, uint256 targetBaseTokenAmount) + internal + view + returns (uint256 payQuoteToken) + { + require(amount < targetBaseTokenAmount, "DODO_BASE_TOKEN_BALANCE_NOT_ENOUGH"); + uint256 B2 = targetBaseTokenAmount.sub(amount); + payQuoteToken = _RAboveIntegrate(targetBaseTokenAmount, targetBaseTokenAmount, B2); + return payQuoteToken; + } + + // ============ R < 1 cases ============ + + function _RBelowSellBaseToken( + uint256 amount, + uint256 quoteBalance, + uint256 targetQuoteAmount + ) internal view returns (uint256 receieQuoteToken) { + uint256 i = getOraclePrice(); + uint256 Q2 = DODOMath._SolveQuadraticFunctionForTrade( + targetQuoteAmount, + quoteBalance, + DecimalMath.mul(i, amount), + false, + _K_ + ); + return quoteBalance.sub(Q2); + } + + function _RBelowBuyBaseToken( + uint256 amount, + uint256 quoteBalance, + uint256 targetQuoteAmount + ) internal view returns (uint256 payQuoteToken) { + // Here we don't require amount less than some value + // Because it is limited at upper function + // See Trader.queryBuyBaseToken + uint256 i = getOraclePrice(); + uint256 Q2 = DODOMath._SolveQuadraticFunctionForTrade( + targetQuoteAmount, + quoteBalance, + DecimalMath.mul(i, amount), + true, + _K_ + ); + return Q2.sub(quoteBalance); + } + + function _RBelowBackToOne() + internal + view + returns (uint256 payQuoteToken, uint256 receiveBaseToken) + { + // important: carefully design the system to make sure spareBase always greater than or equal to 0 + uint256 spareBase = _BASE_BALANCE_.sub(_TARGET_BASE_TOKEN_AMOUNT_); + uint256 price = getOraclePrice(); + uint256 fairAmount = DecimalMath.mul(spareBase, price); + uint256 newTargetQuote = DODOMath._SolveQuadraticFunctionForTarget( + _QUOTE_BALANCE_, + _K_, + fairAmount + ); + return (newTargetQuote.sub(_QUOTE_BALANCE_), spareBase); + } + + // ============ R > 1 cases ============ + + function _RAboveBuyBaseToken( + uint256 amount, + uint256 baseBalance, + uint256 targetBaseAmount + ) internal view returns (uint256 payQuoteToken) { + require(amount < baseBalance, "DODO_BASE_TOKEN_BALANCE_NOT_ENOUGH"); + uint256 B2 = baseBalance.sub(amount); + return _RAboveIntegrate(targetBaseAmount, baseBalance, B2); + } + + function _RAboveSellBaseToken( + uint256 amount, + uint256 baseBalance, + uint256 targetBaseAmount + ) internal view returns (uint256 receiveQuoteToken) { + // here we don't require B1 <= targetBaseAmount + // Because it is limited at upper function + // See Trader.querySellBaseToken + uint256 B1 = baseBalance.add(amount); + return _RAboveIntegrate(targetBaseAmount, B1, baseBalance); + } + + function _RAboveBackToOne() + internal + view + returns (uint256 payBaseToken, uint256 receiveQuoteToken) + { + // important: carefully design the system to make sure spareBase always greater than or equal to 0 + uint256 spareQuote = _QUOTE_BALANCE_.sub(_TARGET_QUOTE_TOKEN_AMOUNT_); + uint256 price = getOraclePrice(); + uint256 fairAmount = DecimalMath.divFloor(spareQuote, price); + uint256 newTargetBase = DODOMath._SolveQuadraticFunctionForTarget( + _BASE_BALANCE_, + _K_, + fairAmount + ); + return (newTargetBase.sub(_BASE_BALANCE_), spareQuote); + } + + // ============ Helper functions ============ + + function _getExpectedTarget() internal view returns (uint256 baseTarget, uint256 quoteTarget) { + uint256 Q = _QUOTE_BALANCE_; + uint256 B = _BASE_BALANCE_; + if (_R_STATUS_ == Types.RStatus.ONE) { + return (_TARGET_BASE_TOKEN_AMOUNT_, _TARGET_QUOTE_TOKEN_AMOUNT_); + } else if (_R_STATUS_ == Types.RStatus.BELOW_ONE) { + (uint256 payQuoteToken, uint256 receiveBaseToken) = _RBelowBackToOne(); + return (B.sub(receiveBaseToken), Q.add(payQuoteToken)); + } else if (_R_STATUS_ == Types.RStatus.ABOVE_ONE) { + (uint256 payBaseToken, uint256 receiveQuoteToken) = _RAboveBackToOne(); + return (B.add(payBaseToken), Q.sub(receiveQuoteToken)); + } + } + + function _RAboveIntegrate( + uint256 B0, + uint256 B1, + uint256 B2 + ) internal view returns (uint256) { + uint256 i = getOraclePrice(); + return DODOMath._GeneralIntegrate(B0, B1, B2, i, _K_); + } + + // function _RBelowIntegrate( + // uint256 Q0, + // uint256 Q1, + // uint256 Q2 + // ) internal view returns (uint256) { + // uint256 i = getOraclePrice(); + // i = DecimalMath.divFloor(DecimalMath.ONE, i); // 1/i + // return DODOMath._GeneralIntegrate(Q0, Q1, Q2, i, _K_); + // } +} diff --git a/contracts/impl/Settlement.sol b/contracts/impl/Settlement.sol new file mode 100644 index 0000000..7a7d769 --- /dev/null +++ b/contracts/impl/Settlement.sol @@ -0,0 +1,143 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {SafeMath} from "../lib/SafeMath.sol"; +import {SafeERC20} from "../lib/SafeERC20.sol"; +import {DecimalMath} from "../lib/DecimalMath.sol"; +import {Types} from "../lib/Types.sol"; +import {IERC20} from "../intf/IERC20.sol"; +import {Storage} from "./Storage.sol"; + +/** + * @title Settlement + * @author DODO Breeder + * + * @notice Functions for assets settlement + */ +contract Settlement is Storage { + using SafeMath for uint256; + using SafeERC20 for IERC20; + + // ============ Events ============ + + event DonateBaseToken(uint256 amount); + + event DonateQuoteToken(uint256 amount); + + event Claim(address indexed user, uint256 baseTokenAmount, uint256 quoteTokenAmount); + + // ============ Assets IN/OUT Functions ============ + + function _baseTokenTransferIn(address from, uint256 amount) internal { + IERC20(_BASE_TOKEN_).safeTransferFrom(from, address(this), amount); + _BASE_BALANCE_ = _BASE_BALANCE_.add(amount); + } + + function _quoteTokenTransferIn(address from, uint256 amount) internal { + IERC20(_QUOTE_TOKEN_).safeTransferFrom(from, address(this), amount); + _QUOTE_BALANCE_ = _QUOTE_BALANCE_.add(amount); + } + + function _baseTokenTransferOut(address to, uint256 amount) internal { + IERC20(_BASE_TOKEN_).safeTransfer(to, amount); + _BASE_BALANCE_ = _BASE_BALANCE_.sub(amount); + } + + function _quoteTokenTransferOut(address to, uint256 amount) internal { + IERC20(_QUOTE_TOKEN_).safeTransfer(to, amount); + _QUOTE_BALANCE_ = _QUOTE_BALANCE_.sub(amount); + } + + // ============ Donate to Liquidity Pool Functions ============ + + function _donateBaseToken(uint256 amount) internal { + _TARGET_BASE_TOKEN_AMOUNT_ = _TARGET_BASE_TOKEN_AMOUNT_.add(amount); + emit DonateBaseToken(amount); + } + + function _donateQuoteToken(uint256 amount) internal { + _TARGET_QUOTE_TOKEN_AMOUNT_ = _TARGET_QUOTE_TOKEN_AMOUNT_.add(amount); + emit DonateQuoteToken(amount); + } + + function donateBaseToken(uint256 amount) external { + _baseTokenTransferIn(msg.sender, amount); + _donateBaseToken(amount); + } + + function donateQuoteToken(uint256 amount) external { + _quoteTokenTransferIn(msg.sender, amount); + _donateQuoteToken(amount); + } + + // ============ Final Settlement Functions ============ + + // last step to shut down dodo + function finalSettlement() external onlyOwner notClosed { + _CLOSED_ = true; + _DEPOSIT_QUOTE_ALLOWED_ = false; + _DEPOSIT_BASE_ALLOWED_ = false; + _TRADE_ALLOWED_ = false; + uint256 totalBaseCapital = getTotalBaseCapital(); + uint256 totalQuoteCapital = getTotalQuoteCapital(); + + if (_QUOTE_BALANCE_ > _TARGET_QUOTE_TOKEN_AMOUNT_) { + uint256 spareQuote = _QUOTE_BALANCE_.sub(_TARGET_QUOTE_TOKEN_AMOUNT_); + _BASE_CAPITAL_RECEIVE_QUOTE_ = DecimalMath.divFloor(spareQuote, totalBaseCapital); + } else { + _TARGET_QUOTE_TOKEN_AMOUNT_ = _QUOTE_BALANCE_; + } + + if (_BASE_BALANCE_ > _TARGET_BASE_TOKEN_AMOUNT_) { + uint256 spareBase = _BASE_BALANCE_.sub(_TARGET_BASE_TOKEN_AMOUNT_); + _QUOTE_CAPITAL_RECEIVE_BASE_ = DecimalMath.divFloor(spareBase, totalQuoteCapital); + } else { + _TARGET_BASE_TOKEN_AMOUNT_ = _BASE_BALANCE_; + } + + _R_STATUS_ = Types.RStatus.ONE; + } + + // claim remaining assets after final settlement + function claim() external preventReentrant { + require(_CLOSED_, "DODO_IS_NOT_CLOSED"); + require(!_CLAIMED_[msg.sender], "ALREADY_CLAIMED"); + _CLAIMED_[msg.sender] = true; + uint256 quoteAmount = DecimalMath.mul( + getBaseCapitalBalanceOf(msg.sender), + _BASE_CAPITAL_RECEIVE_QUOTE_ + ); + uint256 baseAmount = DecimalMath.mul( + getQuoteCapitalBalanceOf(msg.sender), + _QUOTE_CAPITAL_RECEIVE_BASE_ + ); + _baseTokenTransferOut(msg.sender, baseAmount); + _quoteTokenTransferOut(msg.sender, quoteAmount); + emit Claim(msg.sender, baseAmount, quoteAmount); + return; + } + + // in case someone transfer to contract directly + function retrieve(address token, uint256 amount) external onlyOwner { + if (token == _BASE_TOKEN_) { + require( + IERC20(_BASE_TOKEN_).balanceOf(address(this)) >= _BASE_BALANCE_.add(amount), + "DODO_BASE_BALANCE_NOT_ENOUGH" + ); + } + if (token == _QUOTE_TOKEN_) { + require( + IERC20(_QUOTE_TOKEN_).balanceOf(address(this)) >= _QUOTE_BALANCE_.add(amount), + "DODO_QUOTE_BALANCE_NOT_ENOUGH" + ); + } + IERC20(token).safeTransfer(msg.sender, amount); + } +} diff --git a/contracts/impl/Storage.sol b/contracts/impl/Storage.sol new file mode 100644 index 0000000..a56e5bd --- /dev/null +++ b/contracts/impl/Storage.sol @@ -0,0 +1,106 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {Ownable} from "../lib/Ownable.sol"; +import {SafeMath} from "../lib/SafeMath.sol"; +import {DecimalMath} from "../lib/DecimalMath.sol"; +import {ReentrancyGuard} from "../lib/ReentrancyGuard.sol"; +import {IOracle} from "../intf/IOracle.sol"; +import {IDODOLpToken} from "../intf/IDODOLpToken.sol"; +import {Types} from "../lib/Types.sol"; + +/** + * @title Storage + * @author DODO Breeder + * + * @notice Local Variables + */ +contract Storage is Ownable, ReentrancyGuard { + using SafeMath for uint256; + + // ============ Variables for Control ============ + + bool internal _INITIALIZED_; + bool public _CLOSED_; + bool public _DEPOSIT_QUOTE_ALLOWED_; + bool public _DEPOSIT_BASE_ALLOWED_; + bool public _TRADE_ALLOWED_; + uint256 public _GAS_PRICE_LIMIT_; + + // ============ Core Address ============ + + address public _SUPERVISOR_; // could freeze system in emergency + address public _MAINTAINER_; // collect maintainer fee to buy food for DODO + + address public _BASE_TOKEN_; + address public _QUOTE_TOKEN_; + address public _ORACLE_; + + // ============ Variables for PMM Algorithm ============ + + uint256 public _LP_FEE_RATE_; + uint256 public _MT_FEE_RATE_; + uint256 public _K_; + + Types.RStatus public _R_STATUS_; + uint256 public _TARGET_BASE_TOKEN_AMOUNT_; + uint256 public _TARGET_QUOTE_TOKEN_AMOUNT_; + uint256 public _BASE_BALANCE_; + uint256 public _QUOTE_BALANCE_; + + address public _BASE_CAPITAL_TOKEN_; + address public _QUOTE_CAPITAL_TOKEN_; + + // ============ Variables for Final Settlement ============ + + uint256 public _BASE_CAPITAL_RECEIVE_QUOTE_; + uint256 public _QUOTE_CAPITAL_RECEIVE_BASE_; + mapping(address => bool) public _CLAIMED_; + + // ============ Modifiers ============ + + modifier onlySupervisorOrOwner() { + require(msg.sender == _SUPERVISOR_ || msg.sender == _OWNER_, "NOT_SUPERVISOR_OR_OWNER"); + _; + } + + modifier notClosed() { + require(!_CLOSED_, "DODO_IS_CLOSED"); + _; + } + + // ============ Helper Functions ============ + + function _checkDODOParameters() internal view returns (uint256) { + require(_K_ < DecimalMath.ONE, "K_MUST_BE_LESS_THAN_ONE"); + require(_K_ > 0, "K_MUST_BE_GREATER_THAN_ZERO"); + require(_LP_FEE_RATE_.add(_MT_FEE_RATE_) < DecimalMath.ONE, "FEE_MUST_BE_LESS_THAN_ONE"); + } + + function getOraclePrice() public view returns (uint256) { + return IOracle(_ORACLE_).getPrice(); + } + + function getBaseCapitalBalanceOf(address lp) public view returns (uint256) { + return IDODOLpToken(_BASE_CAPITAL_TOKEN_).balanceOf(lp); + } + + function getTotalBaseCapital() public view returns (uint256) { + return IDODOLpToken(_BASE_CAPITAL_TOKEN_).totalSupply(); + } + + function getQuoteCapitalBalanceOf(address lp) public view returns (uint256) { + return IDODOLpToken(_QUOTE_CAPITAL_TOKEN_).balanceOf(lp); + } + + function getTotalQuoteCapital() public view returns (uint256) { + return IDODOLpToken(_QUOTE_CAPITAL_TOKEN_).totalSupply(); + } +} diff --git a/contracts/impl/Trader.sol b/contracts/impl/Trader.sol new file mode 100644 index 0000000..80d018c --- /dev/null +++ b/contracts/impl/Trader.sol @@ -0,0 +1,243 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {SafeMath} from "../lib/SafeMath.sol"; +import {DecimalMath} from "../lib/DecimalMath.sol"; +import {Types} from "../lib/Types.sol"; +import {Storage} from "./Storage.sol"; +import {Pricing} from "./Pricing.sol"; +import {Settlement} from "./Settlement.sol"; + +/** + * @title Trader + * @author DODO Breeder + * + * @notice Functions for trader operations + */ +contract Trader is Storage, Pricing, Settlement { + using SafeMath for uint256; + + // ============ Events ============ + + event SellBaseToken(address indexed seller, uint256 payBase, uint256 receiveQuote); + + event BuyBaseToken(address indexed buyer, uint256 receiveBase, uint256 payQuote); + + event MaintainerFee(bool isBaseToken, uint256 amount); + + // ============ Modifiers ============ + + modifier tradeAllowed() { + require(_TRADE_ALLOWED_, "TRADE_NOT_ALLOWED"); + _; + } + + modifier gasPriceLimit() { + require(tx.gasprice <= _GAS_PRICE_LIMIT_, "GAS_PRICE_EXCEED"); + _; + } + + // ============ Trade Functions ============ + + function sellBaseToken(uint256 amount, uint256 minReceiveQuote) + external + tradeAllowed + gasPriceLimit + preventReentrant + returns (uint256) + { + // query price + ( + uint256 receiveQuote, + uint256 lpFeeQuote, + uint256 mtFeeQuote, + Types.RStatus newRStatus, + uint256 newQuoteTarget, + uint256 newBaseTarget + ) = _querySellBaseToken(amount); + require(receiveQuote >= minReceiveQuote, "SELL_BASE_RECEIVE_NOT_ENOUGH"); + + // settle assets + _baseTokenTransferIn(msg.sender, amount); + _quoteTokenTransferOut(msg.sender, receiveQuote); + _quoteTokenTransferOut(_MAINTAINER_, mtFeeQuote); + + // update TARGET + _TARGET_QUOTE_TOKEN_AMOUNT_ = newQuoteTarget; + _TARGET_BASE_TOKEN_AMOUNT_ = newBaseTarget; + _R_STATUS_ = newRStatus; + + _donateQuoteToken(lpFeeQuote); + emit SellBaseToken(msg.sender, amount, receiveQuote); + emit MaintainerFee(false, mtFeeQuote); + + return receiveQuote; + } + + function buyBaseToken(uint256 amount, uint256 maxPayQuote) + external + tradeAllowed + gasPriceLimit + preventReentrant + returns (uint256) + { + // query price + ( + uint256 payQuote, + uint256 lpFeeBase, + uint256 mtFeeBase, + Types.RStatus newRStatus, + uint256 newQuoteTarget, + uint256 newBaseTarget + ) = _queryBuyBaseToken(amount); + require(payQuote <= maxPayQuote, "BUY_BASE_COST_TOO_MUCH"); + + // settle assets + _quoteTokenTransferIn(msg.sender, payQuote); + _baseTokenTransferOut(msg.sender, amount); + _baseTokenTransferOut(_MAINTAINER_, mtFeeBase); + + // update TARGET + _TARGET_QUOTE_TOKEN_AMOUNT_ = newQuoteTarget; + _TARGET_BASE_TOKEN_AMOUNT_ = newBaseTarget; + _R_STATUS_ = newRStatus; + + _donateBaseToken(lpFeeBase); + emit BuyBaseToken(msg.sender, amount, payQuote); + emit MaintainerFee(true, mtFeeBase); + + return payQuote; + } + + // ============ Query Functions ============ + + function querySellBaseToken(uint256 amount) external view returns (uint256 receiveQuote) { + (receiveQuote, , , , , ) = _querySellBaseToken(amount); + return receiveQuote; + } + + function queryBuyBaseToken(uint256 amount) external view returns (uint256 payQuote) { + (payQuote, , , , , ) = _queryBuyBaseToken(amount); + return payQuote; + } + + function _querySellBaseToken(uint256 amount) + internal + view + returns ( + uint256 receiveQuote, + uint256 lpFeeQuote, + uint256 mtFeeQuote, + Types.RStatus newRStatus, + uint256 newQuoteTarget, + uint256 newBaseTarget + ) + { + (newBaseTarget, newQuoteTarget) = _getExpectedTarget(); + + uint256 sellBaseAmount = amount; + + if (_R_STATUS_ == Types.RStatus.ONE) { + // case 1: R=1 + // R falls below one + receiveQuote = _ROneSellBaseToken(sellBaseAmount, newQuoteTarget); + newRStatus = Types.RStatus.BELOW_ONE; + } else if (_R_STATUS_ == Types.RStatus.ABOVE_ONE) { + uint256 backToOnePayBase = newBaseTarget.sub(_BASE_BALANCE_); + uint256 backToOneReceiveQuote = _QUOTE_BALANCE_.sub(newQuoteTarget); + // case 2: R>1 + // complex case, R status depends on trading amount + if (sellBaseAmount < backToOnePayBase) { + // case 2.1: R status do not change + receiveQuote = _RAboveSellBaseToken(sellBaseAmount, _BASE_BALANCE_, newBaseTarget); + newRStatus = Types.RStatus.ABOVE_ONE; + if (receiveQuote > backToOneReceiveQuote) { + // [Important corner case!] may enter this branch when some precision problem happens. And consequently contribute to negative spare quote amount + // to make sure spare quote>=0, mannually set receiveQuote=backToOneReceiveQuote + receiveQuote = backToOneReceiveQuote; + } + } else if (sellBaseAmount == backToOnePayBase) { + // case 2.2: R status changes to ONE + receiveQuote = backToOneReceiveQuote; + newRStatus = Types.RStatus.ONE; + } else { + // case 2.3: R status changes to BELOW_ONE + receiveQuote = backToOneReceiveQuote.add( + _ROneSellBaseToken(sellBaseAmount.sub(backToOnePayBase), newQuoteTarget) + ); + newRStatus = Types.RStatus.BELOW_ONE; + } + } else { + // _R_STATUS_ == Types.RStatus.BELOW_ONE + // case 3: R<1 + receiveQuote = _RBelowSellBaseToken(sellBaseAmount, _QUOTE_BALANCE_, newQuoteTarget); + newRStatus = Types.RStatus.BELOW_ONE; + } + + // count fees + lpFeeQuote = DecimalMath.mul(receiveQuote, _LP_FEE_RATE_); + mtFeeQuote = DecimalMath.mul(receiveQuote, _MT_FEE_RATE_); + receiveQuote = receiveQuote.sub(lpFeeQuote).sub(mtFeeQuote); + + return (receiveQuote, lpFeeQuote, mtFeeQuote, newRStatus, newQuoteTarget, newBaseTarget); + } + + function _queryBuyBaseToken(uint256 amount) + internal + view + returns ( + uint256 payQuote, + uint256 lpFeeBase, + uint256 mtFeeBase, + Types.RStatus newRStatus, + uint256 newQuoteTarget, + uint256 newBaseTarget + ) + { + (newBaseTarget, newQuoteTarget) = _getExpectedTarget(); + + // charge fee from user receive amount + lpFeeBase = DecimalMath.mul(amount, _LP_FEE_RATE_); + mtFeeBase = DecimalMath.mul(amount, _MT_FEE_RATE_); + uint256 buyBaseAmount = amount.add(lpFeeBase).add(mtFeeBase); + + if (_R_STATUS_ == Types.RStatus.ONE) { + // case 1: R=1 + payQuote = _ROneBuyBaseToken(buyBaseAmount, newBaseTarget); + newRStatus = Types.RStatus.ABOVE_ONE; + } else if (_R_STATUS_ == Types.RStatus.ABOVE_ONE) { + // case 2: R>1 + payQuote = _RAboveBuyBaseToken(buyBaseAmount, _BASE_BALANCE_, newBaseTarget); + newRStatus = Types.RStatus.ABOVE_ONE; + } else if (_R_STATUS_ == Types.RStatus.BELOW_ONE) { + uint256 backToOnePayQuote = newQuoteTarget.sub(_QUOTE_BALANCE_); + uint256 backToOneReceiveBase = _BASE_BALANCE_.sub(newBaseTarget); + // case 3: R<1 + // complex case, R status may change + if (buyBaseAmount < backToOneReceiveBase) { + // case 3.1: R status do not change + payQuote = _RBelowBuyBaseToken(buyBaseAmount, _QUOTE_BALANCE_, newQuoteTarget); + newRStatus = Types.RStatus.BELOW_ONE; + } else if (buyBaseAmount == backToOneReceiveBase) { + // case 3.2: R status changes to ONE + payQuote = backToOnePayQuote; + newRStatus = Types.RStatus.ONE; + } else { + // case 3.3: R status changes to ABOVE_ONE + payQuote = backToOnePayQuote.add( + _ROneBuyBaseToken(buyBaseAmount.sub(backToOneReceiveBase), newBaseTarget) + ); + newRStatus = Types.RStatus.ABOVE_ONE; + } + } + + return (payQuote, lpFeeBase, mtFeeBase, newRStatus, newQuoteTarget, newBaseTarget); + } +} diff --git a/contracts/intf/IDODO.sol b/contracts/intf/IDODO.sol new file mode 100644 index 0000000..5a21c29 --- /dev/null +++ b/contracts/intf/IDODO.sol @@ -0,0 +1,46 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + + +interface IDODO { + function init( + address supervisor, + address maintainer, + address baseToken, + address quoteToken, + address oracle, + uint256 lpFeeRate, + uint256 mtFeeRate, + uint256 k, + uint256 gasPriceLimit + ) external; + + function transferOwnership(address newOwner) external; + + function sellBaseToken(uint256 amount, uint256 minReceiveQuote) external returns (uint256); + + function buyBaseToken(uint256 amount, uint256 maxPayQuote) external returns (uint256); + + function querySellBaseToken(uint256 amount) external view returns (uint256 receiveQuote); + + function queryBuyBaseToken(uint256 amount) external view returns (uint256 payQuote); + + function depositBaseTo(address to, uint256 amount) external; + + function withdrawBase(uint256 amount) external returns (uint256); + + function withdrawAllBase() external returns (uint256); + + function depositQuoteTo(address to, uint256 amount) external; + + function withdrawQuote(uint256 amount) external returns (uint256); + + function withdrawAllQuote() external returns (uint256); +} diff --git a/contracts/intf/IDODOLpToken.sol b/contracts/intf/IDODOLpToken.sol new file mode 100644 index 0000000..f1b5383 --- /dev/null +++ b/contracts/intf/IDODOLpToken.sol @@ -0,0 +1,20 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity ^0.6.9; +pragma experimental ABIEncoderV2; + + +interface IDODOLpToken { + function mint(address user, uint256 value) external; + + function burn(address user, uint256 value) external; + + function balanceOf(address owner) external view returns (uint256); + + function totalSupply() external view returns (uint256); +} diff --git a/contracts/intf/IDODOZoo.sol b/contracts/intf/IDODOZoo.sol new file mode 100644 index 0000000..1abedf9 --- /dev/null +++ b/contracts/intf/IDODOZoo.sol @@ -0,0 +1,14 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + + +interface IDODOZoo { + function getDODO(address baseToken, address quoteToken) external view returns (address); +} diff --git a/contracts/intf/IERC20.sol b/contracts/intf/IERC20.sol new file mode 100644 index 0000000..e24f1ec --- /dev/null +++ b/contracts/intf/IERC20.sol @@ -0,0 +1,84 @@ +// This is a file copied from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol +// SPDX-License-Identifier: MIT + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `recipient`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address recipient, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `sender` to `recipient` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address sender, + address recipient, + uint256 amount + ) external returns (bool); + + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); +} diff --git a/contracts/intf/IOracle.sol b/contracts/intf/IOracle.sol new file mode 100644 index 0000000..9434fed --- /dev/null +++ b/contracts/intf/IOracle.sol @@ -0,0 +1,14 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + + +interface IOracle { + function getPrice() external view returns (uint256); +} diff --git a/contracts/intf/IWETH.sol b/contracts/intf/IWETH.sol new file mode 100644 index 0000000..fe83c8c --- /dev/null +++ b/contracts/intf/IWETH.sol @@ -0,0 +1,32 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + + +interface IWETH { + function totalSupply() external view returns (uint256); + + function balanceOf(address account) external view returns (uint256); + + function transfer(address recipient, uint256 amount) external returns (bool); + + function allowance(address owner, address spender) external view returns (uint256); + + function approve(address spender, uint256 amount) external returns (bool); + + function transferFrom( + address src, + address dst, + uint256 wad + ) external returns (bool); + + function deposit() external payable; + + function withdraw(uint256 wad) external; +} diff --git a/contracts/lib/DODOMath.sol b/contracts/lib/DODOMath.sol new file mode 100644 index 0000000..181073a --- /dev/null +++ b/contracts/lib/DODOMath.sol @@ -0,0 +1,117 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {SafeMath} from "./SafeMath.sol"; +import {DecimalMath} from "./DecimalMath.sol"; + +/** + * @title DODOMath + * @author DODO Breeder + * + * @notice Functions for complex calculating. Including ONE Integration and TWO Quadratic solutions + */ +library DODOMath { + using SafeMath for uint256; + + /* + Integrate dodo curve fron V1 to V2 + require V0>=V1>=V2>0 + res = (1-k)i(V1-V2)+ikV0*V0(1/V2-1/V1) + let V1-V2=delta + res = i*delta*(1-k+k(V0^2/V1/V2)) + */ + function _GeneralIntegrate( + uint256 V0, + uint256 V1, + uint256 V2, + uint256 i, + uint256 k + ) internal pure returns (uint256) { + uint256 fairAmount = DecimalMath.mul(i, V1.sub(V2)); // i*delta + uint256 V0V1 = DecimalMath.divCeil(V0, V1); // V0/V1 + uint256 V0V2 = DecimalMath.divCeil(V0, V2); // V0/V2 + uint256 penalty = DecimalMath.mul(DecimalMath.mul(k, V0V1), V0V2); // k(V0^2/V1/V2) + return DecimalMath.mul(fairAmount, DecimalMath.ONE.sub(k).add(penalty)); + } + + /* + The same with integration expression above, we have: + i*deltaB = (Q2-Q1)*(1-k+kQ0^2/Q1/Q2) + Given Q1 and deltaB, solve Q2 + This is a quadratic function and the standard version is + aQ2^2 + bQ2 + c = 0, where + a=1-k + -b=(1-k)Q1-kQ0^2/Q1+i*deltaB + c=-kQ0^2 + and Q2=(-b+sqrt(b^2+4(1-k)kQ0^2))/2(1-k) + note: another root is negative, abondan + if deltaBSig=true, then Q2>Q1 + if deltaBSig=false, then Q2= kQ02Q1) { + b = b.sub(kQ02Q1); + minusbSig = true; + } else { + b = kQ02Q1.sub(b); + minusbSig = false; + } + + // calculate sqrt + uint256 squareRoot = DecimalMath.mul( + DecimalMath.ONE.sub(k).mul(4), + DecimalMath.mul(k, Q0).mul(Q0) + ); // 4(1-k)kQ0^2 + squareRoot = b.mul(b).add(squareRoot).sqrt(); // sqrt(b*b-4(1-k)kQ0*Q0) + + // final res + uint256 denominator = DecimalMath.ONE.sub(k).mul(2); // 2(1-k) + if (minusbSig) { + return DecimalMath.divFloor(b.add(squareRoot), denominator); + } else { + return DecimalMath.divFloor(squareRoot.sub(b), denominator); + } + } + + /* + Start from the integration function + i*deltaB = (Q2-Q1)*(1-k+kQ0^2/Q1/Q2) + Assume Q2=Q0, Given Q1 and deltaB, solve Q0 + let fairAmount = i*deltaB + */ + function _SolveQuadraticFunctionForTarget( + uint256 V1, + uint256 k, + uint256 fairAmount + ) internal pure returns (uint256 V0) { + // V0 = V1+V1*(sqrt-1)/2k + uint256 sqrt = DecimalMath.divFloor(DecimalMath.mul(k, fairAmount), V1).mul(4); + sqrt = sqrt.add(DecimalMath.ONE).mul(DecimalMath.ONE).sqrt(); + uint256 premium = DecimalMath.divFloor(sqrt.sub(DecimalMath.ONE), k.mul(2)); + // V0 is greater than or equal to V1 according to the solution + return DecimalMath.mul(V1, DecimalMath.ONE.add(premium)); + } +} diff --git a/contracts/lib/DecimalMath.sol b/contracts/lib/DecimalMath.sol new file mode 100644 index 0000000..a121d24 --- /dev/null +++ b/contracts/lib/DecimalMath.sol @@ -0,0 +1,35 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {SafeMath} from "./SafeMath.sol"; + +/** + * @title DecimalMath + * @author DODO Breeder + * + * @notice Functions for fixed point number with 18 decimals + */ +library DecimalMath { + using SafeMath for uint256; + + uint256 constant ONE = 10**18; + + function mul(uint256 target, uint256 d) internal pure returns (uint256) { + return target.mul(d) / ONE; + } + + function divFloor(uint256 target, uint256 d) internal pure returns (uint256) { + return target.mul(ONE).div(d); + } + + function divCeil(uint256 target, uint256 d) internal pure returns (uint256) { + return target.mul(ONE).divCeil(d); + } +} diff --git a/contracts/lib/Ownable.sol b/contracts/lib/Ownable.sol new file mode 100644 index 0000000..da32aa8 --- /dev/null +++ b/contracts/lib/Ownable.sol @@ -0,0 +1,43 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +/** + * @title Ownable + * @author DODO Breeder + * + * @notice Ownership related functions + */ +contract Ownable { + address public _OWNER_; + + // ============ Events ============ + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + // ============ Modifiers ============ + + modifier onlyOwner() { + require(msg.sender == _OWNER_, "NOT_OWNER"); + _; + } + + // ============ Functions ============ + + constructor() internal { + _OWNER_ = msg.sender; + emit OwnershipTransferred(address(0), _OWNER_); + } + + function transferOwnership(address newOwner) external onlyOwner { + require(newOwner != address(0), "INVALID_OWNER"); + emit OwnershipTransferred(_OWNER_, newOwner); + _OWNER_ = newOwner; + } +} diff --git a/contracts/lib/ReentrancyGuard.sol b/contracts/lib/ReentrancyGuard.sol new file mode 100644 index 0000000..dee0bea --- /dev/null +++ b/contracts/lib/ReentrancyGuard.sol @@ -0,0 +1,32 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {Types} from "./Types.sol"; + +/** + * @title ReentrancyGuard + * @author DODO Breeder + * + * @notice Protect functions from Reentrancy Attack + */ +contract ReentrancyGuard { + Types.EnterStatus private _ENTER_STATUS_; + + constructor() internal { + _ENTER_STATUS_ = Types.EnterStatus.NOT_ENTERED; + } + + modifier preventReentrant() { + require(_ENTER_STATUS_ != Types.EnterStatus.ENTERED, "ReentrancyGuard: reentrant call"); + _ENTER_STATUS_ = Types.EnterStatus.ENTERED; + _; + _ENTER_STATUS_ = Types.EnterStatus.NOT_ENTERED; + } +} diff --git a/contracts/lib/SafeERC20.sol b/contracts/lib/SafeERC20.sol new file mode 100644 index 0000000..09440bf --- /dev/null +++ b/contracts/lib/SafeERC20.sol @@ -0,0 +1,74 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + This is a simplified version of OpenZepplin's SafeERC20 library + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {IERC20} from "../intf/IERC20.sol"; +import {SafeMath} from "./SafeMath.sol"; + + +/** + * @title SafeERC20 + * @dev Wrappers around ERC20 operations that throw on failure (when the token + * contract returns false). Tokens that return no value (and instead revert or + * throw on failure) are also supported, non-reverting calls are assumed to be + * successful. + * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract, + * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. + */ +library SafeERC20 { + using SafeMath for uint256; + + function safeTransfer( + IERC20 token, + address to, + uint256 value + ) internal { + _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); + } + + function safeTransferFrom( + IERC20 token, + address from, + address to, + uint256 value + ) internal { + _callOptionalReturn( + token, + abi.encodeWithSelector(token.transferFrom.selector, from, to, value) + ); + } + + /** + * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement + * on the return value: the return value is optional (but if data is returned, it must not be false). + * @param token The token targeted by the call. + * @param data The call data (encoded using abi.encode or one of its variants). + */ + function _callOptionalReturn(IERC20 token, bytes memory data) private { + // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since + // we're implementing it ourselves. + + // A Solidity high level call has three parts: + // 1. The target address is checked to verify it contains contract code + // 2. The call itself is made, and success asserted + // 3. The return value is decoded, which in turn checks the size of the returned data. + // solhint-disable-next-line max-line-length + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = address(token).call(data); + require(success, "SafeERC20: low-level call failed"); + + if (returndata.length > 0) { + // Return data is optional + // solhint-disable-next-line max-line-length + require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); + } + } +} diff --git a/contracts/lib/SafeMath.sol b/contracts/lib/SafeMath.sol new file mode 100644 index 0000000..92eb396 --- /dev/null +++ b/contracts/lib/SafeMath.sol @@ -0,0 +1,63 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +/** + * @title SafeMath + * @author DODO Breeder + * + * @notice Math operations with safety checks that revert on error + */ +library SafeMath { + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + if (a == 0) { + return 0; + } + + uint256 c = a * b; + require(c / a == b, "MUL_ERROR"); + + return c; + } + + function div(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "DIVIDING_ERROR"); + return a / b; + } + + function divCeil(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 quotient = div(a, b); + uint256 remainder = a - quotient * b; + if (remainder > 0) { + return quotient + 1; + } else { + return quotient; + } + } + + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + require(b <= a, "SUB_ERROR"); + return a - b; + } + + function add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + require(c >= a, "ADD_ERROR"); + return c; + } + + function sqrt(uint256 x) internal pure returns (uint256 y) { + uint256 z = (x + 1) / 2; + y = x; + while (z < y) { + y = z; + z = (x / z + z) / 2; + } + } +} diff --git a/contracts/lib/Types.sol b/contracts/lib/Types.sol new file mode 100644 index 0000000..606f509 --- /dev/null +++ b/contracts/lib/Types.sol @@ -0,0 +1,14 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +library Types { + enum RStatus {ONE, ABOVE_ONE, BELOW_ONE} + enum EnterStatus {ENTERED, NOT_ENTERED} +} diff --git a/coverage.json b/coverage.json new file mode 100644 index 0000000..e90025d --- /dev/null +++ b/coverage.json @@ -0,0 +1 @@ +{"contracts/DODO.sol":{"l":{"37":11,"38":10,"40":10,"41":10,"42":10,"43":10,"44":10,"46":10,"47":10,"48":10,"49":10,"51":10,"52":10,"53":10,"54":10,"56":10,"57":10,"59":10},"path":"/Users/leimingda/Documents/dodo/contracts/DODO.sol","s":{"1":11,"2":10,"3":10,"4":10,"5":10,"6":10,"7":10,"8":10,"9":10,"10":10,"11":10,"12":10,"13":10,"14":10,"15":10,"16":10,"17":10,"18":10},"b":{"1":[10,1]},"f":{"1":11},"fnMap":{"1":{"name":"init","line":36,"loc":{"start":{"line":26,"column":4},"end":{"line":60,"column":4}}}},"statementMap":{"1":{"start":{"line":37,"column":8},"end":{"line":37,"column":58}},"2":{"start":{"line":38,"column":8},"end":{"line":38,"column":27}},"3":{"start":{"line":40,"column":8},"end":{"line":40,"column":32}},"4":{"start":{"line":41,"column":8},"end":{"line":41,"column":32}},"5":{"start":{"line":42,"column":8},"end":{"line":42,"column":31}},"6":{"start":{"line":43,"column":8},"end":{"line":43,"column":33}},"7":{"start":{"line":44,"column":8},"end":{"line":44,"column":24}},"8":{"start":{"line":46,"column":8},"end":{"line":46,"column":36}},"9":{"start":{"line":47,"column":8},"end":{"line":47,"column":37}},"10":{"start":{"line":48,"column":8},"end":{"line":48,"column":29}},"11":{"start":{"line":49,"column":8},"end":{"line":49,"column":40}},"12":{"start":{"line":51,"column":8},"end":{"line":51,"column":32}},"13":{"start":{"line":52,"column":8},"end":{"line":52,"column":32}},"14":{"start":{"line":53,"column":8},"end":{"line":53,"column":14}},"15":{"start":{"line":54,"column":8},"end":{"line":54,"column":37}},"16":{"start":{"line":56,"column":8},"end":{"line":56,"column":56}},"17":{"start":{"line":57,"column":8},"end":{"line":57,"column":57}},"18":{"start":{"line":59,"column":8},"end":{"line":59,"column":29}}},"branchMap":{"1":{"line":37,"type":"if","locations":[{"start":{"line":37,"column":8},"end":{"line":37,"column":8}},{"start":{"line":37,"column":8},"end":{"line":37,"column":8}}]}}},"contracts/DODOEthProxy.sol":{"l":{"52":1,"53":1,"57":0,"61":1,"69":2,"70":1,"71":1,"72":1,"73":1,"74":1,"75":1,"76":1,"77":1,"78":1,"86":1,"87":1,"88":1,"89":1,"90":1,"91":1,"92":1,"93":1,"94":1,"95":1,"103":4,"104":3,"105":3,"106":3,"107":3,"108":3,"118":1,"126":1},"path":"/Users/leimingda/Documents/dodo/contracts/DODOEthProxy.sol","s":{"1":1,"2":1,"3":0,"4":2,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":1,"14":1,"15":1,"16":1,"17":1,"18":1,"19":1,"20":1,"21":1,"22":1,"23":1,"24":4,"25":3,"26":3,"27":3,"28":3,"29":3,"30":1,"31":1},"b":{"1":[0,0],"2":[1,0],"3":[1,1],"4":[1,0],"5":[1,0],"6":[3,1]},"f":{"1":1,"2":0,"3":2,"4":1,"5":4,"6":1,"7":1},"fnMap":{"1":{"name":"constructor","line":51,"loc":{"start":{"line":51,"column":4},"end":{"line":54,"column":4}}},"2":{"name":null,"line":56,"loc":{"start":{"line":56,"column":4},"end":{"line":58,"column":4}}},"3":{"name":"sellEthTo","line":68,"loc":{"start":{"line":64,"column":4},"end":{"line":79,"column":4}}},"4":{"name":"buyEthWith","line":85,"loc":{"start":{"line":81,"column":4},"end":{"line":96,"column":4}}},"5":{"name":"depositEth","line":101,"loc":{"start":{"line":98,"column":4},"end":{"line":109,"column":4}}},"6":{"name":"_transferIn","line":113,"loc":{"start":{"line":113,"column":4},"end":{"line":119,"column":4}}},"7":{"name":"_transferOut","line":121,"loc":{"start":{"line":121,"column":4},"end":{"line":127,"column":4}}}},"statementMap":{"1":{"start":{"line":52,"column":8},"end":{"line":52,"column":27}},"2":{"start":{"line":53,"column":8},"end":{"line":53,"column":20}},"3":{"start":{"line":57,"column":8},"end":{"line":57,"column":60}},"4":{"start":{"line":69,"column":8},"end":{"line":69,"column":62}},"5":{"start":{"line":70,"column":8},"end":{"line":70,"column":78}},"6":{"start":{"line":71,"column":8},"end":{"line":71,"column":69}},"7":{"start":{"line":72,"column":8},"end":{"line":72,"column":81}},"8":{"start":{"line":73,"column":8},"end":{"line":73,"column":48}},"9":{"start":{"line":74,"column":8},"end":{"line":74,"column":45}},"10":{"start":{"line":75,"column":8},"end":{"line":75,"column":66}},"11":{"start":{"line":76,"column":8},"end":{"line":76,"column":70}},"12":{"start":{"line":77,"column":8},"end":{"line":77,"column":87}},"13":{"start":{"line":78,"column":8},"end":{"line":78,"column":33}},"14":{"start":{"line":86,"column":8},"end":{"line":86,"column":78}},"15":{"start":{"line":87,"column":8},"end":{"line":87,"column":64}},"16":{"start":{"line":88,"column":8},"end":{"line":88,"column":67}},"17":{"start":{"line":89,"column":8},"end":{"line":89,"column":65}},"18":{"start":{"line":90,"column":8},"end":{"line":90,"column":62}},"19":{"start":{"line":91,"column":8},"end":{"line":91,"column":61}},"20":{"start":{"line":92,"column":8},"end":{"line":92,"column":40}},"21":{"start":{"line":93,"column":8},"end":{"line":93,"column":37}},"22":{"start":{"line":94,"column":8},"end":{"line":94,"column":82}},"23":{"start":{"line":95,"column":8},"end":{"line":95,"column":29}},"24":{"start":{"line":103,"column":8},"end":{"line":103,"column":62}},"25":{"start":{"line":104,"column":8},"end":{"line":104,"column":78}},"26":{"start":{"line":105,"column":8},"end":{"line":105,"column":48}},"27":{"start":{"line":106,"column":8},"end":{"line":106,"column":45}},"28":{"start":{"line":107,"column":8},"end":{"line":107,"column":55}},"29":{"start":{"line":108,"column":8},"end":{"line":108,"column":70}},"30":{"start":{"line":118,"column":8},"end":{"line":118,"column":73}},"31":{"start":{"line":126,"column":8},"end":{"line":126,"column":52}}},"branchMap":{"1":{"line":57,"type":"if","locations":[{"start":{"line":57,"column":8},"end":{"line":57,"column":8}},{"start":{"line":57,"column":8},"end":{"line":57,"column":8}}]},"2":{"line":61,"type":"if","locations":[{"start":{"line":61,"column":8},"end":{"line":61,"column":8}},{"start":{"line":61,"column":8},"end":{"line":61,"column":8}}]},"3":{"line":69,"type":"if","locations":[{"start":{"line":69,"column":8},"end":{"line":69,"column":8}},{"start":{"line":69,"column":8},"end":{"line":69,"column":8}}]},"4":{"line":72,"type":"if","locations":[{"start":{"line":72,"column":8},"end":{"line":72,"column":8}},{"start":{"line":72,"column":8},"end":{"line":72,"column":8}}]},"5":{"line":88,"type":"if","locations":[{"start":{"line":88,"column":8},"end":{"line":88,"column":8}},{"start":{"line":88,"column":8},"end":{"line":88,"column":8}}]},"6":{"line":103,"type":"if","locations":[{"start":{"line":103,"column":8},"end":{"line":103,"column":8}},{"start":{"line":103,"column":8},"end":{"line":103,"column":8}}]}}},"contracts/DODOZoo.sol":{"l":{"42":12,"43":10,"44":10,"45":10,"56":10,"57":10,"58":10,"59":10,"65":12,"69":10,"71":2,"76":15},"path":"/Users/leimingda/Documents/dodo/contracts/DODOZoo.sol","s":{"1":12,"2":10,"3":10,"4":10,"5":10,"6":10,"7":10,"8":10,"9":12,"10":10,"11":2,"12":15},"b":{"1":[10,2],"2":[10,0],"3":[10,2]},"f":{"1":12,"2":12,"3":15},"fnMap":{"1":{"name":"breedDODO","line":41,"loc":{"start":{"line":31,"column":4},"end":{"line":60,"column":4}}},"2":{"name":"isDODORegistered","line":64,"loc":{"start":{"line":64,"column":4},"end":{"line":73,"column":4}}},"3":{"name":"getDODO","line":75,"loc":{"start":{"line":75,"column":4},"end":{"line":77,"column":4}}}},"statementMap":{"1":{"start":{"line":42,"column":8},"end":{"line":42,"column":78}},"2":{"start":{"line":43,"column":8},"end":{"line":43,"column":66}},"3":{"start":{"line":44,"column":8},"end":{"line":44,"column":49}},"4":{"start":{"line":45,"column":8},"end":{"line":45,"column":1105}},"5":{"start":{"line":56,"column":8},"end":{"line":56,"column":52}},"6":{"start":{"line":57,"column":8},"end":{"line":57,"column":59}},"7":{"start":{"line":58,"column":8},"end":{"line":58,"column":35}},"8":{"start":{"line":59,"column":8},"end":{"line":59,"column":26}},"9":{"start":{"line":65,"column":8},"end":{"line":65,"column":1687}},"10":{"start":{"line":69,"column":12},"end":{"line":69,"column":24}},"11":{"start":{"line":71,"column":12},"end":{"line":71,"column":23}},"12":{"start":{"line":76,"column":8},"end":{"line":76,"column":53}}},"branchMap":{"1":{"line":42,"type":"if","locations":[{"start":{"line":42,"column":8},"end":{"line":42,"column":8}},{"start":{"line":42,"column":8},"end":{"line":42,"column":8}}]},"2":{"line":43,"type":"if","locations":[{"start":{"line":43,"column":8},"end":{"line":43,"column":8}},{"start":{"line":43,"column":8},"end":{"line":43,"column":8}}]},"3":{"line":65,"type":"if","locations":[{"start":{"line":65,"column":8},"end":{"line":65,"column":8}},{"start":{"line":65,"column":8},"end":{"line":65,"column":8}}]}}},"contracts/impl/Admin.sol":{"l":{"28":1,"32":1,"36":1,"40":2,"41":2,"45":2,"46":2,"50":3,"51":3,"55":1,"56":1,"62":1,"66":1,"70":1,"74":1,"78":1,"82":1},"path":"/Users/leimingda/Documents/dodo/contracts/impl/Admin.sol","s":{"1":1,"2":1,"3":1,"4":2,"5":2,"6":2,"7":2,"8":3,"9":3,"10":1,"11":1,"12":1,"13":1,"14":1,"15":1,"16":1,"17":1},"b":{},"f":{"1":1,"2":1,"3":1,"4":2,"5":2,"6":3,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":1},"fnMap":{"1":{"name":"setOracle","line":27,"loc":{"start":{"line":27,"column":4},"end":{"line":29,"column":4}}},"2":{"name":"setSupervisor","line":31,"loc":{"start":{"line":31,"column":4},"end":{"line":33,"column":4}}},"3":{"name":"setMaintainer","line":35,"loc":{"start":{"line":35,"column":4},"end":{"line":37,"column":4}}},"4":{"name":"setLiquidityProviderFeeRate","line":39,"loc":{"start":{"line":39,"column":4},"end":{"line":42,"column":4}}},"5":{"name":"setMaintainerFeeRate","line":44,"loc":{"start":{"line":44,"column":4},"end":{"line":47,"column":4}}},"6":{"name":"setK","line":49,"loc":{"start":{"line":49,"column":4},"end":{"line":52,"column":4}}},"7":{"name":"setGasPriceLimit","line":54,"loc":{"start":{"line":54,"column":4},"end":{"line":57,"column":4}}},"8":{"name":"disableTrading","line":61,"loc":{"start":{"line":61,"column":4},"end":{"line":63,"column":4}}},"9":{"name":"enableTrading","line":65,"loc":{"start":{"line":65,"column":4},"end":{"line":67,"column":4}}},"10":{"name":"disableQuoteDeposit","line":69,"loc":{"start":{"line":69,"column":4},"end":{"line":71,"column":4}}},"11":{"name":"enableQuoteDeposit","line":73,"loc":{"start":{"line":73,"column":4},"end":{"line":75,"column":4}}},"12":{"name":"disableBaseDeposit","line":77,"loc":{"start":{"line":77,"column":4},"end":{"line":79,"column":4}}},"13":{"name":"enableBaseDeposit","line":81,"loc":{"start":{"line":81,"column":4},"end":{"line":83,"column":4}}}},"statementMap":{"1":{"start":{"line":28,"column":8},"end":{"line":28,"column":27}},"2":{"start":{"line":32,"column":8},"end":{"line":32,"column":35}},"3":{"start":{"line":36,"column":8},"end":{"line":36,"column":35}},"4":{"start":{"line":40,"column":8},"end":{"line":40,"column":49}},"5":{"start":{"line":41,"column":8},"end":{"line":41,"column":29}},"6":{"start":{"line":45,"column":8},"end":{"line":45,"column":43}},"7":{"start":{"line":46,"column":8},"end":{"line":46,"column":29}},"8":{"start":{"line":50,"column":8},"end":{"line":50,"column":17}},"9":{"start":{"line":51,"column":8},"end":{"line":51,"column":29}},"10":{"start":{"line":55,"column":8},"end":{"line":55,"column":43}},"11":{"start":{"line":56,"column":8},"end":{"line":56,"column":50}},"12":{"start":{"line":62,"column":8},"end":{"line":62,"column":30}},"13":{"start":{"line":66,"column":8},"end":{"line":66,"column":29}},"14":{"start":{"line":70,"column":8},"end":{"line":70,"column":38}},"15":{"start":{"line":74,"column":8},"end":{"line":74,"column":37}},"16":{"start":{"line":78,"column":8},"end":{"line":78,"column":37}},"17":{"start":{"line":82,"column":8},"end":{"line":82,"column":36}}},"branchMap":{}},"contracts/impl/LiquidityProvider.sol":{"l":{"47":38,"48":37,"52":43,"53":42,"59":8,"63":39,"67":8,"71":37,"75":9,"79":8,"89":37,"90":37,"91":37,"92":37,"93":30,"95":37,"96":7,"99":37,"100":37,"101":37,"103":37,"107":42,"108":42,"109":42,"110":42,"111":34,"113":42,"114":8,"117":42,"118":42,"119":42,"121":42,"127":9,"128":9,"131":8,"132":8,"133":8,"139":7,"140":7,"143":5,"144":5,"145":5,"146":5,"148":5,"149":5,"151":5,"155":9,"156":9,"159":8,"160":8,"161":8,"167":7,"168":7,"171":5,"172":5,"173":5,"174":5,"176":5,"177":5,"179":5,"185":9,"186":9,"187":9,"190":8,"191":8,"194":8,"195":8,"196":8,"197":8,"199":8,"200":8,"202":8,"206":10,"207":10,"208":10,"211":9,"212":9,"215":9,"216":9,"217":9,"218":9,"220":9,"221":9,"223":9,"229":42,"233":37,"237":14,"241":13,"247":37,"248":37,"249":37,"250":1,"252":36,"253":36,"257":34,"258":34,"259":34,"260":1,"262":33,"263":33,"267":20,"268":7,"269":6,"270":6,"271":6,"272":6,"277":6,"282":6,"284":13,"289":22,"290":9,"291":8,"292":8,"293":8,"294":8,"299":8,"304":8,"306":13},"path":"/Users/leimingda/Documents/dodo/contracts/impl/LiquidityProvider.sol","s":{"1":38,"2":43,"3":8,"4":39,"5":8,"6":37,"7":9,"8":8,"9":37,"10":37,"11":37,"12":37,"13":30,"14":37,"15":7,"16":37,"17":37,"18":37,"19":37,"20":42,"21":42,"22":42,"23":42,"24":34,"25":42,"26":8,"27":42,"28":42,"29":42,"30":42,"31":9,"32":9,"33":8,"34":8,"35":8,"36":7,"37":7,"38":5,"39":5,"40":5,"41":5,"42":5,"43":5,"44":5,"45":9,"46":9,"47":8,"48":8,"49":8,"50":7,"51":7,"52":5,"53":5,"54":5,"55":5,"56":5,"57":5,"58":5,"59":9,"60":9,"61":9,"62":8,"63":8,"64":8,"65":8,"66":8,"67":8,"68":8,"69":8,"70":8,"71":10,"72":10,"73":10,"74":9,"75":9,"76":9,"77":9,"78":9,"79":9,"80":9,"81":9,"82":9,"83":42,"84":37,"85":14,"86":13,"87":37,"88":37,"89":37,"90":1,"91":36,"92":36,"93":34,"94":34,"95":34,"96":1,"97":33,"98":33,"99":20,"100":7,"101":6,"102":6,"103":6,"104":6,"105":6,"106":6,"107":13,"108":22,"109":9,"110":8,"111":8,"112":8,"113":8,"114":8,"115":8,"116":13},"b":{"1":[37,1],"2":[42,1],"3":[30,7],"4":[7,30],"5":[34,8],"6":[8,34],"7":[8,1],"8":[7,1],"9":[5,2],"10":[8,1],"11":[7,1],"12":[5,2],"13":[8,1],"14":[8,0],"15":[9,1],"16":[9,0],"17":[1,36],"18":[1,33],"19":[7,13],"20":[6,1],"21":[9,13],"22":[8,1]},"f":{"1":38,"2":43,"3":8,"4":39,"5":8,"6":37,"7":9,"8":8,"9":37,"10":42,"11":9,"12":9,"13":9,"14":10,"15":42,"16":37,"17":14,"18":13,"19":37,"20":34,"21":20,"22":22},"fnMap":{"1":{"name":"depositQuoteAllowed","line":46,"loc":{"start":{"line":46,"column":4},"end":{"line":49,"column":4}}},"2":{"name":"depositBaseAllowed","line":51,"loc":{"start":{"line":51,"column":4},"end":{"line":54,"column":4}}},"3":{"name":"withdrawBase","line":58,"loc":{"start":{"line":58,"column":4},"end":{"line":60,"column":4}}},"4":{"name":"depositBase","line":62,"loc":{"start":{"line":62,"column":4},"end":{"line":64,"column":4}}},"5":{"name":"withdrawQuote","line":66,"loc":{"start":{"line":66,"column":4},"end":{"line":68,"column":4}}},"6":{"name":"depositQuote","line":70,"loc":{"start":{"line":70,"column":4},"end":{"line":72,"column":4}}},"7":{"name":"withdrawAllBase","line":74,"loc":{"start":{"line":74,"column":4},"end":{"line":76,"column":4}}},"8":{"name":"withdrawAllQuote","line":78,"loc":{"start":{"line":78,"column":4},"end":{"line":80,"column":4}}},"9":{"name":"depositQuoteTo","line":87,"loc":{"start":{"line":84,"column":4},"end":{"line":104,"column":4}}},"10":{"name":"depositBaseTo","line":106,"loc":{"start":{"line":106,"column":4},"end":{"line":122,"column":4}}},"11":{"name":"withdrawQuoteTo","line":126,"loc":{"start":{"line":126,"column":4},"end":{"line":152,"column":4}}},"12":{"name":"withdrawBaseTo","line":154,"loc":{"start":{"line":154,"column":4},"end":{"line":180,"column":4}}},"13":{"name":"withdrawAllQuoteTo","line":184,"loc":{"start":{"line":184,"column":4},"end":{"line":203,"column":4}}},"14":{"name":"withdrawAllBaseTo","line":205,"loc":{"start":{"line":205,"column":4},"end":{"line":224,"column":4}}},"15":{"name":"_mintBaseTokenCapital","line":228,"loc":{"start":{"line":228,"column":4},"end":{"line":230,"column":4}}},"16":{"name":"_mintQuoteTokenCapital","line":232,"loc":{"start":{"line":232,"column":4},"end":{"line":234,"column":4}}},"17":{"name":"_burnBaseTokenCapital","line":236,"loc":{"start":{"line":236,"column":4},"end":{"line":238,"column":4}}},"18":{"name":"_burnQuoteTokenCapital","line":240,"loc":{"start":{"line":240,"column":4},"end":{"line":242,"column":4}}},"19":{"name":"getLpBaseBalance","line":246,"loc":{"start":{"line":246,"column":4},"end":{"line":254,"column":4}}},"20":{"name":"getLpQuoteBalance","line":256,"loc":{"start":{"line":256,"column":4},"end":{"line":264,"column":4}}},"21":{"name":"getWithdrawQuotePenalty","line":266,"loc":{"start":{"line":266,"column":4},"end":{"line":286,"column":4}}},"22":{"name":"getWithdrawBasePenalty","line":288,"loc":{"start":{"line":288,"column":4},"end":{"line":308,"column":4}}}},"statementMap":{"1":{"start":{"line":47,"column":8},"end":{"line":47,"column":68}},"2":{"start":{"line":52,"column":8},"end":{"line":52,"column":66}},"3":{"start":{"line":59,"column":8},"end":{"line":59,"column":49}},"4":{"start":{"line":63,"column":8},"end":{"line":63,"column":40}},"5":{"start":{"line":67,"column":8},"end":{"line":67,"column":50}},"6":{"start":{"line":71,"column":8},"end":{"line":71,"column":41}},"7":{"start":{"line":75,"column":8},"end":{"line":75,"column":44}},"8":{"start":{"line":79,"column":8},"end":{"line":79,"column":45}},"9":{"start":{"line":89,"column":8},"end":{"line":89,"column":54}},"10":{"start":{"line":90,"column":8},"end":{"line":90,"column":32}},"11":{"start":{"line":91,"column":8},"end":{"line":91,"column":58}},"12":{"start":{"line":92,"column":8},"end":{"line":92,"column":2660}},"13":{"start":{"line":93,"column":12},"end":{"line":93,"column":44}},"14":{"start":{"line":95,"column":8},"end":{"line":95,"column":2801}},"15":{"start":{"line":96,"column":12},"end":{"line":96,"column":67}},"16":{"start":{"line":99,"column":8},"end":{"line":99,"column":48}},"17":{"start":{"line":100,"column":8},"end":{"line":100,"column":42}},"18":{"start":{"line":101,"column":8},"end":{"line":101,"column":76}},"19":{"start":{"line":103,"column":8},"end":{"line":103,"column":54}},"20":{"start":{"line":107,"column":8},"end":{"line":107,"column":53}},"21":{"start":{"line":108,"column":8},"end":{"line":108,"column":32}},"22":{"start":{"line":109,"column":8},"end":{"line":109,"column":56}},"23":{"start":{"line":110,"column":8},"end":{"line":110,"column":3445}},"24":{"start":{"line":111,"column":12},"end":{"line":111,"column":43}},"25":{"start":{"line":113,"column":8},"end":{"line":113,"column":3583}},"26":{"start":{"line":114,"column":12},"end":{"line":114,"column":65}},"27":{"start":{"line":117,"column":8},"end":{"line":117,"column":47}},"28":{"start":{"line":118,"column":8},"end":{"line":118,"column":41}},"29":{"start":{"line":119,"column":8},"end":{"line":119,"column":74}},"30":{"start":{"line":121,"column":8},"end":{"line":121,"column":53}},"31":{"start":{"line":127,"column":8},"end":{"line":127,"column":35}},"32":{"start":{"line":128,"column":8},"end":{"line":128,"column":66}},"33":{"start":{"line":131,"column":8},"end":{"line":131,"column":54}},"34":{"start":{"line":132,"column":8},"end":{"line":132,"column":93}},"35":{"start":{"line":133,"column":8},"end":{"line":133,"column":4412}},"36":{"start":{"line":139,"column":8},"end":{"line":139,"column":57}},"37":{"start":{"line":140,"column":8},"end":{"line":140,"column":71}},"38":{"start":{"line":143,"column":8},"end":{"line":143,"column":76}},"39":{"start":{"line":144,"column":8},"end":{"line":144,"column":62}},"40":{"start":{"line":145,"column":8},"end":{"line":145,"column":54}},"41":{"start":{"line":146,"column":8},"end":{"line":146,"column":33}},"42":{"start":{"line":148,"column":8},"end":{"line":148,"column":68}},"43":{"start":{"line":149,"column":8},"end":{"line":149,"column":52}},"44":{"start":{"line":151,"column":8},"end":{"line":151,"column":34}},"45":{"start":{"line":155,"column":8},"end":{"line":155,"column":34}},"46":{"start":{"line":156,"column":8},"end":{"line":156,"column":65}},"47":{"start":{"line":159,"column":8},"end":{"line":159,"column":53}},"48":{"start":{"line":160,"column":8},"end":{"line":160,"column":90}},"49":{"start":{"line":161,"column":8},"end":{"line":161,"column":5560}},"50":{"start":{"line":167,"column":8},"end":{"line":167,"column":56}},"51":{"start":{"line":168,"column":8},"end":{"line":168,"column":71}},"52":{"start":{"line":171,"column":8},"end":{"line":171,"column":74}},"53":{"start":{"line":172,"column":8},"end":{"line":172,"column":60}},"54":{"start":{"line":173,"column":8},"end":{"line":173,"column":53}},"55":{"start":{"line":174,"column":8},"end":{"line":174,"column":32}},"56":{"start":{"line":176,"column":8},"end":{"line":176,"column":67}},"57":{"start":{"line":177,"column":8},"end":{"line":177,"column":51}},"58":{"start":{"line":179,"column":8},"end":{"line":179,"column":34}},"59":{"start":{"line":185,"column":8},"end":{"line":185,"column":35}},"60":{"start":{"line":186,"column":8},"end":{"line":186,"column":62}},"61":{"start":{"line":187,"column":8},"end":{"line":187,"column":74}},"62":{"start":{"line":190,"column":8},"end":{"line":190,"column":65}},"63":{"start":{"line":191,"column":8},"end":{"line":191,"column":79}},"64":{"start":{"line":194,"column":8},"end":{"line":194,"column":84}},"65":{"start":{"line":195,"column":8},"end":{"line":195,"column":79}},"66":{"start":{"line":196,"column":8},"end":{"line":196,"column":62}},"67":{"start":{"line":197,"column":8},"end":{"line":197,"column":33}},"68":{"start":{"line":199,"column":8},"end":{"line":199,"column":63}},"69":{"start":{"line":200,"column":8},"end":{"line":200,"column":52}},"70":{"start":{"line":202,"column":8},"end":{"line":202,"column":42}},"71":{"start":{"line":206,"column":8},"end":{"line":206,"column":34}},"72":{"start":{"line":207,"column":8},"end":{"line":207,"column":61}},"73":{"start":{"line":208,"column":8},"end":{"line":208,"column":73}},"74":{"start":{"line":211,"column":8},"end":{"line":211,"column":64}},"75":{"start":{"line":212,"column":8},"end":{"line":212,"column":79}},"76":{"start":{"line":215,"column":8},"end":{"line":215,"column":82}},"77":{"start":{"line":216,"column":8},"end":{"line":216,"column":77}},"78":{"start":{"line":217,"column":8},"end":{"line":217,"column":61}},"79":{"start":{"line":218,"column":8},"end":{"line":218,"column":32}},"80":{"start":{"line":220,"column":8},"end":{"line":220,"column":62}},"81":{"start":{"line":221,"column":8},"end":{"line":221,"column":51}},"82":{"start":{"line":223,"column":8},"end":{"line":223,"column":42}},"83":{"start":{"line":229,"column":8},"end":{"line":229,"column":60}},"84":{"start":{"line":233,"column":8},"end":{"line":233,"column":61}},"85":{"start":{"line":237,"column":8},"end":{"line":237,"column":60}},"86":{"start":{"line":241,"column":8},"end":{"line":241,"column":61}},"87":{"start":{"line":247,"column":8},"end":{"line":247,"column":56}},"88":{"start":{"line":248,"column":8},"end":{"line":248,"column":53}},"89":{"start":{"line":249,"column":8},"end":{"line":249,"column":9114}},"90":{"start":{"line":250,"column":12},"end":{"line":250,"column":20}},"91":{"start":{"line":252,"column":8},"end":{"line":252,"column":84}},"92":{"start":{"line":253,"column":8},"end":{"line":253,"column":24}},"93":{"start":{"line":257,"column":8},"end":{"line":257,"column":58}},"94":{"start":{"line":258,"column":8},"end":{"line":258,"column":54}},"95":{"start":{"line":259,"column":8},"end":{"line":259,"column":9504}},"96":{"start":{"line":260,"column":12},"end":{"line":260,"column":20}},"97":{"start":{"line":262,"column":8},"end":{"line":262,"column":87}},"98":{"start":{"line":263,"column":8},"end":{"line":263,"column":24}},"99":{"start":{"line":267,"column":8},"end":{"line":267,"column":9790}},"100":{"start":{"line":268,"column":12},"end":{"line":268,"column":77}},"101":{"start":{"line":269,"column":12},"end":{"line":269,"column":78}},"102":{"start":{"line":270,"column":12},"end":{"line":270,"column":44}},"103":{"start":{"line":271,"column":12},"end":{"line":271,"column":66}},"104":{"start":{"line":272,"column":12},"end":{"line":272,"column":10126}},"105":{"start":{"line":277,"column":12},"end":{"line":277,"column":10299}},"106":{"start":{"line":282,"column":12},"end":{"line":282,"column":71}},"107":{"start":{"line":284,"column":12},"end":{"line":284,"column":20}},"108":{"start":{"line":289,"column":8},"end":{"line":289,"column":10708}},"109":{"start":{"line":290,"column":12},"end":{"line":290,"column":75}},"110":{"start":{"line":291,"column":12},"end":{"line":291,"column":81}},"111":{"start":{"line":292,"column":12},"end":{"line":292,"column":44}},"112":{"start":{"line":293,"column":12},"end":{"line":293,"column":72}},"113":{"start":{"line":294,"column":12},"end":{"line":294,"column":11051}},"114":{"start":{"line":299,"column":12},"end":{"line":299,"column":11222}},"115":{"start":{"line":304,"column":12},"end":{"line":304,"column":69}},"116":{"start":{"line":306,"column":12},"end":{"line":306,"column":20}}},"branchMap":{"1":{"line":47,"type":"if","locations":[{"start":{"line":47,"column":8},"end":{"line":47,"column":8}},{"start":{"line":47,"column":8},"end":{"line":47,"column":8}}]},"2":{"line":52,"type":"if","locations":[{"start":{"line":52,"column":8},"end":{"line":52,"column":8}},{"start":{"line":52,"column":8},"end":{"line":52,"column":8}}]},"3":{"line":92,"type":"if","locations":[{"start":{"line":92,"column":8},"end":{"line":92,"column":8}},{"start":{"line":92,"column":8},"end":{"line":92,"column":8}}]},"4":{"line":95,"type":"if","locations":[{"start":{"line":95,"column":8},"end":{"line":95,"column":8}},{"start":{"line":95,"column":8},"end":{"line":95,"column":8}}]},"5":{"line":110,"type":"if","locations":[{"start":{"line":110,"column":8},"end":{"line":110,"column":8}},{"start":{"line":110,"column":8},"end":{"line":110,"column":8}}]},"6":{"line":113,"type":"if","locations":[{"start":{"line":113,"column":8},"end":{"line":113,"column":8}},{"start":{"line":113,"column":8},"end":{"line":113,"column":8}}]},"7":{"line":128,"type":"if","locations":[{"start":{"line":128,"column":8},"end":{"line":128,"column":8}},{"start":{"line":128,"column":8},"end":{"line":128,"column":8}}]},"8":{"line":133,"type":"if","locations":[{"start":{"line":133,"column":8},"end":{"line":133,"column":8}},{"start":{"line":133,"column":8},"end":{"line":133,"column":8}}]},"9":{"line":140,"type":"if","locations":[{"start":{"line":140,"column":8},"end":{"line":140,"column":8}},{"start":{"line":140,"column":8},"end":{"line":140,"column":8}}]},"10":{"line":156,"type":"if","locations":[{"start":{"line":156,"column":8},"end":{"line":156,"column":8}},{"start":{"line":156,"column":8},"end":{"line":156,"column":8}}]},"11":{"line":161,"type":"if","locations":[{"start":{"line":161,"column":8},"end":{"line":161,"column":8}},{"start":{"line":161,"column":8},"end":{"line":161,"column":8}}]},"12":{"line":168,"type":"if","locations":[{"start":{"line":168,"column":8},"end":{"line":168,"column":8}},{"start":{"line":168,"column":8},"end":{"line":168,"column":8}}]},"13":{"line":187,"type":"if","locations":[{"start":{"line":187,"column":8},"end":{"line":187,"column":8}},{"start":{"line":187,"column":8},"end":{"line":187,"column":8}}]},"14":{"line":191,"type":"if","locations":[{"start":{"line":191,"column":8},"end":{"line":191,"column":8}},{"start":{"line":191,"column":8},"end":{"line":191,"column":8}}]},"15":{"line":208,"type":"if","locations":[{"start":{"line":208,"column":8},"end":{"line":208,"column":8}},{"start":{"line":208,"column":8},"end":{"line":208,"column":8}}]},"16":{"line":212,"type":"if","locations":[{"start":{"line":212,"column":8},"end":{"line":212,"column":8}},{"start":{"line":212,"column":8},"end":{"line":212,"column":8}}]},"17":{"line":249,"type":"if","locations":[{"start":{"line":249,"column":8},"end":{"line":249,"column":8}},{"start":{"line":249,"column":8},"end":{"line":249,"column":8}}]},"18":{"line":259,"type":"if","locations":[{"start":{"line":259,"column":8},"end":{"line":259,"column":8}},{"start":{"line":259,"column":8},"end":{"line":259,"column":8}}]},"19":{"line":267,"type":"if","locations":[{"start":{"line":267,"column":8},"end":{"line":267,"column":8}},{"start":{"line":267,"column":8},"end":{"line":267,"column":8}}]},"20":{"line":268,"type":"if","locations":[{"start":{"line":268,"column":12},"end":{"line":268,"column":12}},{"start":{"line":268,"column":12},"end":{"line":268,"column":12}}]},"21":{"line":289,"type":"if","locations":[{"start":{"line":289,"column":8},"end":{"line":289,"column":8}},{"start":{"line":289,"column":8},"end":{"line":289,"column":8}}]},"22":{"line":290,"type":"if","locations":[{"start":{"line":290,"column":12},"end":{"line":290,"column":12}},{"start":{"line":290,"column":12},"end":{"line":290,"column":12}}]}}},"contracts/impl/Pricing.sol":{"l":{"34":25,"35":25,"44":25,"52":35,"53":33,"54":33,"55":33,"65":1,"66":1,"73":1,"84":2,"85":2,"92":2,"101":34,"102":34,"103":34,"104":34,"109":34,"119":7,"120":6,"121":6,"132":5,"133":5,"142":51,"143":51,"144":51,"145":51,"150":51,"156":246,"157":246,"158":246,"159":161,"161":34,"162":34,"164":51,"165":51,"174":44,"175":44},"path":"/Users/leimingda/Documents/dodo/contracts/impl/Pricing.sol","s":{"1":25,"2":25,"3":25,"4":35,"5":33,"6":33,"7":33,"8":1,"9":1,"10":1,"11":2,"12":2,"13":2,"14":34,"15":34,"16":34,"17":34,"18":34,"19":7,"20":6,"21":6,"22":5,"23":5,"24":51,"25":51,"26":51,"27":51,"28":51,"29":246,"30":246,"31":246,"32":161,"33":85,"34":34,"35":34,"36":51,"37":51,"38":51,"39":44,"40":44},"b":{"1":[33,2],"2":[6,1],"3":[161,85],"4":[34,51],"5":[51,0]},"f":{"1":25,"2":35,"3":1,"4":2,"5":34,"6":7,"7":5,"8":51,"9":246,"10":44},"fnMap":{"1":{"name":"_ROneSellBaseToken","line":29,"loc":{"start":{"line":29,"column":4},"end":{"line":45,"column":4}}},"2":{"name":"_ROneBuyBaseToken","line":47,"loc":{"start":{"line":47,"column":4},"end":{"line":56,"column":4}}},"3":{"name":"_RBelowSellBaseToken","line":60,"loc":{"start":{"line":60,"column":4},"end":{"line":74,"column":4}}},"4":{"name":"_RBelowBuylBaseToken","line":76,"loc":{"start":{"line":76,"column":4},"end":{"line":93,"column":4}}},"5":{"name":"_RBelowBackToOne","line":95,"loc":{"start":{"line":95,"column":4},"end":{"line":110,"column":4}}},"6":{"name":"_RAboveBuyBaseToken","line":114,"loc":{"start":{"line":114,"column":4},"end":{"line":122,"column":4}}},"7":{"name":"_RAboveSellBaseToken","line":124,"loc":{"start":{"line":124,"column":4},"end":{"line":134,"column":4}}},"8":{"name":"_RAboveBackToOne","line":136,"loc":{"start":{"line":136,"column":4},"end":{"line":151,"column":4}}},"9":{"name":"_getExpectedTarget","line":155,"loc":{"start":{"line":155,"column":4},"end":{"line":167,"column":4}}},"10":{"name":"_RAboveIntegrate","line":169,"loc":{"start":{"line":169,"column":4},"end":{"line":176,"column":4}}}},"statementMap":{"1":{"start":{"line":34,"column":8},"end":{"line":34,"column":36}},"2":{"start":{"line":35,"column":8},"end":{"line":35,"column":783}},"3":{"start":{"line":44,"column":8},"end":{"line":44,"column":45}},"4":{"start":{"line":52,"column":8},"end":{"line":52,"column":84}},"5":{"start":{"line":53,"column":8},"end":{"line":53,"column":54}},"6":{"start":{"line":54,"column":8},"end":{"line":54,"column":89}},"7":{"start":{"line":55,"column":8},"end":{"line":55,"column":28}},"8":{"start":{"line":65,"column":8},"end":{"line":65,"column":36}},"9":{"start":{"line":66,"column":8},"end":{"line":66,"column":1874}},"10":{"start":{"line":73,"column":8},"end":{"line":73,"column":40}},"11":{"start":{"line":84,"column":8},"end":{"line":84,"column":36}},"12":{"start":{"line":85,"column":8},"end":{"line":85,"column":2496}},"13":{"start":{"line":92,"column":8},"end":{"line":92,"column":35}},"14":{"start":{"line":101,"column":8},"end":{"line":101,"column":74}},"15":{"start":{"line":102,"column":8},"end":{"line":102,"column":40}},"16":{"start":{"line":103,"column":8},"end":{"line":103,"column":62}},"17":{"start":{"line":104,"column":8},"end":{"line":104,"column":3168}},"18":{"start":{"line":109,"column":8},"end":{"line":109,"column":63}},"19":{"start":{"line":119,"column":8},"end":{"line":119,"column":74}},"20":{"start":{"line":120,"column":8},"end":{"line":120,"column":44}},"21":{"start":{"line":121,"column":8},"end":{"line":121,"column":66}},"22":{"start":{"line":132,"column":8},"end":{"line":132,"column":44}},"23":{"start":{"line":133,"column":8},"end":{"line":133,"column":66}},"24":{"start":{"line":142,"column":8},"end":{"line":142,"column":77}},"25":{"start":{"line":143,"column":8},"end":{"line":143,"column":40}},"26":{"start":{"line":144,"column":8},"end":{"line":144,"column":68}},"27":{"start":{"line":145,"column":8},"end":{"line":145,"column":4694}},"28":{"start":{"line":150,"column":8},"end":{"line":150,"column":62}},"29":{"start":{"line":156,"column":8},"end":{"line":156,"column":35}},"30":{"start":{"line":157,"column":8},"end":{"line":157,"column":34}},"31":{"start":{"line":158,"column":8},"end":{"line":158,"column":5142}},"32":{"start":{"line":159,"column":12},"end":{"line":159,"column":76}},"33":{"start":{"line":160,"column":15},"end":{"line":160,"column":5274}},"34":{"start":{"line":161,"column":12},"end":{"line":161,"column":82}},"35":{"start":{"line":162,"column":12},"end":{"line":162,"column":66}},"36":{"start":{"line":163,"column":15},"end":{"line":163,"column":5486}},"37":{"start":{"line":164,"column":12},"end":{"line":164,"column":82}},"38":{"start":{"line":165,"column":12},"end":{"line":165,"column":66}},"39":{"start":{"line":174,"column":8},"end":{"line":174,"column":36}},"40":{"start":{"line":175,"column":8},"end":{"line":175,"column":61}}},"branchMap":{"1":{"line":52,"type":"if","locations":[{"start":{"line":52,"column":8},"end":{"line":52,"column":8}},{"start":{"line":52,"column":8},"end":{"line":52,"column":8}}]},"2":{"line":119,"type":"if","locations":[{"start":{"line":119,"column":8},"end":{"line":119,"column":8}},{"start":{"line":119,"column":8},"end":{"line":119,"column":8}}]},"3":{"line":158,"type":"if","locations":[{"start":{"line":158,"column":8},"end":{"line":158,"column":8}},{"start":{"line":158,"column":8},"end":{"line":158,"column":8}}]},"4":{"line":160,"type":"if","locations":[{"start":{"line":160,"column":15},"end":{"line":160,"column":15}},{"start":{"line":160,"column":15},"end":{"line":160,"column":15}}]},"5":{"line":163,"type":"if","locations":[{"start":{"line":163,"column":15},"end":{"line":163,"column":15}},{"start":{"line":163,"column":15},"end":{"line":163,"column":15}}]}}},"contracts/impl/Settlement.sol":{"l":{"40":74,"41":74,"45":80,"46":80,"50":102,"51":102,"55":79,"56":79,"62":57,"63":57,"67":45,"68":45,"72":1,"73":1,"77":1,"78":1,"85":4,"86":4,"87":4,"88":4,"89":4,"90":4,"92":4,"93":1,"95":3,"96":2,"97":2,"98":2,"100":1,"101":1,"102":1,"104":3,"109":6,"110":5,"111":4,"112":4,"116":4,"120":4,"121":4,"122":4,"123":4,"128":4,"129":2,"134":3,"135":2,"140":2},"path":"/Users/leimingda/Documents/dodo/contracts/impl/Settlement.sol","s":{"1":74,"2":74,"3":80,"4":80,"5":102,"6":102,"7":79,"8":79,"9":57,"10":57,"11":45,"12":45,"13":1,"14":1,"15":1,"16":1,"17":4,"18":4,"19":4,"20":4,"21":4,"22":4,"23":4,"24":1,"25":3,"26":2,"27":2,"28":2,"29":1,"30":1,"31":1,"32":3,"33":6,"34":5,"35":4,"36":4,"37":4,"38":4,"39":4,"40":4,"41":4,"42":4,"43":2,"44":3,"45":2,"46":2},"b":{"1":[1,3],"2":[2,1],"3":[5,1],"4":[4,1],"5":[2,2],"6":[1,1],"7":[2,1],"8":[1,1]},"f":{"1":74,"2":80,"3":102,"4":79,"5":57,"6":45,"7":1,"8":1,"9":4,"10":6,"11":4},"fnMap":{"1":{"name":"_baseTokenTransferIn","line":39,"loc":{"start":{"line":39,"column":4},"end":{"line":42,"column":4}}},"2":{"name":"_quoteTokenTransferIn","line":44,"loc":{"start":{"line":44,"column":4},"end":{"line":47,"column":4}}},"3":{"name":"_baseTokenTransferOut","line":49,"loc":{"start":{"line":49,"column":4},"end":{"line":52,"column":4}}},"4":{"name":"_quoteTokenTransferOut","line":54,"loc":{"start":{"line":54,"column":4},"end":{"line":57,"column":4}}},"5":{"name":"_donateBaseToken","line":61,"loc":{"start":{"line":61,"column":4},"end":{"line":64,"column":4}}},"6":{"name":"_donateQuoteToken","line":66,"loc":{"start":{"line":66,"column":4},"end":{"line":69,"column":4}}},"7":{"name":"donateBaseToken","line":71,"loc":{"start":{"line":71,"column":4},"end":{"line":74,"column":4}}},"8":{"name":"donateQuoteToken","line":76,"loc":{"start":{"line":76,"column":4},"end":{"line":79,"column":4}}},"9":{"name":"finalSettlement","line":84,"loc":{"start":{"line":84,"column":4},"end":{"line":105,"column":4}}},"10":{"name":"claim","line":108,"loc":{"start":{"line":108,"column":4},"end":{"line":124,"column":4}}},"11":{"name":"retrieve","line":127,"loc":{"start":{"line":127,"column":4},"end":{"line":141,"column":4}}}},"statementMap":{"1":{"start":{"line":40,"column":8},"end":{"line":40,"column":73}},"2":{"start":{"line":41,"column":8},"end":{"line":41,"column":50}},"3":{"start":{"line":45,"column":8},"end":{"line":45,"column":74}},"4":{"start":{"line":46,"column":8},"end":{"line":46,"column":52}},"5":{"start":{"line":50,"column":8},"end":{"line":50,"column":52}},"6":{"start":{"line":51,"column":8},"end":{"line":51,"column":50}},"7":{"start":{"line":55,"column":8},"end":{"line":55,"column":53}},"8":{"start":{"line":56,"column":8},"end":{"line":56,"column":52}},"9":{"start":{"line":62,"column":8},"end":{"line":62,"column":74}},"10":{"start":{"line":63,"column":8},"end":{"line":63,"column":36}},"11":{"start":{"line":67,"column":8},"end":{"line":67,"column":76}},"12":{"start":{"line":68,"column":8},"end":{"line":68,"column":37}},"13":{"start":{"line":72,"column":8},"end":{"line":72,"column":47}},"14":{"start":{"line":73,"column":8},"end":{"line":73,"column":31}},"15":{"start":{"line":77,"column":8},"end":{"line":77,"column":48}},"16":{"start":{"line":78,"column":8},"end":{"line":78,"column":32}},"17":{"start":{"line":85,"column":8},"end":{"line":85,"column":22}},"18":{"start":{"line":86,"column":8},"end":{"line":86,"column":38}},"19":{"start":{"line":87,"column":8},"end":{"line":87,"column":37}},"20":{"start":{"line":88,"column":8},"end":{"line":88,"column":30}},"21":{"start":{"line":89,"column":8},"end":{"line":89,"column":56}},"22":{"start":{"line":90,"column":8},"end":{"line":90,"column":58}},"23":{"start":{"line":92,"column":8},"end":{"line":92,"column":2792}},"24":{"start":{"line":93,"column":12},"end":{"line":93,"column":18}},"25":{"start":{"line":95,"column":8},"end":{"line":95,"column":2869}},"26":{"start":{"line":96,"column":12},"end":{"line":96,"column":54}},"27":{"start":{"line":97,"column":12},"end":{"line":97,"column":81}},"28":{"start":{"line":98,"column":12},"end":{"line":98,"column":92}},"29":{"start":{"line":100,"column":12},"end":{"line":100,"column":56}},"30":{"start":{"line":101,"column":12},"end":{"line":101,"column":78}},"31":{"start":{"line":102,"column":12},"end":{"line":102,"column":92}},"32":{"start":{"line":104,"column":8},"end":{"line":104,"column":37}},"33":{"start":{"line":109,"column":8},"end":{"line":109,"column":43}},"34":{"start":{"line":110,"column":8},"end":{"line":110,"column":57}},"35":{"start":{"line":111,"column":8},"end":{"line":111,"column":35}},"36":{"start":{"line":112,"column":8},"end":{"line":112,"column":3695}},"37":{"start":{"line":116,"column":8},"end":{"line":116,"column":3843}},"38":{"start":{"line":120,"column":8},"end":{"line":120,"column":52}},"39":{"start":{"line":121,"column":8},"end":{"line":121,"column":54}},"40":{"start":{"line":122,"column":8},"end":{"line":122,"column":30}},"41":{"start":{"line":123,"column":8},"end":{"line":123,"column":14}},"42":{"start":{"line":128,"column":8},"end":{"line":128,"column":4284}},"43":{"start":{"line":129,"column":12},"end":{"line":129,"column":4329}},"44":{"start":{"line":134,"column":8},"end":{"line":134,"column":4507}},"45":{"start":{"line":135,"column":12},"end":{"line":135,"column":4553}},"46":{"start":{"line":140,"column":8},"end":{"line":140,"column":53}}},"branchMap":{"1":{"line":92,"type":"if","locations":[{"start":{"line":92,"column":8},"end":{"line":92,"column":8}},{"start":{"line":92,"column":8},"end":{"line":92,"column":8}}]},"2":{"line":95,"type":"if","locations":[{"start":{"line":95,"column":8},"end":{"line":95,"column":8}},{"start":{"line":95,"column":8},"end":{"line":95,"column":8}}]},"3":{"line":109,"type":"if","locations":[{"start":{"line":109,"column":8},"end":{"line":109,"column":8}},{"start":{"line":109,"column":8},"end":{"line":109,"column":8}}]},"4":{"line":110,"type":"if","locations":[{"start":{"line":110,"column":8},"end":{"line":110,"column":8}},{"start":{"line":110,"column":8},"end":{"line":110,"column":8}}]},"5":{"line":128,"type":"if","locations":[{"start":{"line":128,"column":8},"end":{"line":128,"column":8}},{"start":{"line":128,"column":8},"end":{"line":128,"column":8}}]},"6":{"line":129,"type":"if","locations":[{"start":{"line":129,"column":12},"end":{"line":129,"column":12}},{"start":{"line":129,"column":12},"end":{"line":129,"column":12}}]},"7":{"line":134,"type":"if","locations":[{"start":{"line":134,"column":8},"end":{"line":134,"column":8}},{"start":{"line":134,"column":8},"end":{"line":134,"column":8}}]},"8":{"line":135,"type":"if","locations":[{"start":{"line":135,"column":12},"end":{"line":135,"column":12}},{"start":{"line":135,"column":12},"end":{"line":135,"column":12}}]}}},"contracts/impl/Storage.sol":{"l":{"71":8,"72":4,"76":11,"77":7,"83":17,"84":16,"85":15,"89":171,"93":58,"97":91,"101":57,"105":83},"path":"/Users/leimingda/Documents/dodo/contracts/impl/Storage.sol","s":{"1":8,"2":11,"3":17,"4":16,"5":15,"6":171,"7":58,"8":91,"9":57,"10":83},"b":{"1":[4,4],"2":[7,4],"3":[16,1],"4":[15,1],"5":[13,2]},"f":{"1":8,"2":11,"3":17,"4":171,"5":58,"6":91,"7":57,"8":83},"fnMap":{"1":{"name":"onlySupervisorOrOwner","line":70,"loc":{"start":{"line":70,"column":4},"end":{"line":73,"column":4}}},"2":{"name":"notClosed","line":75,"loc":{"start":{"line":75,"column":4},"end":{"line":78,"column":4}}},"3":{"name":"_checkDODOParameters","line":82,"loc":{"start":{"line":82,"column":4},"end":{"line":86,"column":4}}},"4":{"name":"getOraclePrice","line":88,"loc":{"start":{"line":88,"column":4},"end":{"line":90,"column":4}}},"5":{"name":"getBaseCapitalBalanceOf","line":92,"loc":{"start":{"line":92,"column":4},"end":{"line":94,"column":4}}},"6":{"name":"getTotalBaseCapital","line":96,"loc":{"start":{"line":96,"column":4},"end":{"line":98,"column":4}}},"7":{"name":"getQuoteCapitalBalanceOf","line":100,"loc":{"start":{"line":100,"column":4},"end":{"line":102,"column":4}}},"8":{"name":"getTotalQuoteCapital","line":104,"loc":{"start":{"line":104,"column":4},"end":{"line":106,"column":4}}}},"statementMap":{"1":{"start":{"line":71,"column":8},"end":{"line":71,"column":94}},"2":{"start":{"line":76,"column":8},"end":{"line":76,"column":43}},"3":{"start":{"line":83,"column":8},"end":{"line":83,"column":64}},"4":{"start":{"line":84,"column":8},"end":{"line":84,"column":54}},"5":{"start":{"line":85,"column":8},"end":{"line":85,"column":95}},"6":{"start":{"line":89,"column":8},"end":{"line":89,"column":43}},"7":{"start":{"line":93,"column":8},"end":{"line":93,"column":63}},"8":{"start":{"line":97,"column":8},"end":{"line":97,"column":63}},"9":{"start":{"line":101,"column":8},"end":{"line":101,"column":64}},"10":{"start":{"line":105,"column":8},"end":{"line":105,"column":64}}},"branchMap":{"1":{"line":71,"type":"if","locations":[{"start":{"line":71,"column":8},"end":{"line":71,"column":8}},{"start":{"line":71,"column":8},"end":{"line":71,"column":8}}]},"2":{"line":76,"type":"if","locations":[{"start":{"line":76,"column":8},"end":{"line":76,"column":8}},{"start":{"line":76,"column":8},"end":{"line":76,"column":8}}]},"3":{"line":83,"type":"if","locations":[{"start":{"line":83,"column":8},"end":{"line":83,"column":8}},{"start":{"line":83,"column":8},"end":{"line":83,"column":8}}]},"4":{"line":84,"type":"if","locations":[{"start":{"line":84,"column":8},"end":{"line":84,"column":8}},{"start":{"line":84,"column":8},"end":{"line":84,"column":8}}]},"5":{"line":85,"type":"if","locations":[{"start":{"line":85,"column":8},"end":{"line":85,"column":8}},{"start":{"line":85,"column":8},"end":{"line":85,"column":8}}]}}},"contracts/impl/Trader.sol":{"l":{"39":81,"40":80,"44":80,"45":78,"58":32,"66":32,"69":31,"70":31,"71":31,"74":31,"75":31,"76":31,"78":31,"79":31,"80":31,"82":31,"93":46,"101":43,"104":42,"105":42,"106":42,"109":42,"110":42,"111":42,"113":42,"114":42,"115":42,"117":42,"123":1,"124":1,"128":1,"129":1,"144":33,"146":33,"148":33,"151":21,"152":21,"154":11,"155":11,"158":11,"160":5,"161":5,"162":5,"165":0,"169":2,"170":2,"173":4,"176":4,"181":1,"182":1,"186":33,"187":33,"188":33,"190":33,"205":47,"208":47,"209":47,"210":47,"212":47,"214":32,"215":30,"218":7,"219":6,"221":8,"222":8,"225":8,"227":2,"228":2,"231":3,"232":3,"235":3,"238":3,"242":44},"path":"/Users/leimingda/Documents/dodo/contracts/impl/Trader.sol","s":{"1":81,"2":80,"3":32,"4":32,"5":31,"6":31,"7":31,"8":31,"9":31,"10":31,"11":31,"12":31,"13":31,"14":31,"15":46,"16":43,"17":42,"18":42,"19":42,"20":42,"21":42,"22":42,"23":42,"24":42,"25":42,"26":42,"27":1,"28":1,"29":1,"30":1,"31":33,"32":33,"33":33,"34":21,"35":21,"36":12,"37":11,"38":11,"39":11,"40":5,"41":5,"42":5,"43":0,"44":6,"45":2,"46":2,"47":4,"48":4,"49":1,"50":1,"51":33,"52":33,"53":33,"54":33,"55":47,"56":47,"57":47,"58":47,"59":47,"60":32,"61":30,"62":15,"63":7,"64":6,"65":8,"66":8,"67":8,"68":8,"69":2,"70":2,"71":6,"72":3,"73":3,"74":3,"75":3,"76":44},"b":{"1":[80,1],"2":[78,2],"3":[31,1],"4":[42,1],"5":[21,12],"6":[11,1],"7":[5,6],"8":[0,5],"9":[2,4],"10":[32,15],"11":[7,8],"12":[8,0],"13":[2,6],"14":[3,3]},"f":{"1":81,"2":80,"3":32,"4":46,"5":1,"6":1,"7":33,"8":47},"fnMap":{"1":{"name":"tradeAllowed","line":38,"loc":{"start":{"line":38,"column":4},"end":{"line":41,"column":4}}},"2":{"name":"gasPriceLimit","line":43,"loc":{"start":{"line":43,"column":4},"end":{"line":46,"column":4}}},"3":{"name":"sellBaseToken","line":54,"loc":{"start":{"line":50,"column":4},"end":{"line":83,"column":4}}},"4":{"name":"buyBaseToken","line":89,"loc":{"start":{"line":85,"column":4},"end":{"line":118,"column":4}}},"5":{"name":"querySellBaseToken","line":122,"loc":{"start":{"line":122,"column":4},"end":{"line":125,"column":4}}},"6":{"name":"queryBuyBaseToken","line":127,"loc":{"start":{"line":127,"column":4},"end":{"line":130,"column":4}}},"7":{"name":"_querySellBaseToken","line":132,"loc":{"start":{"line":132,"column":4},"end":{"line":191,"column":4}}},"8":{"name":"_queryBuyBaseToken","line":193,"loc":{"start":{"line":193,"column":4},"end":{"line":243,"column":4}}}},"statementMap":{"1":{"start":{"line":39,"column":8},"end":{"line":39,"column":52}},"2":{"start":{"line":44,"column":8},"end":{"line":44,"column":68}},"3":{"start":{"line":58,"column":8},"end":{"line":58,"column":1427}},"4":{"start":{"line":66,"column":8},"end":{"line":66,"column":79}},"5":{"start":{"line":69,"column":8},"end":{"line":69,"column":47}},"6":{"start":{"line":70,"column":8},"end":{"line":70,"column":55}},"7":{"start":{"line":71,"column":8},"end":{"line":71,"column":55}},"8":{"start":{"line":74,"column":8},"end":{"line":74,"column":51}},"9":{"start":{"line":75,"column":8},"end":{"line":75,"column":49}},"10":{"start":{"line":76,"column":8},"end":{"line":76,"column":30}},"11":{"start":{"line":78,"column":8},"end":{"line":78,"column":36}},"12":{"start":{"line":79,"column":8},"end":{"line":79,"column":60}},"13":{"start":{"line":80,"column":8},"end":{"line":80,"column":45}},"14":{"start":{"line":82,"column":8},"end":{"line":82,"column":27}},"15":{"start":{"line":93,"column":8},"end":{"line":93,"column":2511}},"16":{"start":{"line":101,"column":8},"end":{"line":101,"column":65}},"17":{"start":{"line":104,"column":8},"end":{"line":104,"column":50}},"18":{"start":{"line":105,"column":8},"end":{"line":105,"column":48}},"19":{"start":{"line":106,"column":8},"end":{"line":106,"column":53}},"20":{"start":{"line":109,"column":8},"end":{"line":109,"column":51}},"21":{"start":{"line":110,"column":8},"end":{"line":110,"column":49}},"22":{"start":{"line":111,"column":8},"end":{"line":111,"column":30}},"23":{"start":{"line":113,"column":8},"end":{"line":113,"column":34}},"24":{"start":{"line":114,"column":8},"end":{"line":114,"column":55}},"25":{"start":{"line":115,"column":8},"end":{"line":115,"column":43}},"26":{"start":{"line":117,"column":8},"end":{"line":117,"column":23}},"27":{"start":{"line":123,"column":8},"end":{"line":123,"column":61}},"28":{"start":{"line":124,"column":8},"end":{"line":124,"column":27}},"29":{"start":{"line":128,"column":8},"end":{"line":128,"column":56}},"30":{"start":{"line":129,"column":8},"end":{"line":129,"column":23}},"31":{"start":{"line":144,"column":8},"end":{"line":144,"column":61}},"32":{"start":{"line":146,"column":8},"end":{"line":146,"column":39}},"33":{"start":{"line":148,"column":8},"end":{"line":148,"column":4175}},"34":{"start":{"line":151,"column":12},"end":{"line":151,"column":76}},"35":{"start":{"line":152,"column":12},"end":{"line":152,"column":47}},"36":{"start":{"line":153,"column":15},"end":{"line":153,"column":4418}},"37":{"start":{"line":154,"column":12},"end":{"line":154,"column":72}},"38":{"start":{"line":155,"column":12},"end":{"line":155,"column":79}},"39":{"start":{"line":158,"column":12},"end":{"line":158,"column":4725}},"40":{"start":{"line":160,"column":16},"end":{"line":160,"column":97}},"41":{"start":{"line":161,"column":16},"end":{"line":161,"column":51}},"42":{"start":{"line":162,"column":16},"end":{"line":162,"column":4992}},"43":{"start":{"line":165,"column":20},"end":{"line":165,"column":55}},"44":{"start":{"line":167,"column":19},"end":{"line":167,"column":5394}},"45":{"start":{"line":169,"column":16},"end":{"line":169,"column":51}},"46":{"start":{"line":170,"column":16},"end":{"line":170,"column":45}},"47":{"start":{"line":173,"column":16},"end":{"line":173,"column":5691}},"48":{"start":{"line":176,"column":16},"end":{"line":176,"column":51}},"49":{"start":{"line":181,"column":12},"end":{"line":181,"column":94}},"50":{"start":{"line":182,"column":12},"end":{"line":182,"column":47}},"51":{"start":{"line":186,"column":8},"end":{"line":186,"column":64}},"52":{"start":{"line":187,"column":8},"end":{"line":187,"column":64}},"53":{"start":{"line":188,"column":8},"end":{"line":188,"column":66}},"54":{"start":{"line":190,"column":8},"end":{"line":190,"column":96}},"55":{"start":{"line":205,"column":8},"end":{"line":205,"column":61}},"56":{"start":{"line":208,"column":8},"end":{"line":208,"column":57}},"57":{"start":{"line":209,"column":8},"end":{"line":209,"column":57}},"58":{"start":{"line":210,"column":8},"end":{"line":210,"column":68}},"59":{"start":{"line":212,"column":8},"end":{"line":212,"column":7114}},"60":{"start":{"line":214,"column":12},"end":{"line":214,"column":69}},"61":{"start":{"line":215,"column":12},"end":{"line":215,"column":47}},"62":{"start":{"line":216,"column":15},"end":{"line":216,"column":7317}},"63":{"start":{"line":218,"column":12},"end":{"line":218,"column":87}},"64":{"start":{"line":219,"column":12},"end":{"line":219,"column":47}},"65":{"start":{"line":220,"column":15},"end":{"line":220,"column":7544}},"66":{"start":{"line":221,"column":12},"end":{"line":221,"column":75}},"67":{"start":{"line":222,"column":12},"end":{"line":222,"column":76}},"68":{"start":{"line":225,"column":12},"end":{"line":225,"column":7836}},"69":{"start":{"line":227,"column":16},"end":{"line":227,"column":94}},"70":{"start":{"line":228,"column":16},"end":{"line":228,"column":51}},"71":{"start":{"line":229,"column":19},"end":{"line":229,"column":8102}},"72":{"start":{"line":231,"column":16},"end":{"line":231,"column":43}},"73":{"start":{"line":232,"column":16},"end":{"line":232,"column":45}},"74":{"start":{"line":235,"column":16},"end":{"line":235,"column":8394}},"75":{"start":{"line":238,"column":16},"end":{"line":238,"column":51}},"76":{"start":{"line":242,"column":8},"end":{"line":242,"column":90}}},"branchMap":{"1":{"line":39,"type":"if","locations":[{"start":{"line":39,"column":8},"end":{"line":39,"column":8}},{"start":{"line":39,"column":8},"end":{"line":39,"column":8}}]},"2":{"line":44,"type":"if","locations":[{"start":{"line":44,"column":8},"end":{"line":44,"column":8}},{"start":{"line":44,"column":8},"end":{"line":44,"column":8}}]},"3":{"line":66,"type":"if","locations":[{"start":{"line":66,"column":8},"end":{"line":66,"column":8}},{"start":{"line":66,"column":8},"end":{"line":66,"column":8}}]},"4":{"line":101,"type":"if","locations":[{"start":{"line":101,"column":8},"end":{"line":101,"column":8}},{"start":{"line":101,"column":8},"end":{"line":101,"column":8}}]},"5":{"line":148,"type":"if","locations":[{"start":{"line":148,"column":8},"end":{"line":148,"column":8}},{"start":{"line":148,"column":8},"end":{"line":148,"column":8}}]},"6":{"line":153,"type":"if","locations":[{"start":{"line":153,"column":15},"end":{"line":153,"column":15}},{"start":{"line":153,"column":15},"end":{"line":153,"column":15}}]},"7":{"line":158,"type":"if","locations":[{"start":{"line":158,"column":12},"end":{"line":158,"column":12}},{"start":{"line":158,"column":12},"end":{"line":158,"column":12}}]},"8":{"line":162,"type":"if","locations":[{"start":{"line":162,"column":16},"end":{"line":162,"column":16}},{"start":{"line":162,"column":16},"end":{"line":162,"column":16}}]},"9":{"line":167,"type":"if","locations":[{"start":{"line":167,"column":19},"end":{"line":167,"column":19}},{"start":{"line":167,"column":19},"end":{"line":167,"column":19}}]},"10":{"line":212,"type":"if","locations":[{"start":{"line":212,"column":8},"end":{"line":212,"column":8}},{"start":{"line":212,"column":8},"end":{"line":212,"column":8}}]},"11":{"line":216,"type":"if","locations":[{"start":{"line":216,"column":15},"end":{"line":216,"column":15}},{"start":{"line":216,"column":15},"end":{"line":216,"column":15}}]},"12":{"line":220,"type":"if","locations":[{"start":{"line":220,"column":15},"end":{"line":220,"column":15}},{"start":{"line":220,"column":15},"end":{"line":220,"column":15}}]},"13":{"line":225,"type":"if","locations":[{"start":{"line":225,"column":12},"end":{"line":225,"column":12}},{"start":{"line":225,"column":12},"end":{"line":225,"column":12}}]},"14":{"line":229,"type":"if","locations":[{"start":{"line":229,"column":19},"end":{"line":229,"column":19}},{"start":{"line":229,"column":19},"end":{"line":229,"column":19}}]}}},"contracts/lib/DODOMath.sol":{"l":{"38":44,"39":44,"40":44,"41":44,"42":44,"43":44,"69":28,"70":28,"71":28,"72":28,"73":2,"75":26,"77":28,"78":22,"79":22,"81":6,"82":6,"86":28,"90":28,"93":28,"94":28,"95":22,"97":6,"113":113,"114":113,"115":113,"117":113},"path":"/Users/leimingda/Documents/dodo/contracts/lib/DODOMath.sol","s":{"1":44,"2":44,"3":44,"4":44,"5":44,"6":44,"7":28,"8":28,"9":28,"10":28,"11":2,"12":26,"13":28,"14":22,"15":22,"16":6,"17":6,"18":28,"19":28,"20":28,"21":28,"22":22,"23":6,"24":113,"25":113,"26":113,"27":113},"b":{"1":[2,26],"2":[22,6],"3":[22,6]},"f":{"1":44,"2":28,"3":113},"fnMap":{"1":{"name":"_GeneralIntegrate","line":31,"loc":{"start":{"line":31,"column":4},"end":{"line":44,"column":4}}},"2":{"name":"_SolveQuadraticFunctionForTrade","line":60,"loc":{"start":{"line":60,"column":4},"end":{"line":99,"column":4}}},"3":{"name":"_SolveQuadraticFunctionForTarget","line":107,"loc":{"start":{"line":107,"column":4},"end":{"line":118,"column":4}}}},"statementMap":{"1":{"start":{"line":38,"column":8},"end":{"line":38,"column":34}},"2":{"start":{"line":39,"column":8},"end":{"line":39,"column":54}},"3":{"start":{"line":40,"column":8},"end":{"line":40,"column":50}},"4":{"start":{"line":41,"column":8},"end":{"line":41,"column":50}},"5":{"start":{"line":42,"column":8},"end":{"line":42,"column":73}},"6":{"start":{"line":43,"column":8},"end":{"line":43,"column":79}},"7":{"start":{"line":69,"column":8},"end":{"line":69,"column":63}},"8":{"start":{"line":70,"column":8},"end":{"line":70,"column":63}},"9":{"start":{"line":71,"column":8},"end":{"line":71,"column":29}},"10":{"start":{"line":72,"column":8},"end":{"line":72,"column":2179}},"11":{"start":{"line":73,"column":12},"end":{"line":73,"column":29}},"12":{"start":{"line":75,"column":12},"end":{"line":75,"column":39}},"13":{"start":{"line":77,"column":8},"end":{"line":77,"column":2350}},"14":{"start":{"line":78,"column":12},"end":{"line":78,"column":28}},"15":{"start":{"line":79,"column":12},"end":{"line":79,"column":27}},"16":{"start":{"line":81,"column":12},"end":{"line":81,"column":28}},"17":{"start":{"line":82,"column":12},"end":{"line":82,"column":28}},"18":{"start":{"line":86,"column":8},"end":{"line":86,"column":2555}},"19":{"start":{"line":90,"column":8},"end":{"line":90,"column":51}},"20":{"start":{"line":93,"column":8},"end":{"line":93,"column":59}},"21":{"start":{"line":94,"column":8},"end":{"line":94,"column":2885}},"22":{"start":{"line":95,"column":12},"end":{"line":95,"column":71}},"23":{"start":{"line":97,"column":12},"end":{"line":97,"column":71}},"24":{"start":{"line":113,"column":8},"end":{"line":113,"column":86}},"25":{"start":{"line":114,"column":8},"end":{"line":114,"column":67}},"26":{"start":{"line":115,"column":8},"end":{"line":115,"column":83}},"27":{"start":{"line":117,"column":8},"end":{"line":117,"column":64}}},"branchMap":{"1":{"line":72,"type":"if","locations":[{"start":{"line":72,"column":8},"end":{"line":72,"column":8}},{"start":{"line":72,"column":8},"end":{"line":72,"column":8}}]},"2":{"line":77,"type":"if","locations":[{"start":{"line":77,"column":8},"end":{"line":77,"column":8}},{"start":{"line":77,"column":8},"end":{"line":77,"column":8}}]},"3":{"line":94,"type":"if","locations":[{"start":{"line":94,"column":8},"end":{"line":94,"column":8}},{"start":{"line":94,"column":8},"end":{"line":94,"column":8}}]}}},"contracts/lib/SafeERC20.sol":{"l":{"33":184,"42":155,"65":339,"66":339,"68":339,"71":339},"path":"/Users/leimingda/Documents/dodo/contracts/lib/SafeERC20.sol","s":{"1":184,"2":155,"3":339,"4":339,"5":339,"6":339},"b":{"1":[339,0],"2":[339,0],"3":[339,0]},"f":{"1":184,"2":155,"3":339},"fnMap":{"1":{"name":"safeTransfer","line":28,"loc":{"start":{"line":28,"column":4},"end":{"line":34,"column":4}}},"2":{"name":"safeTransferFrom","line":36,"loc":{"start":{"line":36,"column":4},"end":{"line":46,"column":4}}},"3":{"name":"_callOptionalReturn","line":54,"loc":{"start":{"line":54,"column":4},"end":{"line":73,"column":4}}}},"statementMap":{"1":{"start":{"line":33,"column":8},"end":{"line":33,"column":93}},"2":{"start":{"line":42,"column":8},"end":{"line":42,"column":1162}},"3":{"start":{"line":65,"column":8},"end":{"line":65,"column":75}},"4":{"start":{"line":66,"column":8},"end":{"line":66,"column":59}},"5":{"start":{"line":68,"column":8},"end":{"line":68,"column":2470}},"6":{"start":{"line":71,"column":12},"end":{"line":71,"column":96}}},"branchMap":{"1":{"line":66,"type":"if","locations":[{"start":{"line":66,"column":8},"end":{"line":66,"column":8}},{"start":{"line":66,"column":8},"end":{"line":66,"column":8}}]},"2":{"line":68,"type":"if","locations":[{"start":{"line":68,"column":8},"end":{"line":68,"column":8}},{"start":{"line":68,"column":8},"end":{"line":68,"column":8}}]},"3":{"line":71,"type":"if","locations":[{"start":{"line":71,"column":12},"end":{"line":71,"column":12}},{"start":{"line":71,"column":12},"end":{"line":71,"column":12}}]}}}} \ No newline at end of file diff --git a/migrations/1_initial_migration.js b/migrations/1_initial_migration.js new file mode 100644 index 0000000..ee2135d --- /dev/null +++ b/migrations/1_initial_migration.js @@ -0,0 +1,5 @@ +const Migrations = artifacts.require("Migrations"); + +module.exports = function(deployer) { + deployer.deploy(Migrations); +}; diff --git a/migrations/2_deploy.js b/migrations/2_deploy.js new file mode 100644 index 0000000..943d7be --- /dev/null +++ b/migrations/2_deploy.js @@ -0,0 +1,27 @@ +const DecimalMath = artifacts.require("DecimalMath"); +const SafeERC20 = artifacts.require("SafeERC20"); +const DODOMath = artifacts.require("DODOMath"); +const DODO = artifacts.require("DODO"); +const DODOZoo = artifacts.require("DODOZoo"); + +module.exports = async (deployer, network) => { + const deployDODO = async () => { + await deployer.deploy(DecimalMath); + await deployer.deploy(SafeERC20); + await deployer.deploy(DODOMath); + + await deployer.link(SafeERC20, DODO); + await deployer.link(DecimalMath, DODO); + await deployer.link(DODOMath, DODO); + + await deployer.deploy(DODO); + await deployer.deploy(DODOZoo); + }; + + if (network == "production") { + } else if (network == "kovan") { + } else { + // for development & test + await deployDODO(); + } +}; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..b5c0f03 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,10691 @@ +{ + "name": "dodo", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.1.tgz", + "integrity": "sha512-IGhtTmpjGbYzcEDOw7DcQtbQSXcG9ftmAXtWTu9V936vDye4xjjekktFAtgZsWpzTj/X01jocB46mTywm/4SZw==", + "requires": { + "@babel/highlight": "^7.10.1" + } + }, + "@babel/generator": { + "version": "7.10.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.10.2.tgz", + "integrity": "sha512-AxfBNHNu99DTMvlUPlt1h2+Hn7knPpH5ayJ8OqDWSeLld+Fi2AYBTC/IejWDM9Edcii4UzZRCsbUt0WlSDsDsA==", + "requires": { + "@babel/types": "^7.10.2", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } + } + }, + "@babel/helper-function-name": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.1.tgz", + "integrity": "sha512-fcpumwhs3YyZ/ttd5Rz0xn0TpIwVkN7X0V38B9TWNfVF42KEkhkAAuPCQ3oXmtTRtiPJrmZ0TrfS0GKF0eMaRQ==", + "requires": { + "@babel/helper-get-function-arity": "^7.10.1", + "@babel/template": "^7.10.1", + "@babel/types": "^7.10.1" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.1.tgz", + "integrity": "sha512-F5qdXkYGOQUb0hpRaPoetF9AnsXknKjWMZ+wmsIRsp5ge5sFh4c3h1eH2pRTTuy9KKAA2+TTYomGXAtEL2fQEw==", + "requires": { + "@babel/types": "^7.10.1" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.1.tgz", + "integrity": "sha512-UQ1LVBPrYdbchNhLwj6fetj46BcFwfS4NllJo/1aJsT+1dLTEnXJL0qHqtY7gPzF8S2fXBJamf1biAXV3X077g==", + "requires": { + "@babel/types": "^7.10.1" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.1.tgz", + "integrity": "sha512-5vW/JXLALhczRCWP0PnFDMCJAchlBvM7f4uk/jXritBnIa6E1KmqmtrS3yn1LAnxFBypQ3eneLuXjsnfQsgILw==" + }, + "@babel/highlight": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.1.tgz", + "integrity": "sha512-8rMof+gVP8mxYZApLF/JgNDAkdKa+aJt3ZYxF8z6+j/hpeXL7iMsKCPHa2jNMHu/qqBwzQF4OHNoYi8dMA/rYg==", + "requires": { + "@babel/helper-validator-identifier": "^7.10.1", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + } + } + }, + "@babel/parser": { + "version": "7.10.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.2.tgz", + "integrity": "sha512-PApSXlNMJyB4JiGVhCOlzKIif+TKFTvu0aQAhnTvfP/z3vVSN6ZypH5bfUNwFXXjRQtUEBNFd2PtmCmG2Py3qQ==" + }, + "@babel/template": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.1.tgz", + "integrity": "sha512-OQDg6SqvFSsc9A0ej6SKINWrpJiNonRIniYondK2ViKhB06i3c0s+76XUft71iqBEe9S1OKsHwPAjfHnuvnCig==", + "requires": { + "@babel/code-frame": "^7.10.1", + "@babel/parser": "^7.10.1", + "@babel/types": "^7.10.1" + } + }, + "@babel/traverse": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.10.1.tgz", + "integrity": "sha512-C/cTuXeKt85K+p08jN6vMDz8vSV0vZcI0wmQ36o6mjbuo++kPMdpOYw23W2XH04dbRt9/nMEfA4W3eR21CD+TQ==", + "requires": { + "@babel/code-frame": "^7.10.1", + "@babel/generator": "^7.10.1", + "@babel/helper-function-name": "^7.10.1", + "@babel/helper-split-export-declaration": "^7.10.1", + "@babel/parser": "^7.10.1", + "@babel/types": "^7.10.1", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + }, + "dependencies": { + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + } + } + }, + "@babel/types": { + "version": "7.10.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.2.tgz", + "integrity": "sha512-AD3AwWBSz0AWF0AkCN9VPiWrvldXq+/e3cHa4J89vo4ymjz1XwrBFFVZmkJTsQIPNk+ZVomPSXUJqq8yyjZsng==", + "requires": { + "@babel/helper-validator-identifier": "^7.10.1", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + }, + "dependencies": { + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + } + } + }, + "@ethersproject/abi": { + "version": "5.0.0-beta.153", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.0.0-beta.153.tgz", + "integrity": "sha512-aXweZ1Z7vMNzJdLpR1CZUAIgnwjrZeUSvN9syCwlBaEBUFJmFY+HHnfuTI5vIhVs/mRkfJVrbEyl51JZQqyjAg==", + "requires": { + "@ethersproject/address": ">=5.0.0-beta.128", + "@ethersproject/bignumber": ">=5.0.0-beta.130", + "@ethersproject/bytes": ">=5.0.0-beta.129", + "@ethersproject/constants": ">=5.0.0-beta.128", + "@ethersproject/hash": ">=5.0.0-beta.128", + "@ethersproject/keccak256": ">=5.0.0-beta.127", + "@ethersproject/logger": ">=5.0.0-beta.129", + "@ethersproject/properties": ">=5.0.0-beta.131", + "@ethersproject/strings": ">=5.0.0-beta.130" + } + }, + "@ethersproject/address": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.0.1.tgz", + "integrity": "sha512-kfQtXpBP2pI2TfoRRAYv8grHGiYw8U0c1KbMsC58/W33TIBy7gFSf/oAzOd94lNzdIUenKU0OuSzrHQfVcDDDA==", + "requires": { + "@ethersproject/bignumber": "^5.0.0", + "@ethersproject/bytes": "^5.0.0", + "@ethersproject/keccak256": "^5.0.0", + "@ethersproject/logger": "^5.0.0", + "@ethersproject/rlp": "^5.0.0", + "bn.js": "^4.4.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } + } + }, + "@ethersproject/bignumber": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.0.1.tgz", + "integrity": "sha512-srGDO7ksT0avdDw5pBtj6F81psv5xiJMInwSSatfIKplitubFb6yVwoHGObGRd0Pp3TvrkIDfJkuskoSMj4OHQ==", + "requires": { + "@ethersproject/bytes": "^5.0.0", + "@ethersproject/logger": "^5.0.0", + "@ethersproject/properties": "^5.0.0", + "bn.js": "^4.4.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } + } + }, + "@ethersproject/bytes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.0.1.tgz", + "integrity": "sha512-Y198536UW9Jb9RBXuqmCsCa9mYJUsxJn+5aGr2XjNMpLBc6vEn/44GHnbQXYgRCzh4rnWtJ9bTgSwDjme9Hgnw==", + "requires": { + "@ethersproject/logger": "^5.0.0" + } + }, + "@ethersproject/constants": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.0.1.tgz", + "integrity": "sha512-Xec07hFCPN4wfC3WDiRay7KipkApl2msiKTrBHCuAwNMOM8M92+mlQp8tgfEL51DPwCZkmdk1f02kArc6caVSw==", + "requires": { + "@ethersproject/bignumber": "^5.0.0" + } + }, + "@ethersproject/hash": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.0.1.tgz", + "integrity": "sha512-1ByUXYvkszrSSks07xctBtZfpFnIVmftxWlAAnguxh6Q65vKECd/EPi5uI5xVOvnrYMH9Vb8MK1SofPX/6fArQ==", + "requires": { + "@ethersproject/bytes": "^5.0.0", + "@ethersproject/keccak256": "^5.0.0", + "@ethersproject/logger": "^5.0.0", + "@ethersproject/strings": "^5.0.0" + } + }, + "@ethersproject/keccak256": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.0.1.tgz", + "integrity": "sha512-AtFm/4qHRQUvZcG3WYmaT7zV79dz72+N01w0XphcIBaD/7UZXyW85Uf08sirVlckHmh9fvc4UDWyHiroKsBT6Q==", + "requires": { + "@ethersproject/bytes": "^5.0.0", + "js-sha3": "0.5.7" + } + }, + "@ethersproject/logger": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.0.2.tgz", + "integrity": "sha512-NQe3O1/Nwkcp6bto6hsTvrcCeR/cOGK+RhOMn0Zi2FND6gdWsf1g+5ie8gQ1REqDX4MTGP/Y131dZas985ls/g==" + }, + "@ethersproject/properties": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.0.1.tgz", + "integrity": "sha512-b3VZ/NpYIf64/hFXeWNxVCbY1xoMPIYM3n6Qnu6Ayr3bLt1olFPQfAaaRB0aOsLz7tMtmkT3DrA1KG/IrOgBRw==", + "requires": { + "@ethersproject/logger": "^5.0.0" + } + }, + "@ethersproject/rlp": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.0.1.tgz", + "integrity": "sha512-3F8XE1zS4w8w4xiK1hMtFuVs6UnhQlmrEHLT85GanqK8vG5wGi81IQmkukL9tQIu2a5jykoO46ibja+6N1fpFg==", + "requires": { + "@ethersproject/bytes": "^5.0.0", + "@ethersproject/logger": "^5.0.0" + } + }, + "@ethersproject/signing-key": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.0.1.tgz", + "integrity": "sha512-Z3yMPFFf4KkWltndDNi/tpese7qZh6ZWKbGu3DHd8xOX0PJqbScdAs6gCfFeMatO06qyX307Y52soc/Ayf8ZSg==", + "requires": { + "@ethersproject/bytes": "^5.0.0", + "@ethersproject/logger": "^5.0.0", + "@ethersproject/properties": "^5.0.0", + "elliptic": "6.5.2" + } + }, + "@ethersproject/strings": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.0.1.tgz", + "integrity": "sha512-N8LxdHGBT7GZdogkEOV5xKXYTz5PNHuNzcxLNPYfH3kpvWSyXshZBgAz8YE1a8sMZagGj+Ic6d3mHijdCTSkGA==", + "requires": { + "@ethersproject/bytes": "^5.0.0", + "@ethersproject/constants": "^5.0.0", + "@ethersproject/logger": "^5.0.0" + } + }, + "@ethersproject/transactions": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.0.1.tgz", + "integrity": "sha512-IGc6/5hri3PrqR/ZCj89osDiq3Lt0CSrycn6vlRl8SjpBKYDdcT+Ru5xkeC7YcsnqcdBmTL+jyR3SLudU+x2Kw==", + "requires": { + "@ethersproject/address": "^5.0.0", + "@ethersproject/bignumber": "^5.0.0", + "@ethersproject/bytes": "^5.0.0", + "@ethersproject/constants": "^5.0.0", + "@ethersproject/keccak256": "^5.0.0", + "@ethersproject/logger": "^5.0.0", + "@ethersproject/properties": "^5.0.0", + "@ethersproject/rlp": "^5.0.0", + "@ethersproject/signing-key": "^5.0.0" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", + "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.3", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", + "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", + "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.3", + "fastq": "^1.6.0" + } + }, + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==" + }, + "@solidity-parser/parser": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.6.1.tgz", + "integrity": "sha512-MUA5kP9LdeTILeOsaz/k/qA4MdTNUxrn6q6HMYsMzQN5crU9bWKND2DaoWZhzofQM0VaTOaD8GFkCw1BYbNj5w==", + "dev": true + }, + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "requires": { + "defer-to-connect": "^1.0.1" + } + }, + "@truffle/error": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@truffle/error/-/error-0.0.7.tgz", + "integrity": "sha512-UIfVKsXSXocKnn5+RNklUXNoGd/JVj7V8KmC48TQzmjU33HQI86PX0JDS7SpHMHasI3w9X//1q7Lu7nZtj3Zzg==", + "dev": true + }, + "@truffle/interface-adapter": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@truffle/interface-adapter/-/interface-adapter-0.3.3.tgz", + "integrity": "sha512-l3I4WFTfnBSIfG96IOBRtAIE6AHDAxcOUJE7W5zh9hocQwzQlGWc2yEyyTcLa0656TTM8RxaZZ2S/KdHHMvCaw==", + "dev": true, + "requires": { + "bn.js": "^4.11.8", + "ethers": "^4.0.32", + "lodash": "^4.17.13", + "web3": "1.2.2" + }, + "dependencies": { + "@types/node": { + "version": "12.12.47", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.47.tgz", + "integrity": "sha512-yzBInQFhdY8kaZmqoL2+3U5dSTMrKaYcb561VU+lDzAYvqt+2lojvBEy+hmpSNuXnPTx7m9+04CzWYOUqWME2A==", + "dev": true + }, + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + }, + "web3": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.2.2.tgz", + "integrity": "sha512-/ChbmB6qZpfGx6eNpczt5YSUBHEA5V2+iUCbn85EVb3Zv6FVxrOo5Tv7Lw0gE2tW7EEjASbCyp3mZeiZaCCngg==", + "dev": true, + "requires": { + "@types/node": "^12.6.1", + "web3-bzz": "1.2.2", + "web3-core": "1.2.2", + "web3-eth": "1.2.2", + "web3-eth-personal": "1.2.2", + "web3-net": "1.2.2", + "web3-shh": "1.2.2", + "web3-utils": "1.2.2" + } + } + } + }, + "@truffle/provider": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@truffle/provider/-/provider-0.1.19.tgz", + "integrity": "sha512-ke8iQmzW4Y99+8iff8xQcc+mCNU4AkwtaZ/iSpmVD8qpLytw8/DSNCm0RiEz9/+I93Q1zqI4Jnij/rXnkS2Njw==", + "dev": true, + "requires": { + "@truffle/error": "^0.0.7", + "@truffle/interface-adapter": "^0.3.0", + "web3": "1.2.1" + }, + "dependencies": { + "@types/node": { + "version": "10.17.26", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.26.tgz", + "integrity": "sha512-myMwkO2Cr82kirHY8uknNRHEVtn0wV3DTQfkrjx17jmkstDRZ24gNUdl8AHXVyVclTYI/bNjgTPTAWvWLqXqkw==", + "dev": true + }, + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "dev": true + }, + "eth-lib": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.7.tgz", + "integrity": "sha1-L5Pxex4jrsN1nNSj/iDBKGo/wco=", + "dev": true, + "requires": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + } + }, + "ethers": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.0-beta.3.tgz", + "integrity": "sha512-YYPogooSknTwvHg3+Mv71gM/3Wcrx+ZpCzarBj3mqs9njjRkrOo2/eufzhHloOCo3JSoNI4TQJJ6yU5ABm3Uog==", + "dev": true, + "requires": { + "@types/node": "^10.3.2", + "aes-js": "3.0.0", + "bn.js": "^4.4.0", + "elliptic": "6.3.3", + "hash.js": "1.1.3", + "js-sha3": "0.5.7", + "scrypt-js": "2.0.3", + "setimmediate": "1.0.4", + "uuid": "2.0.1", + "xmlhttprequest": "1.8.0" + }, + "dependencies": { + "elliptic": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.3.3.tgz", + "integrity": "sha1-VILZZG1UvLif19mU/J4ulWiHbj8=", + "dev": true, + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "inherits": "^2.0.1" + } + } + } + }, + "hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.0" + } + }, + "scrypt-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.3.tgz", + "integrity": "sha1-uwBAvgMEPamgEqLOqfyfhSz8h9Q=", + "dev": true + }, + "semver": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.2.0.tgz", + "integrity": "sha512-jdFC1VdUGT/2Scgbimf7FSx9iJLXoqfglSF+gJeuNWVpiE37OIbc1jywR/GJyFdz3mnkz2/id0L0J/cr0izR5A==", + "dev": true + }, + "web3": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.2.1.tgz", + "integrity": "sha512-nNMzeCK0agb5i/oTWNdQ1aGtwYfXzHottFP2Dz0oGIzavPMGSKyVlr8ibVb1yK5sJBjrWVnTdGaOC2zKDFuFRw==", + "dev": true, + "requires": { + "web3-bzz": "1.2.1", + "web3-core": "1.2.1", + "web3-eth": "1.2.1", + "web3-eth-personal": "1.2.1", + "web3-net": "1.2.1", + "web3-shh": "1.2.1", + "web3-utils": "1.2.1" + } + }, + "web3-bzz": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.2.1.tgz", + "integrity": "sha512-LdOO44TuYbGIPfL4ilkuS89GQovxUpmLz6C1UC7VYVVRILeZS740FVB3j9V4P4FHUk1RenaDfKhcntqgVCHtjw==", + "dev": true, + "requires": { + "got": "9.6.0", + "swarm-js": "0.1.39", + "underscore": "1.9.1" + } + }, + "web3-core": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.2.1.tgz", + "integrity": "sha512-5ODwIqgl8oIg/0+Ai4jsLxkKFWJYE0uLuE1yUKHNVCL4zL6n3rFjRMpKPokd6id6nJCNgeA64KdWQ4XfpnjdMg==", + "dev": true, + "requires": { + "web3-core-helpers": "1.2.1", + "web3-core-method": "1.2.1", + "web3-core-requestmanager": "1.2.1", + "web3-utils": "1.2.1" + } + }, + "web3-core-helpers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.1.tgz", + "integrity": "sha512-Gx3sTEajD5r96bJgfuW377PZVFmXIH4TdqDhgGwd2lZQCcMi+DA4TgxJNJGxn0R3aUVzyyE76j4LBrh412mXrw==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-eth-iban": "1.2.1", + "web3-utils": "1.2.1" + } + }, + "web3-core-method": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.2.1.tgz", + "integrity": "sha512-Ghg2WS23qi6Xj8Od3VCzaImLHseEA7/usvnOItluiIc5cKs00WYWsNy2YRStzU9a2+z8lwQywPYp0nTzR/QXdQ==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-core-helpers": "1.2.1", + "web3-core-promievent": "1.2.1", + "web3-core-subscriptions": "1.2.1", + "web3-utils": "1.2.1" + } + }, + "web3-core-promievent": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.2.1.tgz", + "integrity": "sha512-IVUqgpIKoeOYblwpex4Hye6npM0aMR+kU49VP06secPeN0rHMyhGF0ZGveWBrGvf8WDPI7jhqPBFIC6Jf3Q3zw==", + "dev": true, + "requires": { + "any-promise": "1.3.0", + "eventemitter3": "3.1.2" + } + }, + "web3-core-requestmanager": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.2.1.tgz", + "integrity": "sha512-xfknTC69RfYmLKC+83Jz73IC3/sS2ZLhGtX33D4Q5nQ8yc39ElyAolxr9sJQS8kihOcM6u4J+8gyGMqsLcpIBg==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-core-helpers": "1.2.1", + "web3-providers-http": "1.2.1", + "web3-providers-ipc": "1.2.1", + "web3-providers-ws": "1.2.1" + } + }, + "web3-core-subscriptions": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.2.1.tgz", + "integrity": "sha512-nmOwe3NsB8V8UFsY1r+sW6KjdOS68h8nuh7NzlWxBQT/19QSUGiERRTaZXWu5BYvo1EoZRMxCKyCQpSSXLc08g==", + "dev": true, + "requires": { + "eventemitter3": "3.1.2", + "underscore": "1.9.1", + "web3-core-helpers": "1.2.1" + } + }, + "web3-eth": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.2.1.tgz", + "integrity": "sha512-/2xly4Yry5FW1i+uygPjhfvgUP/MS/Dk+PDqmzp5M88tS86A+j8BzKc23GrlA8sgGs0645cpZK/999LpEF5UdA==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-core": "1.2.1", + "web3-core-helpers": "1.2.1", + "web3-core-method": "1.2.1", + "web3-core-subscriptions": "1.2.1", + "web3-eth-abi": "1.2.1", + "web3-eth-accounts": "1.2.1", + "web3-eth-contract": "1.2.1", + "web3-eth-ens": "1.2.1", + "web3-eth-iban": "1.2.1", + "web3-eth-personal": "1.2.1", + "web3-net": "1.2.1", + "web3-utils": "1.2.1" + } + }, + "web3-eth-abi": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.2.1.tgz", + "integrity": "sha512-jI/KhU2a/DQPZXHjo2GW0myEljzfiKOn+h1qxK1+Y9OQfTcBMxrQJyH5AP89O6l6NZ1QvNdq99ThAxBFoy5L+g==", + "dev": true, + "requires": { + "ethers": "4.0.0-beta.3", + "underscore": "1.9.1", + "web3-utils": "1.2.1" + } + }, + "web3-eth-accounts": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.2.1.tgz", + "integrity": "sha512-26I4qq42STQ8IeKUyur3MdQ1NzrzCqPsmzqpux0j6X/XBD7EjZ+Cs0lhGNkSKH5dI3V8CJasnQ5T1mNKeWB7nQ==", + "dev": true, + "requires": { + "any-promise": "1.3.0", + "crypto-browserify": "3.12.0", + "eth-lib": "0.2.7", + "scryptsy": "2.1.0", + "semver": "6.2.0", + "underscore": "1.9.1", + "uuid": "3.3.2", + "web3-core": "1.2.1", + "web3-core-helpers": "1.2.1", + "web3-core-method": "1.2.1", + "web3-utils": "1.2.1" + }, + "dependencies": { + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true + } + } + }, + "web3-eth-contract": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.2.1.tgz", + "integrity": "sha512-kYFESbQ3boC9bl2rYVghj7O8UKMiuKaiMkxvRH5cEDHil8V7MGEGZNH0slSdoyeftZVlaWSMqkRP/chfnKND0g==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-core": "1.2.1", + "web3-core-helpers": "1.2.1", + "web3-core-method": "1.2.1", + "web3-core-promievent": "1.2.1", + "web3-core-subscriptions": "1.2.1", + "web3-eth-abi": "1.2.1", + "web3-utils": "1.2.1" + } + }, + "web3-eth-ens": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.2.1.tgz", + "integrity": "sha512-lhP1kFhqZr2nnbu3CGIFFrAnNxk2veXpOXBY48Tub37RtobDyHijHgrj+xTh+mFiPokyrapVjpFsbGa+Xzye4Q==", + "dev": true, + "requires": { + "eth-ens-namehash": "2.0.8", + "underscore": "1.9.1", + "web3-core": "1.2.1", + "web3-core-helpers": "1.2.1", + "web3-core-promievent": "1.2.1", + "web3-eth-abi": "1.2.1", + "web3-eth-contract": "1.2.1", + "web3-utils": "1.2.1" + } + }, + "web3-eth-iban": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.2.1.tgz", + "integrity": "sha512-9gkr4QPl1jCU+wkgmZ8EwODVO3ovVj6d6JKMos52ggdT2YCmlfvFVF6wlGLwi0VvNa/p+0BjJzaqxnnG/JewjQ==", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "web3-utils": "1.2.1" + } + }, + "web3-eth-personal": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.2.1.tgz", + "integrity": "sha512-RNDVSiaSoY4aIp8+Hc7z+X72H7lMb3fmAChuSBADoEc7DsJrY/d0R5qQDK9g9t2BO8oxgLrLNyBP/9ub2Hc6Bg==", + "dev": true, + "requires": { + "web3-core": "1.2.1", + "web3-core-helpers": "1.2.1", + "web3-core-method": "1.2.1", + "web3-net": "1.2.1", + "web3-utils": "1.2.1" + } + }, + "web3-net": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.2.1.tgz", + "integrity": "sha512-Yt1Bs7WgnLESPe0rri/ZoPWzSy55ovioaP35w1KZydrNtQ5Yq4WcrAdhBzcOW7vAkIwrsLQsvA+hrOCy7mNauw==", + "dev": true, + "requires": { + "web3-core": "1.2.1", + "web3-core-method": "1.2.1", + "web3-utils": "1.2.1" + } + }, + "web3-providers-http": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.2.1.tgz", + "integrity": "sha512-BDtVUVolT9b3CAzeGVA/np1hhn7RPUZ6YYGB/sYky+GjeO311Yoq8SRDUSezU92x8yImSC2B+SMReGhd1zL+bQ==", + "dev": true, + "requires": { + "web3-core-helpers": "1.2.1", + "xhr2-cookies": "1.1.0" + } + }, + "web3-providers-ipc": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.2.1.tgz", + "integrity": "sha512-oPEuOCwxVx8L4CPD0TUdnlOUZwGBSRKScCz/Ws2YHdr9Ium+whm+0NLmOZjkjQp5wovQbyBzNa6zJz1noFRvFA==", + "dev": true, + "requires": { + "oboe": "2.1.4", + "underscore": "1.9.1", + "web3-core-helpers": "1.2.1" + } + }, + "web3-providers-ws": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.2.1.tgz", + "integrity": "sha512-oqsQXzu+ejJACVHy864WwIyw+oB21nw/pI65/sD95Zi98+/HQzFfNcIFneF1NC4bVF3VNX4YHTNq2I2o97LAiA==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-core-helpers": "1.2.1", + "websocket": "github:web3-js/WebSocket-Node#polyfill/globalThis" + } + }, + "web3-shh": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.2.1.tgz", + "integrity": "sha512-/3Cl04nza5kuFn25bV3FJWa0s3Vafr5BlT933h26xovQ6HIIz61LmvNQlvX1AhFL+SNJOTcQmK1SM59vcyC8bA==", + "dev": true, + "requires": { + "web3-core": "1.2.1", + "web3-core-method": "1.2.1", + "web3-core-subscriptions": "1.2.1", + "web3-net": "1.2.1" + } + }, + "web3-utils": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.2.1.tgz", + "integrity": "sha512-Mrcn3l58L+yCKz3zBryM6JZpNruWuT0OCbag8w+reeNROSGVlXzUQkU+gtAwc9JCZ7tKUyg67+2YUGqUjVcyBA==", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "eth-lib": "0.2.7", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randomhex": "0.1.5", + "underscore": "1.9.1", + "utf8": "3.0.0" + } + } + } + }, + "@types/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", + "requires": { + "@types/node": "*" + } + }, + "@types/chai": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.11.tgz", + "integrity": "sha512-t7uW6eFafjO+qJ3BIV2gGUyZs27egcNRkUdalkud+Qa3+kg//f129iuOFivHDXQ+vnU3fDXuwgv0cqMCbcE8sw==" + }, + "@types/es6-promisify": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@types/es6-promisify/-/es6-promisify-6.0.0.tgz", + "integrity": "sha512-w3eB2FfE60gHeUTWT65G/FsTlqOAl8qZeyDGxAniF4oS7T6acQ7uvtGKQlCIQNOGh6r21A/3mBASNzy8Tbx+hg==" + }, + "@types/glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-VgNIkxK+j7Nz5P7jvUZlRvhuPSmsEfS03b0alKcq5V/STUKAa3Plemsn5mrQUO7am6OErJ4rhGEGJbACclrtRA==", + "dev": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, + "@types/mocha": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-7.0.2.tgz", + "integrity": "sha512-ZvO2tAcjmMi8V/5Z3JsyofMe3hasRcaw88cto5etSVMwVQfeivGAlEYmaQgceUSVYFofVjT+ioHsATjdWcFt1w==" + }, + "@types/node": { + "version": "14.0.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.10.tgz", + "integrity": "sha512-Bz23oN/5bi0rniKT24ExLf4cK0JdvN3dH/3k0whYkdN4eI4vS2ZW/2ENNn2uxHCzWcbdHIa/GRuWQytfzCjRYw==" + }, + "@web3-js/scrypt-shim": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@web3-js/scrypt-shim/-/scrypt-shim-0.1.0.tgz", + "integrity": "sha512-ZtZeWCc/s0nMcdx/+rZwY1EcuRdemOK9ag21ty9UsHkFxsNb/AaoucUz0iPuyGe0Ku+PFuRmWZG7Z7462p9xPw==", + "dev": true, + "requires": { + "scryptsy": "^2.1.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@web3-js/websocket": { + "version": "1.0.30", + "resolved": "https://registry.npmjs.org/@web3-js/websocket/-/websocket-1.0.30.tgz", + "integrity": "sha512-fDwrD47MiDrzcJdSeTLF75aCcxVVt8B1N74rA+vh2XCAvFy4tEWJjtnUtj2QG7/zlQ6g9cQ88bZFBxwd9/FmtA==", + "dev": true, + "requires": { + "debug": "^2.2.0", + "es5-ext": "^0.10.50", + "nan": "^2.14.0", + "typedarray-to-buffer": "^3.1.5", + "yaeti": "^0.0.6" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "abbrev": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", + "dev": true + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "address": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.1.2.tgz", + "integrity": "sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA==", + "dev": true + }, + "aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0=" + }, + "ajv": { + "version": "6.12.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", + "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true, + "optional": true + }, + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==" + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" + }, + "anymatch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "optional": true, + "requires": { + "micromatch": "^2.1.5", + "normalize-path": "^2.0.0" + }, + "dependencies": { + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "optional": true, + "requires": { + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" + } + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "optional": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "optional": true, + "requires": { + "is-extglob": "^1.0.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "optional": true, + "requires": { + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" + } + } + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "optional": true, + "requires": { + "arr-flatten": "^1.0.1" + } + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "optional": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "optional": true + }, + "array-filter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-1.0.0.tgz", + "integrity": "sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=" + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "optional": true + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } + } + }, + "assert": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-2.0.0.tgz", + "integrity": "sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A==", + "requires": { + "es6-object-assign": "^1.1.0", + "is-nan": "^1.2.1", + "object-is": "^1.0.1", + "util": "^0.12.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==" + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "optional": true + }, + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "optional": true + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "optional": true + }, + "available-typed-arrays": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz", + "integrity": "sha512-XWX3OX8Onv97LMk/ftVyBibpGwY5a8SmuxZPzeOxqmuEqUCOM9ZE+uIaD1VNJ5QnvU2UQusvmKbuM1FR8QWGfQ==", + "requires": { + "array-filter": "^1.0.0" + } + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.0.tgz", + "integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA==" + }, + "babel-cli": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-cli/-/babel-cli-6.26.0.tgz", + "integrity": "sha1-UCq1SHTX24itALiHoGODzgPQAvE=", + "requires": { + "babel-core": "^6.26.0", + "babel-polyfill": "^6.26.0", + "babel-register": "^6.26.0", + "babel-runtime": "^6.26.0", + "chokidar": "^1.6.1", + "commander": "^2.11.0", + "convert-source-map": "^1.5.0", + "fs-readdir-recursive": "^1.0.0", + "glob": "^7.1.2", + "lodash": "^4.17.4", + "output-file-sync": "^1.1.2", + "path-is-absolute": "^1.0.1", + "slash": "^1.0.0", + "source-map": "^0.5.6", + "v8flags": "^2.1.1" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } + } + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + } + } + }, + "babel-core": { + "version": "6.26.3", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", + "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", + "requires": { + "babel-code-frame": "^6.26.0", + "babel-generator": "^6.26.0", + "babel-helpers": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-register": "^6.26.0", + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "convert-source-map": "^1.5.1", + "debug": "^2.6.9", + "json5": "^0.5.1", + "lodash": "^4.17.4", + "minimatch": "^3.0.4", + "path-is-absolute": "^1.0.1", + "private": "^0.1.8", + "slash": "^1.0.0", + "source-map": "^0.5.7" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } + } + }, + "babel-eslint": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", + "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.0", + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0", + "eslint-visitor-keys": "^1.0.0", + "resolve": "^1.12.0" + }, + "dependencies": { + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "requires": { + "path-parse": "^1.0.6" + } + } + } + }, + "babel-generator": { + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", + "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", + "requires": { + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "detect-indent": "^4.0.0", + "jsesc": "^1.3.0", + "lodash": "^4.17.4", + "source-map": "^0.5.7", + "trim-right": "^1.0.1" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } + } + }, + "babel-helpers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", + "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-polyfill": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz", + "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=", + "requires": { + "babel-runtime": "^6.26.0", + "core-js": "^2.5.0", + "regenerator-runtime": "^0.10.5" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", + "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=" + } + } + }, + "babel-register": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", + "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", + "requires": { + "babel-core": "^6.26.0", + "babel-runtime": "^6.26.0", + "core-js": "^2.5.0", + "home-or-tmp": "^2.0.0", + "lodash": "^4.17.4", + "mkdirp": "^0.5.1", + "source-map-support": "^0.4.15" + }, + "dependencies": { + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + } + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "requires": { + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" + } + }, + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "requires": { + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "requires": { + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "optional": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "optional": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "optional": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "optional": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "optional": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "optional": true + } + } + }, + "base-x": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.8.tgz", + "integrity": "sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "bignumber.js": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "optional": true + }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "bip66": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/bip66/-/bip66-1.1.5.tgz", + "integrity": "sha1-AfqHSHhcpwlV1QESF9GzE5lpyiI=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "bl": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", + "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", + "requires": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + } + } + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "bn.js": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.2.tgz", + "integrity": "sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA==" + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "requires": { + "bn.js": "^4.1.0", + "randombytes": "^2.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } + } + }, + "browserify-sign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.0.tgz", + "integrity": "sha512-hEZC1KEeYuoHRqhGhTy6gWrpJA3ZDjFWv0DE61643ZnOXAKJb3u7yWcrU0mMc9SwAqK1n7myPGndkp0dFG7NFA==", + "requires": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.2", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + } + }, + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "requires": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" + }, + "buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=" + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "buffer-to-arraybuffer": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz", + "integrity": "sha1-YGSkD6dutDxyOrqe+PbhIW0QURo=" + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "optional": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "optional": true + } + } + }, + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "dependencies": { + "get-stream": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" + } + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "chai": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", + "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.0", + "type-detect": "^4.0.5" + } + }, + "chai-bignumber": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chai-bignumber/-/chai-bignumber-3.0.0.tgz", + "integrity": "sha512-SubOtaSI2AILWTWe2j0c6i2yFT/f9J6UBjeVGDuwDiPLkF/U5+/eTWUE3sbCZ1KgcPF6UJsDVYbIxaYA097MQA==" + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + } + } + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=" + }, + "chokidar": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "optional": true, + "requires": { + "anymatch": "^1.3.0", + "async-each": "^1.0.0", + "fsevents": "^1.0.0", + "glob-parent": "^2.0.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^2.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0" + }, + "dependencies": { + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "optional": true, + "requires": { + "is-glob": "^2.0.0" + } + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "optional": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "optional": true, + "requires": { + "is-extglob": "^1.0.0" + } + } + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "cids": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/cids/-/cids-0.7.5.tgz", + "integrity": "sha512-zT7mPeghoWAu+ppn8+BS1tQ5qGmbMfB4AregnQjA/qHY3GC1m1ptI9GkWNlgeu38r7CuRdXB47uY2XgAYt6QVA==", + "requires": { + "buffer": "^5.5.0", + "class-is": "^1.1.0", + "multibase": "~0.6.0", + "multicodec": "^1.0.0", + "multihashes": "~0.4.15" + }, + "dependencies": { + "multicodec": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-1.0.1.tgz", + "integrity": "sha512-yrrU/K8zHyAH2B0slNVeq3AiwluflHpgQ3TAzwNJcuO2AoPyXgBT2EDkdbP1D8B/yFOY+S2hDYmFlI1vhVFkQw==", + "requires": { + "buffer": "^5.5.0", + "varint": "^5.0.0" + } + } + } + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "class-is": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/class-is/-/class-is-1.1.0.tgz", + "integrity": "sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw==" + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "optional": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "optional": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "optional": true + } + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "requires": { + "mimic-response": "^1.0.0" + } + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "optional": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", + "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", + "requires": { + "graceful-readlink": ">= 1.0.0" + } + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "requires": { + "safe-buffer": "5.1.2" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "content-hash": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/content-hash/-/content-hash-2.5.2.tgz", + "integrity": "sha512-FvIQKy0S1JaWV10sMsA7TRx8bpU+pqPkhbsfvOJAdjRXvYxEckAwQWGwtRjiaJfh+E0DvcWUGqcdjwMGFjsSdw==", + "requires": { + "cids": "^0.7.1", + "multicodec": "^0.5.5", + "multihashes": "^0.4.15" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "requires": { + "safe-buffer": "~5.1.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==" + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "optional": true + }, + "core-js": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", + "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, + "create-ecdh": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", + "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "death": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/death/-/death-1.1.0.tgz", + "integrity": "sha1-AaqcQB7dknUFFEcLgmY5DGbGcxg=", + "dev": true + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" + }, + "decompress": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.1.tgz", + "integrity": "sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ==", + "requires": { + "decompress-tar": "^4.0.0", + "decompress-tarbz2": "^4.0.0", + "decompress-targz": "^4.0.0", + "decompress-unzip": "^4.0.1", + "graceful-fs": "^4.1.10", + "make-dir": "^1.0.0", + "pify": "^2.3.0", + "strip-dirs": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } + } + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "requires": { + "mimic-response": "^1.0.0" + } + }, + "decompress-tar": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", + "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", + "requires": { + "file-type": "^5.2.0", + "is-stream": "^1.1.0", + "tar-stream": "^1.5.2" + } + }, + "decompress-tarbz2": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", + "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", + "requires": { + "decompress-tar": "^4.1.0", + "file-type": "^6.1.0", + "is-stream": "^1.1.0", + "seek-bzip": "^1.0.5", + "unbzip2-stream": "^1.0.9" + }, + "dependencies": { + "file-type": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", + "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==" + } + } + }, + "decompress-targz": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", + "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", + "requires": { + "decompress-tar": "^4.1.1", + "file-type": "^5.2.0", + "is-stream": "^1.1.0" + } + }, + "decompress-unzip": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", + "integrity": "sha1-3qrM39FK6vhVePczroIQ+bSEj2k=", + "requires": { + "file-type": "^3.8.0", + "get-stream": "^2.2.0", + "pify": "^2.3.0", + "yauzl": "^2.4.2" + }, + "dependencies": { + "file-type": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", + "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=" + }, + "get-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", + "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=", + "requires": { + "object-assign": "^4.0.1", + "pinkie-promise": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } + } + }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "requires": { + "type-detect": "^4.0.0" + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "optional": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "optional": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "optional": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "optional": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "optional": true + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "requires": { + "repeating": "^2.0.0" + } + }, + "detect-port": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.3.0.tgz", + "integrity": "sha512-E+B1gzkl2gqxt1IhUzwjrxBKRqx1UzC3WLONHinn8S3T6lwV/agVCyitiFOsGJ/eYuEUBvD71MZHy3Pv1G9doQ==", + "dev": true, + "requires": { + "address": "^1.0.1", + "debug": "^2.6.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } + } + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "dir-to-object": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dir-to-object/-/dir-to-object-2.0.0.tgz", + "integrity": "sha512-sXs0JKIhymON7T1UZuO2Ud6VTNAx/VTBXIl4+3mjb2RgfOpt+hectX0x04YqPOPdkeOAKoJuKqwqnXXURNPNEA==", + "dev": true + }, + "dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" + }, + "dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" + }, + "dotenv-flow": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/dotenv-flow/-/dotenv-flow-3.1.0.tgz", + "integrity": "sha512-BMA8vfu2DbAx5x5G3C+tgb1hCbONggZTSpBE7B4yCPG5vziKX/lA3CzsjdGKlPvLxZgTbP1qb+KlWux8pYqsmA==", + "requires": { + "dotenv": "^8.0.0" + } + }, + "drbg.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/drbg.js/-/drbg.js-1.0.1.tgz", + "integrity": "sha1-Pja2xCs3BDgjzbwzLVjzHiRFSAs=", + "requires": { + "browserify-aes": "^1.0.6", + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4" + } + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "elliptic": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz", + "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==", + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } + } + }, + "emoji-regex": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.0.0.tgz", + "integrity": "sha512-6p1NII1Vm62wni/VR/cUMauVQoxmLVb9csqQlvLz+hO2gk8U2UYDfXHQSUYIBKmZwAKz867IDqG7B+u0mj+M6w==", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es5-ext": { + "version": "0.10.53", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", + "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "requires": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.3", + "next-tick": "~1.0.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-object-assign": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", + "integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=" + }, + "es6-promisify": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-6.1.1.tgz", + "integrity": "sha512-HBL8I3mIki5C1Cc9QjKUenHtnG0A5/xA8Q/AllRcfiwl2CZFXGK7ddBiCoRwAix4i2KxcQfjtIVcrVbB3vbmwg==" + }, + "es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "requires": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "escodegen": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", + "dev": true, + "requires": { + "esprima": "^2.7.1", + "estraverse": "^1.9.1", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.2.0" + }, + "dependencies": { + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.2.0.tgz", + "integrity": "sha512-WFb4ihckKil6hu3Dp798xdzSfddwKKU3+nGniKF6HfeW6OLd2OUDEPP7TcHtB5+QXOKg2s6B2DaMPE1Nn/kxKQ==" + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "esprima-extract-comments": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/esprima-extract-comments/-/esprima-extract-comments-1.1.0.tgz", + "integrity": "sha512-sBQUnvJwpeE9QnPrxh7dpI/dp67erYG4WXEAreAMoelPRpMR7NWb4YtwRPn9b+H1uLQKl/qS8WYmyaljTpjIsw==", + "dev": true, + "requires": { + "esprima": "^4.0.0" + } + }, + "estraverse": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "eth-ens-namehash": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz", + "integrity": "sha1-IprEbsqG1S4MmR58sq74P/D2i88=", + "requires": { + "idna-uts46-hx": "^2.3.1", + "js-sha3": "^0.5.7" + } + }, + "eth-lib": { + "version": "0.1.29", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.1.29.tgz", + "integrity": "sha512-bfttrr3/7gG4E02HoWTDUcDDslN003OlOoBxk9virpAZQ1ja/jDgwkWB8QfJF7ojuEowrqy+lzp9VcJG7/k5bQ==", + "requires": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "nano-json-stream-parser": "^0.1.2", + "servify": "^0.1.12", + "ws": "^3.0.0", + "xhr-request-promise": "^0.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } + } + }, + "ethereum-bloom-filters": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.7.tgz", + "integrity": "sha512-cDcJJSJ9GMAcURiAWO3DxIEhTL/uWqlQnvgKpuYQzYPrt/izuGU+1ntQmHt0IRq6ADoSYHFnB+aCEFIldjhkMQ==", + "requires": { + "js-sha3": "^0.8.0" + }, + "dependencies": { + "js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" + } + } + }, + "ethereumjs-common": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ethereumjs-common/-/ethereumjs-common-1.5.1.tgz", + "integrity": "sha512-aVUPRLgmXORGXXEVkFYgPhr9TGtpBY2tGhZ9Uh0A3lIUzUDr1x6kQx33SbjPUkLkX3eniPQnIL/2psjkjrOfcQ==" + }, + "ethereumjs-tx": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-2.1.2.tgz", + "integrity": "sha512-zZEK1onCeiORb0wyCXUvg94Ve5It/K6GD1K+26KfFKodiBiS6d9lfCXlUKGBBdQ+bv7Day+JK0tj1K+BeNFRAw==", + "requires": { + "ethereumjs-common": "^1.5.0", + "ethereumjs-util": "^6.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + }, + "ethereumjs-util": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.0.tgz", + "integrity": "sha512-vb0XN9J2QGdZGIEKG2vXM+kUdEivUfU6Wmi5y0cg+LRhDYKnXIZ/Lz7XjFbHRR9VIKq2lVGLzGBkA++y2nOdOQ==", + "requires": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "ethjs-util": "0.1.6", + "keccak": "^2.0.0", + "rlp": "^2.2.3", + "secp256k1": "^3.0.1" + } + }, + "keccak": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-2.1.0.tgz", + "integrity": "sha512-m1wbJRTo+gWbctZWay9i26v5fFnYkOn7D5PCxJ3fZUGUEb49dE1Pm4BREUYCt/aoO6di7jeoGmhvqN9Nzylm3Q==", + "requires": { + "bindings": "^1.5.0", + "inherits": "^2.0.4", + "nan": "^2.14.0", + "safe-buffer": "^5.2.0" + } + }, + "secp256k1": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-3.8.0.tgz", + "integrity": "sha512-k5ke5avRZbtl9Tqx/SA7CbY3NF6Ro+Sj9cZxezFzuBlLDmyqPiL8hJJ+EmzD8Ig4LUDByHJ3/iPOVoRixs/hmw==", + "requires": { + "bindings": "^1.5.0", + "bip66": "^1.1.5", + "bn.js": "^4.11.8", + "create-hash": "^1.2.0", + "drbg.js": "^1.0.1", + "elliptic": "^6.5.2", + "nan": "^2.14.0", + "safe-buffer": "^5.1.2" + } + } + } + }, + "ethereumjs-util": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.0.2.tgz", + "integrity": "sha512-ATAP02eJLpAlWGfiKQddNrRfZpwXiTFhRN2EM/yLXMCdBW/xjKYblNKcx8GLzzrjXg0ymotck+lam1nuV90arQ==", + "requires": { + "@types/bn.js": "^4.11.3", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethjs-util": "0.1.6", + "keccak": "^3.0.0", + "rlp": "^2.2.4", + "secp256k1": "^4.0.1" + } + }, + "ethers": { + "version": "4.0.47", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.47.tgz", + "integrity": "sha512-hssRYhngV4hiDNeZmVU/k5/E8xmLG8UpcNUzg6mb7lqhgpFPH/t7nuv20RjRrEf0gblzvi2XwR5Te+V3ZFc9pQ==", + "dev": true, + "requires": { + "aes-js": "3.0.0", + "bn.js": "^4.4.0", + "elliptic": "6.5.2", + "hash.js": "1.1.3", + "js-sha3": "0.5.7", + "scrypt-js": "2.0.4", + "setimmediate": "1.0.4", + "uuid": "2.0.1", + "xmlhttprequest": "1.8.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + }, + "hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.0" + } + } + } + }, + "ethjs-unit": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", + "integrity": "sha1-xmWSHkduh7ziqdWIpv4EBbLEFpk=", + "requires": { + "bn.js": "4.11.6", + "number-to-bn": "1.7.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=" + } + } + }, + "ethjs-util": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", + "requires": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + } + }, + "eventemitter3": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", + "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==" + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "optional": true, + "requires": { + "is-posix-bracket": "^0.1.0" + } + }, + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "optional": true, + "requires": { + "fill-range": "^2.1.0" + }, + "dependencies": { + "fill-range": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", + "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "optional": true, + "requires": { + "is-number": "^2.1.0", + "isobject": "^2.0.0", + "randomatic": "^3.0.0", + "repeat-element": "^1.1.2", + "repeat-string": "^1.5.2" + } + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "optional": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "ext": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", + "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", + "requires": { + "type": "^2.0.0" + }, + "dependencies": { + "type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz", + "integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==" + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "optional": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "optional": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "optional": true, + "requires": { + "is-extglob": "^1.0.0" + }, + "dependencies": { + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "optional": true + } + } + }, + "extract-comments": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/extract-comments/-/extract-comments-1.1.0.tgz", + "integrity": "sha512-dzbZV2AdSSVW/4E7Ti5hZdHWbA+Z80RJsJhr5uiL10oyjl/gy7/o+HI1HwK4/WSZhlq4SNKU3oUzXlM13Qx02Q==", + "dev": true, + "requires": { + "esprima-extract-comments": "^1.1.0", + "parse-code-context": "^1.0.0" + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fast-deep-equal": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", + "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==" + }, + "fast-glob": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.3.tgz", + "integrity": "sha512-fWSEEcoqcYqlFJrpSH5dJTwv6o0r+2bLAmnlne8OQMbFhpSTQXA8Ngp6q1DGA4B+eewHeuH5ndZeiV2qyXXNsA==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2", + "picomatch": "^2.2.1" + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fastq": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", + "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "requires": { + "pend": "~1.2.0" + } + }, + "file-type": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", + "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=" + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "optional": true + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "flat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", + "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", + "requires": { + "is-buffer": "~2.0.3" + }, + "dependencies": { + "is-buffer": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==" + } + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "optional": true + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "optional": true, + "requires": { + "for-in": "^1.0.1" + } + }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "optional": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "requires": { + "minipass": "^2.6.0" + } + }, + "fs-readdir-recursive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "ganache-cli": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/ganache-cli/-/ganache-cli-6.9.1.tgz", + "integrity": "sha512-VPBumkNUZzXDRQwVOby5YyQpd5t1clkr06xMgB28lZdEIn5ht1GMwUskOTFOAxdkQ4J12IWP0gdeacVRGowqbA==", + "dev": true, + "requires": { + "ethereumjs-util": "6.1.0", + "source-map-support": "0.5.12", + "yargs": "13.2.4" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "bundled": true, + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "bundled": true, + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "bindings": { + "version": "1.5.0", + "bundled": true, + "dev": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "bip66": { + "version": "1.1.5", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "bn.js": { + "version": "4.11.8", + "bundled": true, + "dev": true + }, + "brorand": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "browserify-aes": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "buffer-from": { + "version": "1.1.1", + "bundled": true, + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "bundled": true, + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "bundled": true, + "dev": true + }, + "cipher-base": { + "version": "1.0.4", + "bundled": true, + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "cliui": { + "version": "5.0.0", + "bundled": true, + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "color-convert": { + "version": "1.9.3", + "bundled": true, + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "bundled": true, + "dev": true + }, + "create-hash": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "bundled": true, + "dev": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "cross-spawn": { + "version": "6.0.5", + "bundled": true, + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "decamelize": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "drbg.js": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "browserify-aes": "^1.0.6", + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4" + } + }, + "elliptic": { + "version": "6.5.0", + "bundled": true, + "dev": true, + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + } + }, + "emoji-regex": { + "version": "7.0.3", + "bundled": true, + "dev": true + }, + "end-of-stream": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "ethereumjs-util": { + "version": "6.1.0", + "bundled": true, + "dev": true, + "requires": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "ethjs-util": "0.1.6", + "keccak": "^1.0.2", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1", + "secp256k1": "^3.0.1" + } + }, + "ethjs-util": { + "version": "0.1.6", + "bundled": true, + "dev": true, + "requires": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + } + }, + "evp_bytestokey": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "execa": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "file-uri-to-path": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "find-up": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "get-caller-file": { + "version": "2.0.5", + "bundled": true, + "dev": true + }, + "get-stream": { + "version": "4.1.0", + "bundled": true, + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "hash-base": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "hash.js": { + "version": "1.1.7", + "bundled": true, + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "inherits": { + "version": "2.0.4", + "bundled": true, + "dev": true + }, + "invert-kv": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "is-hex-prefixed": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "isexe": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "keccak": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "bindings": "^1.2.1", + "inherits": "^2.0.3", + "nan": "^2.2.1", + "safe-buffer": "^5.1.0" + } + }, + "lcid": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "map-age-cleaner": { + "version": "0.1.3", + "bundled": true, + "dev": true, + "requires": { + "p-defer": "^1.0.0" + } + }, + "md5.js": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "mem": { + "version": "4.3.0", + "bundled": true, + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "minimalistic-assert": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "nan": { + "version": "2.14.0", + "bundled": true, + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "bundled": true, + "dev": true + }, + "npm-run-path": { + "version": "2.0.2", + "bundled": true, + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "os-locale": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "p-defer": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "p-finally": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "p-is-promise": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "p-limit": { + "version": "2.2.0", + "bundled": true, + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "bundled": true, + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "path-key": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "pump": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "require-directory": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "ripemd160": { + "version": "2.0.2", + "bundled": true, + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "rlp": { + "version": "2.2.3", + "bundled": true, + "dev": true, + "requires": { + "bn.js": "^4.11.1", + "safe-buffer": "^5.1.1" + } + }, + "safe-buffer": { + "version": "5.2.0", + "bundled": true, + "dev": true + }, + "secp256k1": { + "version": "3.7.1", + "bundled": true, + "dev": true, + "requires": { + "bindings": "^1.5.0", + "bip66": "^1.1.5", + "bn.js": "^4.11.8", + "create-hash": "^1.2.0", + "drbg.js": "^1.0.1", + "elliptic": "^6.4.1", + "nan": "^2.14.0", + "safe-buffer": "^5.1.2" + } + }, + "semver": { + "version": "5.7.0", + "bundled": true, + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "bundled": true, + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shebang-command": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true + }, + "source-map": { + "version": "0.6.1", + "bundled": true, + "dev": true + }, + "source-map-support": { + "version": "0.5.12", + "bundled": true, + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "string-width": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "strip-eof": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "strip-hex-prefix": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-hex-prefixed": "1.0.0" + } + }, + "which": { + "version": "1.3.1", + "bundled": true, + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "wrap-ansi": { + "version": "5.1.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "y18n": { + "version": "4.0.0", + "bundled": true, + "dev": true + }, + "yargs": { + "version": "13.2.4", + "bundled": true, + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "os-locale": "^3.1.0", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.0" + } + }, + "yargs-parser": { + "version": "13.1.1", + "bundled": true, + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=" + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "requires": { + "pump": "^3.0.0" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "optional": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "ghost-testrpc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/ghost-testrpc/-/ghost-testrpc-0.0.2.tgz", + "integrity": "sha512-i08dAEgJ2g8z5buJIrCTduwPIhih3DP+hOCTyyryikfV8T0bNvHnGXO67i0DD1H4GBDETTclPy9njZbfluQYrQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "node-emoji": "^1.10.0" + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "optional": true, + "requires": { + "glob-parent": "^2.0.0", + "is-glob": "^2.0.0" + }, + "dependencies": { + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "optional": true, + "requires": { + "is-glob": "^2.0.0" + } + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "optional": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "optional": true, + "requires": { + "is-extglob": "^1.0.0" + } + } + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "requires": { + "is-glob": "^4.0.1" + } + }, + "global": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz", + "integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=", + "requires": { + "min-document": "^2.19.0", + "process": "~0.5.1" + } + }, + "global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "requires": { + "global-prefix": "^3.0.0" + } + }, + "global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "requires": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==" + }, + "globby": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz", + "integrity": "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" + } + }, + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "requires": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" + }, + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==" + }, + "handlebars": { + "version": "4.7.6", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz", + "integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==", + "dev": true, + "requires": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + } + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "has-symbol-support-x": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", + "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==" + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" + }, + "has-to-string-tag-x": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", + "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", + "requires": { + "has-symbol-support-x": "^1.4.1" + } + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "optional": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "optional": true + } + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "optional": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "optional": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "home-or-tmp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", + "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.1" + } + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + } + } + }, + "http-https": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", + "integrity": "sha1-L5CN1fHbQGjAWM1ubUzjkskTOJs=" + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "idna-uts46-hx": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz", + "integrity": "sha512-PWoF9Keq6laYdIRwwCdhTPl60xRqAloYNMQLiyUnG42VjT53oW07BXIRM+NK7eQjzXjAk2gUvX9caRxlnF9TAA==", + "requires": { + "punycode": "2.1.0" + }, + "dependencies": { + "punycode": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz", + "integrity": "sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0=" + } + } + }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "requires": { + "loose-envify": "^1.0.0" + } + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "optional": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-arguments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", + "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==" + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "optional": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "optional": true + }, + "is-callable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", + "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==" + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "optional": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "optional": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "optional": true + } + } + }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", + "optional": true + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "optional": true, + "requires": { + "is-primitive": "^2.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "optional": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-finite": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", + "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==" + }, + "is-generator-function": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.7.tgz", + "integrity": "sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw==" + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-hex-prefixed": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", + "integrity": "sha1-fY035q135dEnFIkTxXPggtd39VQ=" + }, + "is-nan": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.0.tgz", + "integrity": "sha512-z7bbREymOqt2CCaZVly8aC4ML3Xhfi0ekuOnjO2L8vKdl+CttdVoGZQhd4adMFAsxQ5VeRVwORs4tU8RH+HFtQ==", + "requires": { + "define-properties": "^1.1.3" + } + }, + "is-natural-number": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", + "integrity": "sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=" + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "is-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", + "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=" + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=" + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "optional": true, + "requires": { + "isobject": "^3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "optional": true + } + } + }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", + "optional": true + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", + "optional": true + }, + "is-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", + "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-retry-allowed": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", + "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==" + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-typed-array": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.3.tgz", + "integrity": "sha512-BSYUBOK/HJibQ30wWkWold5txYwMUXQct9YHAQJr8fSwvZoiglcqB0pd7vEN23+Tsi9IUEjztdOSzl4qLVYGTQ==", + "requires": { + "available-typed-arrays": "^1.0.0", + "es-abstract": "^1.17.4", + "foreach": "^2.0.5", + "has-symbols": "^1.0.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "optional": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "optional": true, + "requires": { + "isarray": "1.0.0" + } + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "isurl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", + "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", + "requires": { + "has-to-string-tag-x": "^1.2.0", + "is-object": "^1.0.1" + } + }, + "js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc=" + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=" + }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsonschema": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.2.6.tgz", + "integrity": "sha512-SqhURKZG07JyKKeo/ir24QnS4/BV7a6gQy93bUSe4lUdNp0QNpIz2c9elWJQ9dpc5cQYY6cvCzgRwy0MQCLyqA==", + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "keccak": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.0.tgz", + "integrity": "sha512-/4h4FIfFEpTEuySXi/nVFM5rqSKPnnhI7cL4K3MFSwoI3VyM7AhPSq3SsysARtnEBEeIKMBUWD8cTh9nHE8AkA==", + "requires": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + } + }, + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "requires": { + "json-buffer": "3.0.0" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + }, + "lodash.toarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", + "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=", + "dev": true + }, + "log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "requires": { + "chalk": "^2.4.2" + } + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" + }, + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "requires": { + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + } + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "optional": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "optional": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "math-random": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", + "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==", + "optional": true + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" + }, + "mime-types": { + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "requires": { + "mime-db": "1.44.0" + } + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" + }, + "min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", + "requires": { + "dom-walk": "^0.1.0" + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "requires": { + "minipass": "^2.9.0" + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "optional": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "optional": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + }, + "mkdirp-promise": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz", + "integrity": "sha1-6bj2jlUsaKnBcTuEiD96HdA5uKE=", + "requires": { + "mkdirp": "*" + } + }, + "mocha": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.2.0.tgz", + "integrity": "sha512-O9CIypScywTVpNaRrCAgoUnJgozpIofjKUYmJhiCIJMiuYnLI6otcb1/kpW9/n/tJODHGZ7i8aLQoDVsMtOKQQ==", + "requires": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "chokidar": "3.3.0", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "3.0.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.5", + "ms": "2.1.1", + "node-environment-flags": "1.0.6", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.0" + }, + "dependencies": { + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "binary-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==" + }, + "chokidar": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "optional": true + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "requires": { + "picomatch": "^2.0.4" + } + }, + "supports-color": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "mock-fs": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.12.0.tgz", + "integrity": "sha512-/P/HtrlvBxY4o/PzXY9cCNBrdylDNxg7gnrv2sMNxj+UJ2m8jSpl0/A6fuJeNAWr99ZvGWH8XCbE0vmnM5KupQ==" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "multibase": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.6.1.tgz", + "integrity": "sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw==", + "requires": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + }, + "multicodec": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-0.5.7.tgz", + "integrity": "sha512-PscoRxm3f+88fAtELwUnZxGDkduE2HD9Q6GHUOywQLjOGT/HAdhjLDYNZ1e7VR0s0TP0EwZ16LNUTFpoBGivOA==", + "requires": { + "varint": "^5.0.0" + } + }, + "multihashes": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/multihashes/-/multihashes-0.4.19.tgz", + "integrity": "sha512-ej74GAfA20imjj00RO5h34aY3pGUFyzn9FJZFWwdeUHlHTkKmv90FrNpvYT4jYf1XXCy5O/5EjVnxTaESgOM6A==", + "requires": { + "buffer": "^5.5.0", + "multibase": "^0.7.0", + "varint": "^5.0.0" + }, + "dependencies": { + "multibase": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.7.0.tgz", + "integrity": "sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg==", + "requires": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + } + } + }, + "nan": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", + "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==" + }, + "nano-json-stream-parser": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz", + "integrity": "sha1-DMj20OK2IrR5xA1JnEbWS3Vcb18=" + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "optional": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "optional": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "optional": true + } + } + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", + "dev": true + }, + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" + }, + "node-addon-api": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.1.tgz", + "integrity": "sha512-2WVfwRfIr1AVn3dRq4yRc2Hn35ND+mPJH6inC6bjpYCZVrpXPB4j3T6i//OGVfqVsR1t/X/axRulDsheq4F0LQ==" + }, + "node-emoji": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz", + "integrity": "sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==", + "dev": true, + "requires": { + "lodash.toarray": "^4.4.0" + } + }, + "node-environment-flags": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", + "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", + "requires": { + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "node-gyp-build": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.2.2.tgz", + "integrity": "sha512-Lqh7mrByWCM8Cf9UPqpeoVBBo5Ugx+RKu885GAzmLBVYjeywScxHXPGLa4JfYNZmcNGwzR0Glu5/9GaQZMFqyA==" + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "optional": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "normalize-url": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", + "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==" + }, + "number-to-bn": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz", + "integrity": "sha1-uzYjWS9+X54AMLGXe9QaDFP+HqA=", + "requires": { + "bn.js": "4.11.6", + "strip-hex-prefix": "1.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=" + } + } + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "optional": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "optional": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" + }, + "object-is": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.2.tgz", + "integrity": "sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "optional": true, + "requires": { + "isobject": "^3.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "optional": true + } + } + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", + "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "optional": true, + "requires": { + "for-own": "^0.1.4", + "is-extendable": "^0.1.1" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "optional": true, + "requires": { + "isobject": "^3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "optional": true + } + } + }, + "oboe": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.4.tgz", + "integrity": "sha1-IMiM2wwVNxuwQRklfU/dNLCqSfY=", + "requires": { + "http-https": "^1.0.0" + } + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "output-file-sync": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/output-file-sync/-/output-file-sync-1.1.2.tgz", + "integrity": "sha1-0KM+7+YaIF+suQCS6CZZjVJFznY=", + "requires": { + "graceful-fs": "^4.1.4", + "mkdirp": "^0.5.1", + "object-assign": "^4.1.0" + }, + "dependencies": { + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + } + } + }, + "p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==" + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-timeout": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz", + "integrity": "sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y=", + "requires": { + "p-finally": "^1.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "parse-asn1": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", + "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", + "requires": { + "asn1.js": "^4.0.0", + "browserify-aes": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-code-context": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-code-context/-/parse-code-context-1.0.0.tgz", + "integrity": "sha512-OZQaqKaQnR21iqhlnPfVisFjBWjhnMl5J9MgbP8xC+EwoVqbXrq78lp+9Zb3ahmLzrIX5Us/qbvBnaS3hkH6OA==", + "dev": true + }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "optional": true, + "requires": { + "glob-base": "^0.3.0", + "is-dotfile": "^1.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.0" + }, + "dependencies": { + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "optional": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "optional": true, + "requires": { + "is-extglob": "^1.0.0" + } + } + } + }, + "parse-headers": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.3.tgz", + "integrity": "sha512-QhhZ+DCCit2Coi2vmAKbq5RGTRcQUOE2+REgv8vdyu7MnYx2eZztegqtTx99TZ86GTIwqiy3+4nQTWZ2tgmdCA==" + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "optional": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=" + }, + "pbkdf2": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.0.tgz", + "integrity": "sha512-wHMFZ6HTLGlB9f/WsQBs5OwMQJoLXYuJUzbA+j+hRBf7+Y8KcXpatzIviIcTy1OAyhWQp08nyiPO8Dnv0z4Sww==", + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==" + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "^2.0.0" + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "optional": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" + }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", + "optional": true + }, + "prettier": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.5.tgz", + "integrity": "sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==", + "dev": true + }, + "prettier-plugin-solidity": { + "version": "1.0.0-alpha.52", + "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.0.0-alpha.52.tgz", + "integrity": "sha512-3Ep3GP+OHbDltvXX60GauvsFLS4TliGLohkWZ5CLGjKeUIikYsB7jlkiRMgVS2K+/eisu4O09hRNYdBaFqcX+g==", + "dev": true, + "requires": { + "@solidity-parser/parser": "^0.6.1", + "dir-to-object": "^2.0.0", + "emoji-regex": "^9.0.0", + "escape-string-regexp": "^4.0.0", + "extract-comments": "^1.1.0", + "prettier": "^2.0.5", + "semver": "^7.3.2", + "string-width": "^4.2.0" + } + }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==" + }, + "process": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz", + "integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + } + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "query-string": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "requires": { + "decode-uri-component": "^0.2.0", + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, + "randomatic": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", + "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", + "optional": true, + "requires": { + "is-number": "^4.0.0", + "kind-of": "^6.0.0", + "math-random": "^1.0.1" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "optional": true + } + } + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "randomhex": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/randomhex/-/randomhex-0.1.5.tgz", + "integrity": "sha1-us7vmCMpCRQA8qKRLGzQLxCU9YU=" + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "optional": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "optional": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "optional": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "optional": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "optional": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "optional": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "optional": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "optional": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "optional": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "optional": true + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "optional": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "optional": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "optional": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "optional": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "optional": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "optional": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "optional": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "optional": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "optional": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "optional": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "optional": true + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "optional": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "requires": { + "resolve": "^1.1.6" + } + }, + "recursive-readdir": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", + "integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==", + "dev": true, + "requires": { + "minimatch": "3.0.4" + } + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + }, + "regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "optional": true, + "requires": { + "is-equal-shallow": "^0.1.3" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "optional": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "optional": true + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "optional": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "optional": true + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "requires": { + "is-finite": "^1.0.0" + } + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "optional": true + }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "requires": { + "lowercase-keys": "^1.0.0" + } + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "optional": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "rlp": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.5.tgz", + "integrity": "sha512-y1QxTQOp0OZnjn19FxBmped4p+BSKPHwGndaqrESseyd2xXZtcgR3yuTIosh8CaMaOii9SKIYerBXnV/CpJ3qw==", + "requires": { + "bn.js": "^4.11.1" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } + } + }, + "run-parallel": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", + "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", + "dev": true + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "optional": true, + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sc-istanbul": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/sc-istanbul/-/sc-istanbul-0.4.5.tgz", + "integrity": "sha512-7wR5EZFLsC4w0wSm9BUuCgW+OGKAU7PNlW5L0qwVPbh+Q1sfVn2fyzfMXYCm6rkNA5ipaCOt94nApcguQwF5Gg==", + "dev": true, + "requires": { + "abbrev": "1.0.x", + "async": "1.x", + "escodegen": "1.8.x", + "esprima": "2.7.x", + "glob": "^5.0.15", + "handlebars": "^4.0.1", + "js-yaml": "3.x", + "mkdirp": "0.5.x", + "nopt": "3.x", + "once": "1.x", + "resolve": "1.1.x", + "supports-color": "^3.1.0", + "which": "^1.1.1", + "wordwrap": "^1.0.0" + }, + "dependencies": { + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "dev": true + }, + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "dev": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "scrypt-js": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.4.tgz", + "integrity": "sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw==", + "dev": true + }, + "scrypt-shim": { + "version": "github:web3-js/scrypt-shim#aafdadda13e660e25e1c525d1f5b2443f5eb1ebb", + "from": "github:web3-js/scrypt-shim", + "dev": true, + "requires": { + "scryptsy": "^2.1.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "scryptsy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/scryptsy/-/scryptsy-2.1.0.tgz", + "integrity": "sha512-1CdSqHQowJBnMAFyPEBRfqag/YP9OF394FV+4YREIJX4ljD7OxvQRDayyoyyCk+senRjSkP6VnUNQmVQqB6g7w==" + }, + "secp256k1": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.1.tgz", + "integrity": "sha512-iGRjbGAKfXMqhtdkkuNxsgJQfJO8Oo78Rm7DAvsG3XKngq+nJIOGqrCSXcQqIVsmCj0wFanE5uTKFxV3T9j2wg==", + "requires": { + "elliptic": "^6.5.2", + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + } + }, + "seek-bzip": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.5.tgz", + "integrity": "sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w=", + "requires": { + "commander": "~2.8.1" + } + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "servify": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/servify/-/servify-0.1.12.tgz", + "integrity": "sha512-/xE6GvsKKqyo1BAY+KxOWXcLpPsUUyji7Qg3bVD7hh1eRze5bR1uYiuDA/k3Gof1s9BTzQZEJK8sNcNGFIzeWw==", + "requires": { + "body-parser": "^1.16.0", + "cors": "^2.8.1", + "express": "^4.14.0", + "request": "^2.79.0", + "xhr": "^2.3.3" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "optional": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "setimmediate": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz", + "integrity": "sha1-IOgd5iLUoCWIzgyNqJc8vPHTE48=" + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shelljs": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz", + "integrity": "sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==", + "dev": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, + "simple-concat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz", + "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=" + }, + "simple-get": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.1.tgz", + "integrity": "sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw==", + "requires": { + "decompress-response": "^3.3.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "optional": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "optional": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "optional": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "optional": true + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "optional": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "optional": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "optional": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "optional": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "optional": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "optional": true + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "optional": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "solidity-coverage": { + "version": "0.7.7", + "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.7.7.tgz", + "integrity": "sha512-hD043l+Hy8cNMqrI6k5wZNEc7ceVJIWaWztE8D7u8QqbaObZldpknDJPRXHnRGniI5t6HeOQ+8F4ifiNCn2BeA==", + "dev": true, + "requires": { + "@solidity-parser/parser": "^0.6.0", + "@truffle/provider": "^0.1.17", + "chalk": "^2.4.2", + "death": "^1.1.0", + "detect-port": "^1.3.0", + "fs-extra": "^8.1.0", + "ganache-cli": "6.9.0", + "ghost-testrpc": "^0.0.2", + "global-modules": "^2.0.0", + "globby": "^10.0.1", + "jsonschema": "^1.2.4", + "lodash": "^4.17.15", + "node-emoji": "^1.10.0", + "pify": "^4.0.1", + "recursive-readdir": "^2.2.2", + "sc-istanbul": "^0.4.5", + "shelljs": "^0.8.3", + "web3": "1.2.6" + }, + "dependencies": { + "@types/node": { + "version": "12.12.47", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.47.tgz", + "integrity": "sha512-yzBInQFhdY8kaZmqoL2+3U5dSTMrKaYcb561VU+lDzAYvqt+2lojvBEy+hmpSNuXnPTx7m9+04CzWYOUqWME2A==", + "dev": true + }, + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "dev": true + }, + "eth-lib": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.7.tgz", + "integrity": "sha1-L5Pxex4jrsN1nNSj/iDBKGo/wco=", + "dev": true, + "requires": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + } + }, + "ethers": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.0-beta.3.tgz", + "integrity": "sha512-YYPogooSknTwvHg3+Mv71gM/3Wcrx+ZpCzarBj3mqs9njjRkrOo2/eufzhHloOCo3JSoNI4TQJJ6yU5ABm3Uog==", + "dev": true, + "requires": { + "@types/node": "^10.3.2", + "aes-js": "3.0.0", + "bn.js": "^4.4.0", + "elliptic": "6.3.3", + "hash.js": "1.1.3", + "js-sha3": "0.5.7", + "scrypt-js": "2.0.3", + "setimmediate": "1.0.4", + "uuid": "2.0.1", + "xmlhttprequest": "1.8.0" + }, + "dependencies": { + "@types/node": { + "version": "10.17.26", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.26.tgz", + "integrity": "sha512-myMwkO2Cr82kirHY8uknNRHEVtn0wV3DTQfkrjx17jmkstDRZ24gNUdl8AHXVyVclTYI/bNjgTPTAWvWLqXqkw==", + "dev": true + }, + "elliptic": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.3.3.tgz", + "integrity": "sha1-VILZZG1UvLif19mU/J4ulWiHbj8=", + "dev": true, + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "inherits": "^2.0.1" + } + } + } + }, + "ganache-cli": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/ganache-cli/-/ganache-cli-6.9.0.tgz", + "integrity": "sha512-ZdL6kPrApXF/O+f6uU431OJcwxMk69H3KPDSHHrMP82ZvZRNpDHbR+rVv7XX/YUeoQ5q6nZ2AFiGiFAVn9pfzA==", + "dev": true, + "requires": { + "ethereumjs-util": "6.1.0", + "source-map-support": "0.5.12", + "yargs": "13.2.4" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "bundled": true, + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "bundled": true, + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "bindings": { + "version": "1.5.0", + "bundled": true, + "dev": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "bip66": { + "version": "1.1.5", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "bn.js": { + "version": "4.11.8", + "bundled": true, + "dev": true + }, + "brorand": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "browserify-aes": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "buffer-from": { + "version": "1.1.1", + "bundled": true, + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "bundled": true, + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "bundled": true, + "dev": true + }, + "cipher-base": { + "version": "1.0.4", + "bundled": true, + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "cliui": { + "version": "5.0.0", + "bundled": true, + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "color-convert": { + "version": "1.9.3", + "bundled": true, + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "bundled": true, + "dev": true + }, + "create-hash": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "bundled": true, + "dev": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "cross-spawn": { + "version": "6.0.5", + "bundled": true, + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "decamelize": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "drbg.js": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "browserify-aes": "^1.0.6", + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4" + } + }, + "elliptic": { + "version": "6.5.0", + "bundled": true, + "dev": true, + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + } + }, + "emoji-regex": { + "version": "7.0.3", + "bundled": true, + "dev": true + }, + "end-of-stream": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "ethereumjs-util": { + "version": "6.1.0", + "bundled": true, + "dev": true, + "requires": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "ethjs-util": "0.1.6", + "keccak": "^1.0.2", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1", + "secp256k1": "^3.0.1" + } + }, + "ethjs-util": { + "version": "0.1.6", + "bundled": true, + "dev": true, + "requires": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + } + }, + "evp_bytestokey": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "execa": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "file-uri-to-path": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "find-up": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "get-caller-file": { + "version": "2.0.5", + "bundled": true, + "dev": true + }, + "get-stream": { + "version": "4.1.0", + "bundled": true, + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "hash-base": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "hash.js": { + "version": "1.1.7", + "bundled": true, + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "inherits": { + "version": "2.0.4", + "bundled": true, + "dev": true + }, + "invert-kv": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "is-hex-prefixed": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "isexe": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "keccak": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "bindings": "^1.2.1", + "inherits": "^2.0.3", + "nan": "^2.2.1", + "safe-buffer": "^5.1.0" + } + }, + "lcid": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "map-age-cleaner": { + "version": "0.1.3", + "bundled": true, + "dev": true, + "requires": { + "p-defer": "^1.0.0" + } + }, + "md5.js": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "mem": { + "version": "4.3.0", + "bundled": true, + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "minimalistic-assert": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "nan": { + "version": "2.14.0", + "bundled": true, + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "bundled": true, + "dev": true + }, + "npm-run-path": { + "version": "2.0.2", + "bundled": true, + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "os-locale": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "p-defer": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "p-finally": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "p-is-promise": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "p-limit": { + "version": "2.2.0", + "bundled": true, + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "bundled": true, + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "path-key": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "pump": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "require-directory": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "ripemd160": { + "version": "2.0.2", + "bundled": true, + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "rlp": { + "version": "2.2.3", + "bundled": true, + "dev": true, + "requires": { + "bn.js": "^4.11.1", + "safe-buffer": "^5.1.1" + } + }, + "safe-buffer": { + "version": "5.2.0", + "bundled": true, + "dev": true + }, + "secp256k1": { + "version": "3.7.1", + "bundled": true, + "dev": true, + "requires": { + "bindings": "^1.5.0", + "bip66": "^1.1.5", + "bn.js": "^4.11.8", + "create-hash": "^1.2.0", + "drbg.js": "^1.0.1", + "elliptic": "^6.4.1", + "nan": "^2.14.0", + "safe-buffer": "^5.1.2" + } + }, + "semver": { + "version": "5.7.0", + "bundled": true, + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "bundled": true, + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shebang-command": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true + }, + "source-map": { + "version": "0.6.1", + "bundled": true, + "dev": true + }, + "source-map-support": { + "version": "0.5.12", + "bundled": true, + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "string-width": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "strip-eof": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "strip-hex-prefix": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-hex-prefixed": "1.0.0" + } + }, + "which": { + "version": "1.3.1", + "bundled": true, + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "wrap-ansi": { + "version": "5.1.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "y18n": { + "version": "4.0.0", + "bundled": true, + "dev": true + }, + "yargs": { + "version": "13.2.4", + "bundled": true, + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "os-locale": "^3.1.0", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.0" + } + }, + "yargs-parser": { + "version": "13.1.1", + "bundled": true, + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.0" + } + }, + "scrypt-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.3.tgz", + "integrity": "sha1-uwBAvgMEPamgEqLOqfyfhSz8h9Q=", + "dev": true + }, + "web3": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.2.6.tgz", + "integrity": "sha512-tpu9fLIComgxGrFsD8LUtA4s4aCZk7px8UfcdEy6kS2uDi/ZfR07KJqpXZMij7Jvlq+cQrTAhsPSiBVvoMaivA==", + "dev": true, + "requires": { + "@types/node": "^12.6.1", + "web3-bzz": "1.2.6", + "web3-core": "1.2.6", + "web3-eth": "1.2.6", + "web3-eth-personal": "1.2.6", + "web3-net": "1.2.6", + "web3-shh": "1.2.6", + "web3-utils": "1.2.6" + } + }, + "web3-bzz": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.2.6.tgz", + "integrity": "sha512-9NiHLlxdI1XeFtbPJAmi2jnnIHVF+GNy517wvOS72P7ZfuJTPwZaSNXfT01vWgPPE9R96/uAHDWHOg+T4WaDQQ==", + "dev": true, + "requires": { + "@types/node": "^10.12.18", + "got": "9.6.0", + "swarm-js": "0.1.39", + "underscore": "1.9.1" + }, + "dependencies": { + "@types/node": { + "version": "10.17.26", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.26.tgz", + "integrity": "sha512-myMwkO2Cr82kirHY8uknNRHEVtn0wV3DTQfkrjx17jmkstDRZ24gNUdl8AHXVyVclTYI/bNjgTPTAWvWLqXqkw==", + "dev": true + } + } + }, + "web3-core": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.2.6.tgz", + "integrity": "sha512-y/QNBFtr5cIR8vxebnotbjWJpOnO8LDYEAzZjeRRUJh2ijmhjoYk7dSNx9ExgC0UCfNFRoNCa9dGRu/GAxwRlw==", + "dev": true, + "requires": { + "@types/bn.js": "^4.11.4", + "@types/node": "^12.6.1", + "web3-core-helpers": "1.2.6", + "web3-core-method": "1.2.6", + "web3-core-requestmanager": "1.2.6", + "web3-utils": "1.2.6" + } + }, + "web3-core-helpers": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.6.tgz", + "integrity": "sha512-gYKWmC2HmO7RcDzpo4L1K8EIoy5L8iubNDuTC6q69UxczwqKF/Io0kbK/1Z10Av++NlzOSiuyGp2gc4t4UOsDw==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-eth-iban": "1.2.6", + "web3-utils": "1.2.6" + } + }, + "web3-core-method": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.2.6.tgz", + "integrity": "sha512-r2dzyPEonqkBg7Mugq5dknhV5PGaZTHBZlS/C+aMxNyQs3T3eaAsCTqlQDitwNUh/sUcYPEGF0Vo7ahYK4k91g==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-core-helpers": "1.2.6", + "web3-core-promievent": "1.2.6", + "web3-core-subscriptions": "1.2.6", + "web3-utils": "1.2.6" + } + }, + "web3-core-promievent": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.2.6.tgz", + "integrity": "sha512-km72kJef/qtQNiSjDJJVHIZvoVOm6ytW3FCYnOcCs7RIkviAb5JYlPiye0o4pJOLzCXYID7DK7Q9bhY8qWb1lw==", + "dev": true, + "requires": { + "any-promise": "1.3.0", + "eventemitter3": "3.1.2" + } + }, + "web3-core-requestmanager": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.2.6.tgz", + "integrity": "sha512-QU2cbsj9Dm0r6om40oSwk8Oqbp3wTa08tXuMpSmeOTkGZ3EMHJ1/4LiJ8shwg1AvPMrKVU0Nri6+uBNCdReZ+g==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-core-helpers": "1.2.6", + "web3-providers-http": "1.2.6", + "web3-providers-ipc": "1.2.6", + "web3-providers-ws": "1.2.6" + } + }, + "web3-core-subscriptions": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.2.6.tgz", + "integrity": "sha512-M0PzRrP2Ct13x3wPulFtc5kENH4UtnPxO9YxkfQlX2WRKENWjt4Rfq+BCVGYEk3rTutDfWrjfzjmqMRvXqEY5Q==", + "dev": true, + "requires": { + "eventemitter3": "3.1.2", + "underscore": "1.9.1", + "web3-core-helpers": "1.2.6" + } + }, + "web3-eth": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.2.6.tgz", + "integrity": "sha512-ROWlDPzh4QX6tlGGGlAK6X4kA2n0/cNj/4kb0nNVWkRouGmYO0R8k6s47YxYHvGiXt0s0++FUUv5vAbWovtUQw==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-core": "1.2.6", + "web3-core-helpers": "1.2.6", + "web3-core-method": "1.2.6", + "web3-core-subscriptions": "1.2.6", + "web3-eth-abi": "1.2.6", + "web3-eth-accounts": "1.2.6", + "web3-eth-contract": "1.2.6", + "web3-eth-ens": "1.2.6", + "web3-eth-iban": "1.2.6", + "web3-eth-personal": "1.2.6", + "web3-net": "1.2.6", + "web3-utils": "1.2.6" + } + }, + "web3-eth-abi": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.2.6.tgz", + "integrity": "sha512-w9GAyyikn8nSifSDZxAvU9fxtQSX+W2xQWMmrtTXmBGCaE4/ywKOSPAO78gq8AoU4Wq5yqVGKZLLbfpt7/sHlA==", + "dev": true, + "requires": { + "ethers": "4.0.0-beta.3", + "underscore": "1.9.1", + "web3-utils": "1.2.6" + } + }, + "web3-eth-accounts": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.2.6.tgz", + "integrity": "sha512-cDVtonHRgzqi/ZHOOf8kfCQWFEipcfQNAMzXIaKZwc0UUD9mgSI5oJrN45a89Ze+E6Lz9m77cDG5Ax9zscSkcw==", + "dev": true, + "requires": { + "@web3-js/scrypt-shim": "^0.1.0", + "any-promise": "1.3.0", + "crypto-browserify": "3.12.0", + "eth-lib": "^0.2.8", + "ethereumjs-common": "^1.3.2", + "ethereumjs-tx": "^2.1.1", + "underscore": "1.9.1", + "uuid": "3.3.2", + "web3-core": "1.2.6", + "web3-core-helpers": "1.2.6", + "web3-core-method": "1.2.6", + "web3-utils": "1.2.6" + }, + "dependencies": { + "eth-lib": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz", + "integrity": "sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw==", + "dev": true, + "requires": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + } + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true + } + } + }, + "web3-eth-contract": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.2.6.tgz", + "integrity": "sha512-ak4xbHIhWgsbdPCkSN+HnQc1SH4c856y7Ly+S57J/DQVzhFZemK5HvWdpwadJrQTcHET3ZeId1vq3kmW7UYodw==", + "dev": true, + "requires": { + "@types/bn.js": "^4.11.4", + "underscore": "1.9.1", + "web3-core": "1.2.6", + "web3-core-helpers": "1.2.6", + "web3-core-method": "1.2.6", + "web3-core-promievent": "1.2.6", + "web3-core-subscriptions": "1.2.6", + "web3-eth-abi": "1.2.6", + "web3-utils": "1.2.6" + } + }, + "web3-eth-ens": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.2.6.tgz", + "integrity": "sha512-8UEqt6fqR/dji/jBGPFAyBs16OJjwi0t2dPWXPyGXmty/fH+osnXwWXE4HRUyj4xuafiM5P1YkXMsPhKEadjiw==", + "dev": true, + "requires": { + "eth-ens-namehash": "2.0.8", + "underscore": "1.9.1", + "web3-core": "1.2.6", + "web3-core-helpers": "1.2.6", + "web3-core-promievent": "1.2.6", + "web3-eth-abi": "1.2.6", + "web3-eth-contract": "1.2.6", + "web3-utils": "1.2.6" + } + }, + "web3-eth-iban": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.2.6.tgz", + "integrity": "sha512-TPMc3BW9Iso7H+9w+ytbqHK9wgOmtocyCD3PaAe5Eie50KQ/j7ThA60dGJnxItVo6yyRv5pZAYxPVob9x/fJlg==", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "web3-utils": "1.2.6" + } + }, + "web3-eth-personal": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.2.6.tgz", + "integrity": "sha512-T2NUkh1plY8d7wePXSoHnaiKOd8dLNFaQfgBl9JHU6S7IJrG9jnYD9bVxLEgRUfHs9gKf9tQpDf7AcPFdq/A8g==", + "dev": true, + "requires": { + "@types/node": "^12.6.1", + "web3-core": "1.2.6", + "web3-core-helpers": "1.2.6", + "web3-core-method": "1.2.6", + "web3-net": "1.2.6", + "web3-utils": "1.2.6" + } + }, + "web3-net": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.2.6.tgz", + "integrity": "sha512-hsNHAPddrhgjWLmbESW0KxJi2GnthPcow0Sqpnf4oB6+/+ZnQHU9OsIyHb83bnC1OmunrK2vf9Ye2mLPdFIu3A==", + "dev": true, + "requires": { + "web3-core": "1.2.6", + "web3-core-method": "1.2.6", + "web3-utils": "1.2.6" + } + }, + "web3-providers-http": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.2.6.tgz", + "integrity": "sha512-2+SaFCspb5f82QKuHB3nEPQOF9iSWxRf7c18fHtmnLNVkfG9SwLN1zh67bYn3tZGUdOI3gj8aX4Uhfpwx9Ezpw==", + "dev": true, + "requires": { + "web3-core-helpers": "1.2.6", + "xhr2-cookies": "1.1.0" + } + }, + "web3-providers-ipc": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.2.6.tgz", + "integrity": "sha512-b0Es+/GTZyk5FG3SgUDW+2/mBwJAXWt5LuppODptiOas8bB2khLjG6+Gm1K4uwOb+1NJGPt5mZZ8Wi7vibtQ+A==", + "dev": true, + "requires": { + "oboe": "2.1.4", + "underscore": "1.9.1", + "web3-core-helpers": "1.2.6" + } + }, + "web3-providers-ws": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.2.6.tgz", + "integrity": "sha512-20waSYX+gb5M5yKhug5FIwxBBvkKzlJH7sK6XEgdOx6BZ9YYamLmvg9wcRVtnSZO8hV/3cWenO/tRtTrHVvIgQ==", + "dev": true, + "requires": { + "@web3-js/websocket": "^1.0.29", + "underscore": "1.9.1", + "web3-core-helpers": "1.2.6" + } + }, + "web3-shh": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.2.6.tgz", + "integrity": "sha512-rouWyOOM6YMbLQd65grpj8BBezQfgNeRRX+cGyW4xsn6Xgu+B73Zvr6OtA/ftJwwa9bqHGpnLrrLMeWyy4YLUw==", + "dev": true, + "requires": { + "web3-core": "1.2.6", + "web3-core-method": "1.2.6", + "web3-core-subscriptions": "1.2.6", + "web3-net": "1.2.6" + } + }, + "web3-utils": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.2.6.tgz", + "integrity": "sha512-8/HnqG/l7dGmKMgEL9JeKPTtjScxOePTzopv5aaKFExPfaBrYRkgoMqhoowCiAl/s16QaTn4DoIF1QC4YsT7Mg==", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "eth-lib": "0.2.7", + "ethereum-bloom-filters": "^1.0.6", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "underscore": "1.9.1", + "utf8": "3.0.0" + } + } + } + }, + "source-map": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", + "dev": true, + "optional": true, + "requires": { + "amdefine": ">=0.0.4" + } + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "optional": true, + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "requires": { + "source-map": "^0.5.6" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "optional": true + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "optional": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "optional": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "optional": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + } + } + }, + "string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "strip-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", + "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", + "requires": { + "is-natural-number": "^4.0.1" + } + }, + "strip-hex-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", + "integrity": "sha1-DF8VX+8RUTczd96du1iNoFUA428=", + "requires": { + "is-hex-prefixed": "1.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "swarm-js": { + "version": "0.1.39", + "resolved": "https://registry.npmjs.org/swarm-js/-/swarm-js-0.1.39.tgz", + "integrity": "sha512-QLMqL2rzF6n5s50BptyD6Oi0R1aWlJC5Y17SRIVXRj6OR1DRIPM7nepvrxxkjA1zNzFz6mUOMjfeqeDaWB7OOg==", + "requires": { + "bluebird": "^3.5.0", + "buffer": "^5.0.5", + "decompress": "^4.0.0", + "eth-lib": "^0.1.26", + "fs-extra": "^4.0.2", + "got": "^7.1.0", + "mime-types": "^2.1.16", + "mkdirp-promise": "^5.0.1", + "mock-fs": "^4.1.0", + "setimmediate": "^1.0.5", + "tar": "^4.0.2", + "xhr-request-promise": "^0.1.2" + }, + "dependencies": { + "fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" + }, + "got": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/got/-/got-7.1.0.tgz", + "integrity": "sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==", + "requires": { + "decompress-response": "^3.2.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-plain-obj": "^1.1.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "isurl": "^1.0.0-alpha5", + "lowercase-keys": "^1.0.0", + "p-cancelable": "^0.3.0", + "p-timeout": "^1.1.1", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "url-parse-lax": "^1.0.0", + "url-to-options": "^1.0.1" + } + }, + "p-cancelable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz", + "integrity": "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==" + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + }, + "url-parse-lax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "requires": { + "prepend-http": "^1.0.1" + } + } + } + }, + "tar": { + "version": "4.4.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", + "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + }, + "dependencies": { + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + } + } + }, + "tar-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", + "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", + "requires": { + "bl": "^1.0.0", + "buffer-alloc": "^1.2.0", + "end-of-stream": "^1.0.0", + "fs-constants": "^1.0.0", + "readable-stream": "^2.3.0", + "to-buffer": "^1.1.1", + "xtend": "^4.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" + }, + "to-buffer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", + "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==" + }, + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "optional": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==" + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "optional": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" + }, + "truffle-hdwallet-provider": { + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/truffle-hdwallet-provider/-/truffle-hdwallet-provider-1.0.17.tgz", + "integrity": "sha512-s6DvSP83jiIAc6TUcpr7Uqnja1+sLGJ8og3X7n41vfyC4OCaKmBtXL5HOHf+SsU3iblOvnbFDgmN6Y1VBL/fsg==", + "requires": { + "any-promise": "^1.3.0", + "bindings": "^1.3.1", + "web3": "1.2.1", + "websocket": "^1.0.28" + }, + "dependencies": { + "@types/node": { + "version": "10.17.24", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.24.tgz", + "integrity": "sha512-5SCfvCxV74kzR3uWgTYiGxrd69TbT1I6+cMx1A5kEly/IVveJBimtAMlXiEyVFn5DvUFewQWxOOiJhlxeQwxgA==" + }, + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "eth-lib": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.7.tgz", + "integrity": "sha1-L5Pxex4jrsN1nNSj/iDBKGo/wco=", + "requires": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + } + }, + "ethers": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.0-beta.3.tgz", + "integrity": "sha512-YYPogooSknTwvHg3+Mv71gM/3Wcrx+ZpCzarBj3mqs9njjRkrOo2/eufzhHloOCo3JSoNI4TQJJ6yU5ABm3Uog==", + "requires": { + "@types/node": "^10.3.2", + "aes-js": "3.0.0", + "bn.js": "^4.4.0", + "elliptic": "6.3.3", + "hash.js": "1.1.3", + "js-sha3": "0.5.7", + "scrypt-js": "2.0.3", + "setimmediate": "1.0.4", + "uuid": "2.0.1", + "xmlhttprequest": "1.8.0" + }, + "dependencies": { + "elliptic": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.3.3.tgz", + "integrity": "sha1-VILZZG1UvLif19mU/J4ulWiHbj8=", + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "inherits": "^2.0.1" + } + } + } + }, + "hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "scrypt-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.3.tgz", + "integrity": "sha1-uwBAvgMEPamgEqLOqfyfhSz8h9Q=" + }, + "semver": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.2.0.tgz", + "integrity": "sha512-jdFC1VdUGT/2Scgbimf7FSx9iJLXoqfglSF+gJeuNWVpiE37OIbc1jywR/GJyFdz3mnkz2/id0L0J/cr0izR5A==" + }, + "web3": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.2.1.tgz", + "integrity": "sha512-nNMzeCK0agb5i/oTWNdQ1aGtwYfXzHottFP2Dz0oGIzavPMGSKyVlr8ibVb1yK5sJBjrWVnTdGaOC2zKDFuFRw==", + "requires": { + "web3-bzz": "1.2.1", + "web3-core": "1.2.1", + "web3-eth": "1.2.1", + "web3-eth-personal": "1.2.1", + "web3-net": "1.2.1", + "web3-shh": "1.2.1", + "web3-utils": "1.2.1" + } + }, + "web3-bzz": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.2.1.tgz", + "integrity": "sha512-LdOO44TuYbGIPfL4ilkuS89GQovxUpmLz6C1UC7VYVVRILeZS740FVB3j9V4P4FHUk1RenaDfKhcntqgVCHtjw==", + "requires": { + "got": "9.6.0", + "swarm-js": "0.1.39", + "underscore": "1.9.1" + } + }, + "web3-core": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.2.1.tgz", + "integrity": "sha512-5ODwIqgl8oIg/0+Ai4jsLxkKFWJYE0uLuE1yUKHNVCL4zL6n3rFjRMpKPokd6id6nJCNgeA64KdWQ4XfpnjdMg==", + "requires": { + "web3-core-helpers": "1.2.1", + "web3-core-method": "1.2.1", + "web3-core-requestmanager": "1.2.1", + "web3-utils": "1.2.1" + } + }, + "web3-core-helpers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.1.tgz", + "integrity": "sha512-Gx3sTEajD5r96bJgfuW377PZVFmXIH4TdqDhgGwd2lZQCcMi+DA4TgxJNJGxn0R3aUVzyyE76j4LBrh412mXrw==", + "requires": { + "underscore": "1.9.1", + "web3-eth-iban": "1.2.1", + "web3-utils": "1.2.1" + } + }, + "web3-core-method": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.2.1.tgz", + "integrity": "sha512-Ghg2WS23qi6Xj8Od3VCzaImLHseEA7/usvnOItluiIc5cKs00WYWsNy2YRStzU9a2+z8lwQywPYp0nTzR/QXdQ==", + "requires": { + "underscore": "1.9.1", + "web3-core-helpers": "1.2.1", + "web3-core-promievent": "1.2.1", + "web3-core-subscriptions": "1.2.1", + "web3-utils": "1.2.1" + } + }, + "web3-core-promievent": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.2.1.tgz", + "integrity": "sha512-IVUqgpIKoeOYblwpex4Hye6npM0aMR+kU49VP06secPeN0rHMyhGF0ZGveWBrGvf8WDPI7jhqPBFIC6Jf3Q3zw==", + "requires": { + "any-promise": "1.3.0", + "eventemitter3": "3.1.2" + } + }, + "web3-core-requestmanager": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.2.1.tgz", + "integrity": "sha512-xfknTC69RfYmLKC+83Jz73IC3/sS2ZLhGtX33D4Q5nQ8yc39ElyAolxr9sJQS8kihOcM6u4J+8gyGMqsLcpIBg==", + "requires": { + "underscore": "1.9.1", + "web3-core-helpers": "1.2.1", + "web3-providers-http": "1.2.1", + "web3-providers-ipc": "1.2.1", + "web3-providers-ws": "1.2.1" + } + }, + "web3-core-subscriptions": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.2.1.tgz", + "integrity": "sha512-nmOwe3NsB8V8UFsY1r+sW6KjdOS68h8nuh7NzlWxBQT/19QSUGiERRTaZXWu5BYvo1EoZRMxCKyCQpSSXLc08g==", + "requires": { + "eventemitter3": "3.1.2", + "underscore": "1.9.1", + "web3-core-helpers": "1.2.1" + } + }, + "web3-eth": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.2.1.tgz", + "integrity": "sha512-/2xly4Yry5FW1i+uygPjhfvgUP/MS/Dk+PDqmzp5M88tS86A+j8BzKc23GrlA8sgGs0645cpZK/999LpEF5UdA==", + "requires": { + "underscore": "1.9.1", + "web3-core": "1.2.1", + "web3-core-helpers": "1.2.1", + "web3-core-method": "1.2.1", + "web3-core-subscriptions": "1.2.1", + "web3-eth-abi": "1.2.1", + "web3-eth-accounts": "1.2.1", + "web3-eth-contract": "1.2.1", + "web3-eth-ens": "1.2.1", + "web3-eth-iban": "1.2.1", + "web3-eth-personal": "1.2.1", + "web3-net": "1.2.1", + "web3-utils": "1.2.1" + } + }, + "web3-eth-abi": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.2.1.tgz", + "integrity": "sha512-jI/KhU2a/DQPZXHjo2GW0myEljzfiKOn+h1qxK1+Y9OQfTcBMxrQJyH5AP89O6l6NZ1QvNdq99ThAxBFoy5L+g==", + "requires": { + "ethers": "4.0.0-beta.3", + "underscore": "1.9.1", + "web3-utils": "1.2.1" + } + }, + "web3-eth-accounts": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.2.1.tgz", + "integrity": "sha512-26I4qq42STQ8IeKUyur3MdQ1NzrzCqPsmzqpux0j6X/XBD7EjZ+Cs0lhGNkSKH5dI3V8CJasnQ5T1mNKeWB7nQ==", + "requires": { + "any-promise": "1.3.0", + "crypto-browserify": "3.12.0", + "eth-lib": "0.2.7", + "scryptsy": "2.1.0", + "semver": "6.2.0", + "underscore": "1.9.1", + "uuid": "3.3.2", + "web3-core": "1.2.1", + "web3-core-helpers": "1.2.1", + "web3-core-method": "1.2.1", + "web3-utils": "1.2.1" + }, + "dependencies": { + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + } + } + }, + "web3-eth-contract": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.2.1.tgz", + "integrity": "sha512-kYFESbQ3boC9bl2rYVghj7O8UKMiuKaiMkxvRH5cEDHil8V7MGEGZNH0slSdoyeftZVlaWSMqkRP/chfnKND0g==", + "requires": { + "underscore": "1.9.1", + "web3-core": "1.2.1", + "web3-core-helpers": "1.2.1", + "web3-core-method": "1.2.1", + "web3-core-promievent": "1.2.1", + "web3-core-subscriptions": "1.2.1", + "web3-eth-abi": "1.2.1", + "web3-utils": "1.2.1" + } + }, + "web3-eth-ens": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.2.1.tgz", + "integrity": "sha512-lhP1kFhqZr2nnbu3CGIFFrAnNxk2veXpOXBY48Tub37RtobDyHijHgrj+xTh+mFiPokyrapVjpFsbGa+Xzye4Q==", + "requires": { + "eth-ens-namehash": "2.0.8", + "underscore": "1.9.1", + "web3-core": "1.2.1", + "web3-core-helpers": "1.2.1", + "web3-core-promievent": "1.2.1", + "web3-eth-abi": "1.2.1", + "web3-eth-contract": "1.2.1", + "web3-utils": "1.2.1" + } + }, + "web3-eth-iban": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.2.1.tgz", + "integrity": "sha512-9gkr4QPl1jCU+wkgmZ8EwODVO3ovVj6d6JKMos52ggdT2YCmlfvFVF6wlGLwi0VvNa/p+0BjJzaqxnnG/JewjQ==", + "requires": { + "bn.js": "4.11.8", + "web3-utils": "1.2.1" + } + }, + "web3-eth-personal": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.2.1.tgz", + "integrity": "sha512-RNDVSiaSoY4aIp8+Hc7z+X72H7lMb3fmAChuSBADoEc7DsJrY/d0R5qQDK9g9t2BO8oxgLrLNyBP/9ub2Hc6Bg==", + "requires": { + "web3-core": "1.2.1", + "web3-core-helpers": "1.2.1", + "web3-core-method": "1.2.1", + "web3-net": "1.2.1", + "web3-utils": "1.2.1" + } + }, + "web3-net": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.2.1.tgz", + "integrity": "sha512-Yt1Bs7WgnLESPe0rri/ZoPWzSy55ovioaP35w1KZydrNtQ5Yq4WcrAdhBzcOW7vAkIwrsLQsvA+hrOCy7mNauw==", + "requires": { + "web3-core": "1.2.1", + "web3-core-method": "1.2.1", + "web3-utils": "1.2.1" + } + }, + "web3-providers-http": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.2.1.tgz", + "integrity": "sha512-BDtVUVolT9b3CAzeGVA/np1hhn7RPUZ6YYGB/sYky+GjeO311Yoq8SRDUSezU92x8yImSC2B+SMReGhd1zL+bQ==", + "requires": { + "web3-core-helpers": "1.2.1", + "xhr2-cookies": "1.1.0" + } + }, + "web3-providers-ipc": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.2.1.tgz", + "integrity": "sha512-oPEuOCwxVx8L4CPD0TUdnlOUZwGBSRKScCz/Ws2YHdr9Ium+whm+0NLmOZjkjQp5wovQbyBzNa6zJz1noFRvFA==", + "requires": { + "oboe": "2.1.4", + "underscore": "1.9.1", + "web3-core-helpers": "1.2.1" + } + }, + "web3-providers-ws": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.2.1.tgz", + "integrity": "sha512-oqsQXzu+ejJACVHy864WwIyw+oB21nw/pI65/sD95Zi98+/HQzFfNcIFneF1NC4bVF3VNX4YHTNq2I2o97LAiA==", + "requires": { + "underscore": "1.9.1", + "web3-core-helpers": "1.2.1", + "websocket": "github:web3-js/WebSocket-Node#polyfill/globalThis" + }, + "dependencies": { + "websocket": { + "version": "github:web3-js/WebSocket-Node#ef5ea2f41daf4a2113b80c9223df884b4d56c400", + "from": "github:web3-js/WebSocket-Node#polyfill/globalThis", + "requires": { + "debug": "^2.2.0", + "es5-ext": "^0.10.50", + "nan": "^2.14.0", + "typedarray-to-buffer": "^3.1.5", + "yaeti": "^0.0.6" + } + } + } + }, + "web3-shh": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.2.1.tgz", + "integrity": "sha512-/3Cl04nza5kuFn25bV3FJWa0s3Vafr5BlT933h26xovQ6HIIz61LmvNQlvX1AhFL+SNJOTcQmK1SM59vcyC8bA==", + "requires": { + "web3-core": "1.2.1", + "web3-core-method": "1.2.1", + "web3-core-subscriptions": "1.2.1", + "web3-net": "1.2.1" + } + }, + "web3-utils": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.2.1.tgz", + "integrity": "sha512-Mrcn3l58L+yCKz3zBryM6JZpNruWuT0OCbag8w+reeNROSGVlXzUQkU+gtAwc9JCZ7tKUyg67+2YUGqUjVcyBA==", + "requires": { + "bn.js": "4.11.8", + "eth-lib": "0.2.7", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randomhex": "0.1.5", + "underscore": "1.9.1", + "utf8": "3.0.0" + } + }, + "websocket": { + "version": "1.0.31", + "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.31.tgz", + "integrity": "sha512-VAouplvGKPiKFDTeCCO65vYHsyay8DqoBSlzIO3fayrfOgU94lQN5a1uWVnFrMLceTJw/+fQXR5PGbUVRaHshQ==", + "requires": { + "debug": "^2.2.0", + "es5-ext": "^0.10.50", + "nan": "^2.14.0", + "typedarray-to-buffer": "^3.1.5", + "yaeti": "^0.0.6" + } + } + } + }, + "ts-node": { + "version": "8.10.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.2.tgz", + "integrity": "sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==", + "requires": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + } + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "typescript": { + "version": "3.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.5.tgz", + "integrity": "sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==" + }, + "uglify-js": { + "version": "3.9.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.9.4.tgz", + "integrity": "sha512-8RZBJq5smLOa7KslsNsVcSH+KOXf1uDU8yqLeNuVKwmT0T3FA0ZoXlinQfRad7SDcbZZRZE4ov+2v71EnxNyCA==", + "dev": true, + "optional": true, + "requires": { + "commander": "~2.20.3" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "optional": true + } + } + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" + }, + "unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "requires": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, + "underscore": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", + "integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==" + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "optional": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "optional": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "optional": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "optional": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "optional": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "optional": true + } + } + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "optional": true + }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "requires": { + "prepend-http": "^2.0.0" + } + }, + "url-set-query": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-set-query/-/url-set-query-1.0.0.tgz", + "integrity": "sha1-AW6M/Xwg7gXK/neV6JK9BwL6ozk=" + }, + "url-to-options": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", + "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=" + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "optional": true + }, + "user-home": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", + "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=" + }, + "utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", + "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==" + }, + "util": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.3.tgz", + "integrity": "sha512-I8XkoQwE+fPQEhy9v012V+TSdH2kp9ts29i20TaaDUXsg7x/onePbhFJUExBfv/2ay1ZOp/Vsm3nDlmnFGSAog==", + "requires": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "safe-buffer": "^5.1.2", + "which-typed-array": "^1.1.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "uuid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", + "integrity": "sha1-wqMN7bPlNdcsz4LjQ5QaULqFM6w=" + }, + "v8flags": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-2.1.1.tgz", + "integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=", + "requires": { + "user-home": "^1.1.1" + } + }, + "varint": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.0.tgz", + "integrity": "sha1-2Ca4n3SQcy+rwMDtaT7Uddyynr8=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "web3": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.2.9.tgz", + "integrity": "sha512-Mo5aBRm0JrcNpN/g4VOrDzudymfOnHRC3s2VarhYxRA8aWgF5rnhQ0ziySaugpic1gksbXPe105pUWyRqw8HUA==", + "requires": { + "web3-bzz": "1.2.9", + "web3-core": "1.2.9", + "web3-eth": "1.2.9", + "web3-eth-personal": "1.2.9", + "web3-net": "1.2.9", + "web3-shh": "1.2.9", + "web3-utils": "1.2.9" + }, + "dependencies": { + "@types/node": { + "version": "10.17.26", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.26.tgz", + "integrity": "sha512-myMwkO2Cr82kirHY8uknNRHEVtn0wV3DTQfkrjx17jmkstDRZ24gNUdl8AHXVyVclTYI/bNjgTPTAWvWLqXqkw==" + }, + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "p-cancelable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz", + "integrity": "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==" + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" + }, + "scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==" + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + }, + "swarm-js": { + "version": "0.1.40", + "resolved": "https://registry.npmjs.org/swarm-js/-/swarm-js-0.1.40.tgz", + "integrity": "sha512-yqiOCEoA4/IShXkY3WKwP5PvZhmoOOD8clsKA7EEcRILMkTEYHCQ21HDCAcVpmIxZq4LyZvWeRJ6quIyHk1caA==", + "requires": { + "bluebird": "^3.5.0", + "buffer": "^5.0.5", + "eth-lib": "^0.1.26", + "fs-extra": "^4.0.2", + "got": "^7.1.0", + "mime-types": "^2.1.16", + "mkdirp-promise": "^5.0.1", + "mock-fs": "^4.1.0", + "setimmediate": "^1.0.5", + "tar": "^4.0.2", + "xhr-request": "^1.0.1" + }, + "dependencies": { + "got": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/got/-/got-7.1.0.tgz", + "integrity": "sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==", + "requires": { + "decompress-response": "^3.2.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-plain-obj": "^1.1.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "isurl": "^1.0.0-alpha5", + "lowercase-keys": "^1.0.0", + "p-cancelable": "^0.3.0", + "p-timeout": "^1.1.1", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "url-parse-lax": "^1.0.0", + "url-to-options": "^1.0.1" + } + } + } + }, + "url-parse-lax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "requires": { + "prepend-http": "^1.0.1" + } + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + }, + "web3-bzz": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.2.9.tgz", + "integrity": "sha512-ogVQr9jHodu9HobARtvUSmWG22cv2EUQzlPeejGWZ7j5h20HX40EDuWyomGY5VclIj5DdLY76Tmq88RTf/6nxA==", + "requires": { + "@types/node": "^10.12.18", + "got": "9.6.0", + "swarm-js": "^0.1.40", + "underscore": "1.9.1" + } + }, + "web3-core": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.2.9.tgz", + "integrity": "sha512-fSYv21IP658Ty2wAuU9iqmW7V+75DOYMVZsDH/c14jcF/1VXnedOcxzxSj3vArsCvXZNe6XC5/wAuGZyQwR9RA==", + "requires": { + "@types/bn.js": "^4.11.4", + "@types/node": "^12.6.1", + "bignumber.js": "^9.0.0", + "web3-core-helpers": "1.2.9", + "web3-core-method": "1.2.9", + "web3-core-requestmanager": "1.2.9", + "web3-utils": "1.2.9" + }, + "dependencies": { + "@types/node": { + "version": "12.12.47", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.47.tgz", + "integrity": "sha512-yzBInQFhdY8kaZmqoL2+3U5dSTMrKaYcb561VU+lDzAYvqt+2lojvBEy+hmpSNuXnPTx7m9+04CzWYOUqWME2A==" + } + } + }, + "web3-core-method": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.2.9.tgz", + "integrity": "sha512-bjsIoqP3gs7A/gP8+QeLUCyOKJ8bopteCSNbCX36Pxk6TYfYWNuC6hP+2GzUuqdP3xaZNe+XEElQFUNpR3oyAg==", + "requires": { + "@ethersproject/transactions": "^5.0.0-beta.135", + "underscore": "1.9.1", + "web3-core-helpers": "1.2.9", + "web3-core-promievent": "1.2.9", + "web3-core-subscriptions": "1.2.9", + "web3-utils": "1.2.9" + } + }, + "web3-core-promievent": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.2.9.tgz", + "integrity": "sha512-0eAUA2zjgXTleSrnc1wdoKQPPIHU6KHf4fAscu4W9kKrR+mqP1KsjYrxY9wUyjNnXxfQ+5M29ipvbiaK8OqdOw==", + "requires": { + "eventemitter3": "3.1.2" + } + }, + "web3-core-requestmanager": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.2.9.tgz", + "integrity": "sha512-1PwKV2m46ALUnIN5VPPgjOj8yMLJhhqZYvYJE34hTN5SErOkwhzx5zScvo5MN7v7KyQGFnpVCZKKGCiEnDmtFA==", + "requires": { + "underscore": "1.9.1", + "web3-core-helpers": "1.2.9", + "web3-providers-http": "1.2.9", + "web3-providers-ipc": "1.2.9", + "web3-providers-ws": "1.2.9" + } + }, + "web3-core-subscriptions": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.2.9.tgz", + "integrity": "sha512-Y48TvXPSPxEM33OmXjGVDMzTd0j8X0t2+sDw66haeBS8eYnrEzasWuBZZXDq0zNUsqyxItgBGDn+cszkgEnFqg==", + "requires": { + "eventemitter3": "3.1.2", + "underscore": "1.9.1", + "web3-core-helpers": "1.2.9" + } + }, + "web3-eth": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.2.9.tgz", + "integrity": "sha512-sIKO4iE9FEBa/CYUd6GdPd7GXt/wISqxUd8PlIld6+hvMJj02lgO7Z7p5T9mZIJcIZJGvZX81ogx8oJ9yif+Ag==", + "requires": { + "underscore": "1.9.1", + "web3-core": "1.2.9", + "web3-core-helpers": "1.2.9", + "web3-core-method": "1.2.9", + "web3-core-subscriptions": "1.2.9", + "web3-eth-abi": "1.2.9", + "web3-eth-accounts": "1.2.9", + "web3-eth-contract": "1.2.9", + "web3-eth-ens": "1.2.9", + "web3-eth-iban": "1.2.9", + "web3-eth-personal": "1.2.9", + "web3-net": "1.2.9", + "web3-utils": "1.2.9" + } + }, + "web3-eth-abi": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.2.9.tgz", + "integrity": "sha512-3YwUYbh/DMfDbhMWEebAdjSd5bj3ZQieOjLzWFHU23CaLEqT34sUix1lba+hgUH/EN6A7bKAuKOhR3p0OvTn7Q==", + "requires": { + "@ethersproject/abi": "5.0.0-beta.153", + "underscore": "1.9.1", + "web3-utils": "1.2.9" + } + }, + "web3-eth-accounts": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.2.9.tgz", + "integrity": "sha512-jkbDCZoA1qv53mFcRHCinoCsgg8WH+M0YUO1awxmqWXRmCRws1wW0TsuSQ14UThih5Dxolgl+e+aGWxG58LMwg==", + "requires": { + "crypto-browserify": "3.12.0", + "eth-lib": "^0.2.8", + "ethereumjs-common": "^1.3.2", + "ethereumjs-tx": "^2.1.1", + "scrypt-js": "^3.0.1", + "underscore": "1.9.1", + "uuid": "3.3.2", + "web3-core": "1.2.9", + "web3-core-helpers": "1.2.9", + "web3-core-method": "1.2.9", + "web3-utils": "1.2.9" + }, + "dependencies": { + "eth-lib": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz", + "integrity": "sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw==", + "requires": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + } + } + } + }, + "web3-eth-ens": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.2.9.tgz", + "integrity": "sha512-kG4+ZRgZ8I1WYyOBGI8QVRHfUSbbJjvJAGA1AF/NOW7JXQ+x7gBGeJw6taDWJhSshMoEKWcsgvsiuoG4870YxQ==", + "requires": { + "content-hash": "^2.5.2", + "eth-ens-namehash": "2.0.8", + "underscore": "1.9.1", + "web3-core": "1.2.9", + "web3-core-helpers": "1.2.9", + "web3-core-promievent": "1.2.9", + "web3-eth-abi": "1.2.9", + "web3-eth-contract": "1.2.9", + "web3-utils": "1.2.9" + } + }, + "web3-eth-iban": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.2.9.tgz", + "integrity": "sha512-RtdVvJE0pyg9dHLy0GzDiqgnLnssSzfz/JYguhC1wsj9+Gnq1M6Diy3NixACWUAp6ty/zafyOaZnNQ+JuH9TjQ==", + "requires": { + "bn.js": "4.11.8", + "web3-utils": "1.2.9" + } + }, + "web3-eth-personal": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.2.9.tgz", + "integrity": "sha512-cFiNrktxZ1C/rIdJFzQTvFn3/0zcsR3a+Jf8Y3KxeQDHszQtosjLWptP7bsUmDwEh4hzh0Cy3KpOxlYBWB8bJQ==", + "requires": { + "@types/node": "^12.6.1", + "web3-core": "1.2.9", + "web3-core-helpers": "1.2.9", + "web3-core-method": "1.2.9", + "web3-net": "1.2.9", + "web3-utils": "1.2.9" + }, + "dependencies": { + "@types/node": { + "version": "12.12.47", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.47.tgz", + "integrity": "sha512-yzBInQFhdY8kaZmqoL2+3U5dSTMrKaYcb561VU+lDzAYvqt+2lojvBEy+hmpSNuXnPTx7m9+04CzWYOUqWME2A==" + } + } + }, + "web3-net": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.2.9.tgz", + "integrity": "sha512-d2mTn8jPlg+SI2hTj2b32Qan6DmtU9ap/IUlJTeQbZQSkTLf0u9suW8Vjwyr4poJYXTurdSshE7OZsPNn30/ZA==", + "requires": { + "web3-core": "1.2.9", + "web3-core-method": "1.2.9", + "web3-utils": "1.2.9" + } + }, + "web3-providers-http": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.2.9.tgz", + "integrity": "sha512-F956tCIj60Ttr0UvEHWFIhx+be3He8msoPzyA44/kfzzYoMAsCFRn5cf0zQG6al0znE75g6HlWVSN6s3yAh51A==", + "requires": { + "web3-core-helpers": "1.2.9", + "xhr2-cookies": "1.1.0" + } + }, + "web3-providers-ipc": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.2.9.tgz", + "integrity": "sha512-NQ8QnBleoHA2qTJlqoWu7EJAD/FR5uimf7Ielzk4Z2z+m+6UAuJdJMSuQNj+Umhz9L/Ys6vpS1vHx9NizFl+aQ==", + "requires": { + "oboe": "2.1.4", + "underscore": "1.9.1", + "web3-core-helpers": "1.2.9" + } + }, + "web3-providers-ws": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.2.9.tgz", + "integrity": "sha512-6+UpvINeI//dglZoAKStUXqxDOXJy6Iitv2z3dbgInG4zb8tkYl/VBDL80UjUg3ZvzWG0g7EKY2nRPEpON2TFA==", + "requires": { + "eventemitter3": "^4.0.0", + "underscore": "1.9.1", + "web3-core-helpers": "1.2.9", + "websocket": "^1.0.31" + }, + "dependencies": { + "eventemitter3": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", + "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==" + } + } + }, + "web3-shh": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.2.9.tgz", + "integrity": "sha512-PWa8b/EaxaMinFaxy6cV0i0EOi2M7a/ST+9k9nhyhCjVa2vzXuNoBNo2IUOmeZ0WP2UQB8ByJ2+p4htlJaDOjA==", + "requires": { + "web3-core": "1.2.9", + "web3-core-method": "1.2.9", + "web3-core-subscriptions": "1.2.9", + "web3-net": "1.2.9" + } + }, + "web3-utils": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.2.9.tgz", + "integrity": "sha512-9hcpuis3n/LxFzEVjwnVgvJzTirS2S9/MiNAa7l4WOEoywY+BSNwnRX4MuHnjkh9NY25B6QOjuNG6FNnSjTw1w==", + "requires": { + "bn.js": "4.11.8", + "eth-lib": "0.2.7", + "ethereum-bloom-filters": "^1.0.6", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "underscore": "1.9.1", + "utf8": "3.0.0" + }, + "dependencies": { + "eth-lib": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.7.tgz", + "integrity": "sha1-L5Pxex4jrsN1nNSj/iDBKGo/wco=", + "requires": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + } + } + } + }, + "websocket": { + "version": "1.0.31", + "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.31.tgz", + "integrity": "sha512-VAouplvGKPiKFDTeCCO65vYHsyay8DqoBSlzIO3fayrfOgU94lQN5a1uWVnFrMLceTJw/+fQXR5PGbUVRaHshQ==", + "requires": { + "debug": "^2.2.0", + "es5-ext": "^0.10.50", + "nan": "^2.14.0", + "typedarray-to-buffer": "^3.1.5", + "yaeti": "^0.0.6" + } + } + } + }, + "web3-bzz": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.2.2.tgz", + "integrity": "sha512-b1O2ObsqUN1lJxmFSjvnEC4TsaCbmh7Owj3IAIWTKqL9qhVgx7Qsu5O9cD13pBiSPNZJ68uJPaKq380QB4NWeA==", + "dev": true, + "requires": { + "@types/node": "^10.12.18", + "got": "9.6.0", + "swarm-js": "0.1.39", + "underscore": "1.9.1" + }, + "dependencies": { + "@types/node": { + "version": "10.17.26", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.26.tgz", + "integrity": "sha512-myMwkO2Cr82kirHY8uknNRHEVtn0wV3DTQfkrjx17jmkstDRZ24gNUdl8AHXVyVclTYI/bNjgTPTAWvWLqXqkw==", + "dev": true + } + } + }, + "web3-core": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.2.2.tgz", + "integrity": "sha512-miHAX3qUgxV+KYfaOY93Hlc3kLW2j5fH8FJy6kSxAv+d4d5aH0wwrU2IIoJylQdT+FeenQ38sgsCnFu9iZ1hCQ==", + "dev": true, + "requires": { + "@types/bn.js": "^4.11.4", + "@types/node": "^12.6.1", + "web3-core-helpers": "1.2.2", + "web3-core-method": "1.2.2", + "web3-core-requestmanager": "1.2.2", + "web3-utils": "1.2.2" + }, + "dependencies": { + "@types/node": { + "version": "12.12.47", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.47.tgz", + "integrity": "sha512-yzBInQFhdY8kaZmqoL2+3U5dSTMrKaYcb561VU+lDzAYvqt+2lojvBEy+hmpSNuXnPTx7m9+04CzWYOUqWME2A==", + "dev": true + }, + "web3-core-helpers": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.2.tgz", + "integrity": "sha512-HJrRsIGgZa1jGUIhvGz4S5Yh6wtOIo/TMIsSLe+Xay+KVnbseJpPprDI5W3s7H2ODhMQTbogmmUFquZweW2ImQ==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-eth-iban": "1.2.2", + "web3-utils": "1.2.2" + } + } + } + }, + "web3-core-helpers": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.9.tgz", + "integrity": "sha512-t0WAG3orLCE3lqi77ZoSRNFok3VQWZXTniZigDQjyOJYMAX7BU3F3js8HKbjVnAxlX3tiKoDxI0KBk9F3AxYuw==", + "requires": { + "underscore": "1.9.1", + "web3-eth-iban": "1.2.9", + "web3-utils": "1.2.9" + }, + "dependencies": { + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" + }, + "eth-lib": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.7.tgz", + "integrity": "sha1-L5Pxex4jrsN1nNSj/iDBKGo/wco=", + "requires": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + } + }, + "web3-eth-iban": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.2.9.tgz", + "integrity": "sha512-RtdVvJE0pyg9dHLy0GzDiqgnLnssSzfz/JYguhC1wsj9+Gnq1M6Diy3NixACWUAp6ty/zafyOaZnNQ+JuH9TjQ==", + "requires": { + "bn.js": "4.11.8", + "web3-utils": "1.2.9" + } + }, + "web3-utils": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.2.9.tgz", + "integrity": "sha512-9hcpuis3n/LxFzEVjwnVgvJzTirS2S9/MiNAa7l4WOEoywY+BSNwnRX4MuHnjkh9NY25B6QOjuNG6FNnSjTw1w==", + "requires": { + "bn.js": "4.11.8", + "eth-lib": "0.2.7", + "ethereum-bloom-filters": "^1.0.6", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "underscore": "1.9.1", + "utf8": "3.0.0" + } + } + } + }, + "web3-core-method": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.2.2.tgz", + "integrity": "sha512-szR4fDSBxNHaF1DFqE+j6sFR/afv9Aa36OW93saHZnrh+iXSrYeUUDfugeNcRlugEKeUCkd4CZylfgbK2SKYJA==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-core-helpers": "1.2.2", + "web3-core-promievent": "1.2.2", + "web3-core-subscriptions": "1.2.2", + "web3-utils": "1.2.2" + }, + "dependencies": { + "web3-core-helpers": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.2.tgz", + "integrity": "sha512-HJrRsIGgZa1jGUIhvGz4S5Yh6wtOIo/TMIsSLe+Xay+KVnbseJpPprDI5W3s7H2ODhMQTbogmmUFquZweW2ImQ==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-eth-iban": "1.2.2", + "web3-utils": "1.2.2" + } + } + } + }, + "web3-core-promievent": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.2.2.tgz", + "integrity": "sha512-tKvYeT8bkUfKABcQswK6/X79blKTKYGk949urZKcLvLDEaWrM3uuzDwdQT3BNKzQ3vIvTggFPX9BwYh0F1WwqQ==", + "dev": true, + "requires": { + "any-promise": "1.3.0", + "eventemitter3": "3.1.2" + } + }, + "web3-core-requestmanager": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.2.2.tgz", + "integrity": "sha512-a+gSbiBRHtHvkp78U2bsntMGYGF2eCb6219aMufuZWeAZGXJ63Wc2321PCbA8hF9cQrZI4EoZ4kVLRI4OF15Hw==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-core-helpers": "1.2.2", + "web3-providers-http": "1.2.2", + "web3-providers-ipc": "1.2.2", + "web3-providers-ws": "1.2.2" + }, + "dependencies": { + "web3-core-helpers": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.2.tgz", + "integrity": "sha512-HJrRsIGgZa1jGUIhvGz4S5Yh6wtOIo/TMIsSLe+Xay+KVnbseJpPprDI5W3s7H2ODhMQTbogmmUFquZweW2ImQ==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-eth-iban": "1.2.2", + "web3-utils": "1.2.2" + } + } + } + }, + "web3-core-subscriptions": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.2.2.tgz", + "integrity": "sha512-QbTgigNuT4eicAWWr7ahVpJyM8GbICsR1Ys9mJqzBEwpqS+RXTRVSkwZ2IsxO+iqv6liMNwGregbJLq4urMFcQ==", + "dev": true, + "requires": { + "eventemitter3": "3.1.2", + "underscore": "1.9.1", + "web3-core-helpers": "1.2.2" + }, + "dependencies": { + "web3-core-helpers": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.2.tgz", + "integrity": "sha512-HJrRsIGgZa1jGUIhvGz4S5Yh6wtOIo/TMIsSLe+Xay+KVnbseJpPprDI5W3s7H2ODhMQTbogmmUFquZweW2ImQ==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-eth-iban": "1.2.2", + "web3-utils": "1.2.2" + } + } + } + }, + "web3-eth": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.2.2.tgz", + "integrity": "sha512-UXpC74mBQvZzd4b+baD4Ocp7g+BlwxhBHumy9seyE/LMIcMlePXwCKzxve9yReNpjaU16Mmyya6ZYlyiKKV8UA==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-core": "1.2.2", + "web3-core-helpers": "1.2.2", + "web3-core-method": "1.2.2", + "web3-core-subscriptions": "1.2.2", + "web3-eth-abi": "1.2.2", + "web3-eth-accounts": "1.2.2", + "web3-eth-contract": "1.2.2", + "web3-eth-ens": "1.2.2", + "web3-eth-iban": "1.2.2", + "web3-eth-personal": "1.2.2", + "web3-net": "1.2.2", + "web3-utils": "1.2.2" + }, + "dependencies": { + "web3-core-helpers": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.2.tgz", + "integrity": "sha512-HJrRsIGgZa1jGUIhvGz4S5Yh6wtOIo/TMIsSLe+Xay+KVnbseJpPprDI5W3s7H2ODhMQTbogmmUFquZweW2ImQ==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-eth-iban": "1.2.2", + "web3-utils": "1.2.2" + } + }, + "web3-eth-contract": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.2.2.tgz", + "integrity": "sha512-EKT2yVFws3FEdotDQoNsXTYL798+ogJqR2//CaGwx3p0/RvQIgfzEwp8nbgA6dMxCsn9KOQi7OtklzpnJMkjtA==", + "dev": true, + "requires": { + "@types/bn.js": "^4.11.4", + "underscore": "1.9.1", + "web3-core": "1.2.2", + "web3-core-helpers": "1.2.2", + "web3-core-method": "1.2.2", + "web3-core-promievent": "1.2.2", + "web3-core-subscriptions": "1.2.2", + "web3-eth-abi": "1.2.2", + "web3-utils": "1.2.2" + } + } + } + }, + "web3-eth-abi": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.2.2.tgz", + "integrity": "sha512-Yn/ZMgoOLxhTVxIYtPJ0eS6pnAnkTAaJgUJh1JhZS4ekzgswMfEYXOwpMaD5eiqPJLpuxmZFnXnBZlnQ1JMXsw==", + "dev": true, + "requires": { + "ethers": "4.0.0-beta.3", + "underscore": "1.9.1", + "web3-utils": "1.2.2" + }, + "dependencies": { + "@types/node": { + "version": "10.17.26", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.26.tgz", + "integrity": "sha512-myMwkO2Cr82kirHY8uknNRHEVtn0wV3DTQfkrjx17jmkstDRZ24gNUdl8AHXVyVclTYI/bNjgTPTAWvWLqXqkw==", + "dev": true + }, + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + }, + "elliptic": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.3.3.tgz", + "integrity": "sha1-VILZZG1UvLif19mU/J4ulWiHbj8=", + "dev": true, + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "inherits": "^2.0.1" + } + }, + "ethers": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.0-beta.3.tgz", + "integrity": "sha512-YYPogooSknTwvHg3+Mv71gM/3Wcrx+ZpCzarBj3mqs9njjRkrOo2/eufzhHloOCo3JSoNI4TQJJ6yU5ABm3Uog==", + "dev": true, + "requires": { + "@types/node": "^10.3.2", + "aes-js": "3.0.0", + "bn.js": "^4.4.0", + "elliptic": "6.3.3", + "hash.js": "1.1.3", + "js-sha3": "0.5.7", + "scrypt-js": "2.0.3", + "setimmediate": "1.0.4", + "uuid": "2.0.1", + "xmlhttprequest": "1.8.0" + } + }, + "hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.0" + } + }, + "scrypt-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.3.tgz", + "integrity": "sha1-uwBAvgMEPamgEqLOqfyfhSz8h9Q=", + "dev": true + } + } + }, + "web3-eth-accounts": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.2.2.tgz", + "integrity": "sha512-KzHOEyXOEZ13ZOkWN3skZKqSo5f4Z1ogPFNn9uZbKCz+kSp+gCAEKxyfbOsB/JMAp5h7o7pb6eYsPCUBJmFFiA==", + "dev": true, + "requires": { + "any-promise": "1.3.0", + "crypto-browserify": "3.12.0", + "eth-lib": "0.2.7", + "ethereumjs-common": "^1.3.2", + "ethereumjs-tx": "^2.1.1", + "scrypt-shim": "github:web3-js/scrypt-shim", + "underscore": "1.9.1", + "uuid": "3.3.2", + "web3-core": "1.2.2", + "web3-core-helpers": "1.2.2", + "web3-core-method": "1.2.2", + "web3-utils": "1.2.2" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + }, + "eth-lib": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.7.tgz", + "integrity": "sha1-L5Pxex4jrsN1nNSj/iDBKGo/wco=", + "dev": true, + "requires": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + } + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true + }, + "web3-core-helpers": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.2.tgz", + "integrity": "sha512-HJrRsIGgZa1jGUIhvGz4S5Yh6wtOIo/TMIsSLe+Xay+KVnbseJpPprDI5W3s7H2ODhMQTbogmmUFquZweW2ImQ==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-eth-iban": "1.2.2", + "web3-utils": "1.2.2" + } + } + } + }, + "web3-eth-contract": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.2.9.tgz", + "integrity": "sha512-PYMvJf7EG/HyssUZa+pXrc8IB06K/YFfWYyW4R7ed3sab+9wWUys1TlWxBCBuiBXOokSAyM6H6P6/cKEx8FT8Q==", + "requires": { + "@types/bn.js": "^4.11.4", + "underscore": "1.9.1", + "web3-core": "1.2.9", + "web3-core-helpers": "1.2.9", + "web3-core-method": "1.2.9", + "web3-core-promievent": "1.2.9", + "web3-core-subscriptions": "1.2.9", + "web3-eth-abi": "1.2.9", + "web3-utils": "1.2.9" + }, + "dependencies": { + "@types/node": { + "version": "12.12.47", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.47.tgz", + "integrity": "sha512-yzBInQFhdY8kaZmqoL2+3U5dSTMrKaYcb561VU+lDzAYvqt+2lojvBEy+hmpSNuXnPTx7m9+04CzWYOUqWME2A==" + }, + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "eth-lib": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.7.tgz", + "integrity": "sha1-L5Pxex4jrsN1nNSj/iDBKGo/wco=", + "requires": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "web3-core": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.2.9.tgz", + "integrity": "sha512-fSYv21IP658Ty2wAuU9iqmW7V+75DOYMVZsDH/c14jcF/1VXnedOcxzxSj3vArsCvXZNe6XC5/wAuGZyQwR9RA==", + "requires": { + "@types/bn.js": "^4.11.4", + "@types/node": "^12.6.1", + "bignumber.js": "^9.0.0", + "web3-core-helpers": "1.2.9", + "web3-core-method": "1.2.9", + "web3-core-requestmanager": "1.2.9", + "web3-utils": "1.2.9" + } + }, + "web3-core-method": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.2.9.tgz", + "integrity": "sha512-bjsIoqP3gs7A/gP8+QeLUCyOKJ8bopteCSNbCX36Pxk6TYfYWNuC6hP+2GzUuqdP3xaZNe+XEElQFUNpR3oyAg==", + "requires": { + "@ethersproject/transactions": "^5.0.0-beta.135", + "underscore": "1.9.1", + "web3-core-helpers": "1.2.9", + "web3-core-promievent": "1.2.9", + "web3-core-subscriptions": "1.2.9", + "web3-utils": "1.2.9" + } + }, + "web3-core-promievent": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.2.9.tgz", + "integrity": "sha512-0eAUA2zjgXTleSrnc1wdoKQPPIHU6KHf4fAscu4W9kKrR+mqP1KsjYrxY9wUyjNnXxfQ+5M29ipvbiaK8OqdOw==", + "requires": { + "eventemitter3": "3.1.2" + } + }, + "web3-core-requestmanager": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.2.9.tgz", + "integrity": "sha512-1PwKV2m46ALUnIN5VPPgjOj8yMLJhhqZYvYJE34hTN5SErOkwhzx5zScvo5MN7v7KyQGFnpVCZKKGCiEnDmtFA==", + "requires": { + "underscore": "1.9.1", + "web3-core-helpers": "1.2.9", + "web3-providers-http": "1.2.9", + "web3-providers-ipc": "1.2.9", + "web3-providers-ws": "1.2.9" + } + }, + "web3-core-subscriptions": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.2.9.tgz", + "integrity": "sha512-Y48TvXPSPxEM33OmXjGVDMzTd0j8X0t2+sDw66haeBS8eYnrEzasWuBZZXDq0zNUsqyxItgBGDn+cszkgEnFqg==", + "requires": { + "eventemitter3": "3.1.2", + "underscore": "1.9.1", + "web3-core-helpers": "1.2.9" + } + }, + "web3-eth-abi": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.2.9.tgz", + "integrity": "sha512-3YwUYbh/DMfDbhMWEebAdjSd5bj3ZQieOjLzWFHU23CaLEqT34sUix1lba+hgUH/EN6A7bKAuKOhR3p0OvTn7Q==", + "requires": { + "@ethersproject/abi": "5.0.0-beta.153", + "underscore": "1.9.1", + "web3-utils": "1.2.9" + } + }, + "web3-providers-http": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.2.9.tgz", + "integrity": "sha512-F956tCIj60Ttr0UvEHWFIhx+be3He8msoPzyA44/kfzzYoMAsCFRn5cf0zQG6al0znE75g6HlWVSN6s3yAh51A==", + "requires": { + "web3-core-helpers": "1.2.9", + "xhr2-cookies": "1.1.0" + } + }, + "web3-providers-ipc": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.2.9.tgz", + "integrity": "sha512-NQ8QnBleoHA2qTJlqoWu7EJAD/FR5uimf7Ielzk4Z2z+m+6UAuJdJMSuQNj+Umhz9L/Ys6vpS1vHx9NizFl+aQ==", + "requires": { + "oboe": "2.1.4", + "underscore": "1.9.1", + "web3-core-helpers": "1.2.9" + } + }, + "web3-providers-ws": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.2.9.tgz", + "integrity": "sha512-6+UpvINeI//dglZoAKStUXqxDOXJy6Iitv2z3dbgInG4zb8tkYl/VBDL80UjUg3ZvzWG0g7EKY2nRPEpON2TFA==", + "requires": { + "eventemitter3": "^4.0.0", + "underscore": "1.9.1", + "web3-core-helpers": "1.2.9", + "websocket": "^1.0.31" + }, + "dependencies": { + "eventemitter3": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", + "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==" + } + } + }, + "web3-utils": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.2.9.tgz", + "integrity": "sha512-9hcpuis3n/LxFzEVjwnVgvJzTirS2S9/MiNAa7l4WOEoywY+BSNwnRX4MuHnjkh9NY25B6QOjuNG6FNnSjTw1w==", + "requires": { + "bn.js": "4.11.8", + "eth-lib": "0.2.7", + "ethereum-bloom-filters": "^1.0.6", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "underscore": "1.9.1", + "utf8": "3.0.0" + } + }, + "websocket": { + "version": "1.0.31", + "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.31.tgz", + "integrity": "sha512-VAouplvGKPiKFDTeCCO65vYHsyay8DqoBSlzIO3fayrfOgU94lQN5a1uWVnFrMLceTJw/+fQXR5PGbUVRaHshQ==", + "requires": { + "debug": "^2.2.0", + "es5-ext": "^0.10.50", + "nan": "^2.14.0", + "typedarray-to-buffer": "^3.1.5", + "yaeti": "^0.0.6" + } + } + } + }, + "web3-eth-ens": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.2.2.tgz", + "integrity": "sha512-CFjkr2HnuyMoMFBoNUWojyguD4Ef+NkyovcnUc/iAb9GP4LHohKrODG4pl76R5u61TkJGobC2ij6TyibtsyVYg==", + "dev": true, + "requires": { + "eth-ens-namehash": "2.0.8", + "underscore": "1.9.1", + "web3-core": "1.2.2", + "web3-core-helpers": "1.2.2", + "web3-core-promievent": "1.2.2", + "web3-eth-abi": "1.2.2", + "web3-eth-contract": "1.2.2", + "web3-utils": "1.2.2" + }, + "dependencies": { + "web3-core-helpers": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.2.tgz", + "integrity": "sha512-HJrRsIGgZa1jGUIhvGz4S5Yh6wtOIo/TMIsSLe+Xay+KVnbseJpPprDI5W3s7H2ODhMQTbogmmUFquZweW2ImQ==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-eth-iban": "1.2.2", + "web3-utils": "1.2.2" + } + }, + "web3-eth-contract": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.2.2.tgz", + "integrity": "sha512-EKT2yVFws3FEdotDQoNsXTYL798+ogJqR2//CaGwx3p0/RvQIgfzEwp8nbgA6dMxCsn9KOQi7OtklzpnJMkjtA==", + "dev": true, + "requires": { + "@types/bn.js": "^4.11.4", + "underscore": "1.9.1", + "web3-core": "1.2.2", + "web3-core-helpers": "1.2.2", + "web3-core-method": "1.2.2", + "web3-core-promievent": "1.2.2", + "web3-core-subscriptions": "1.2.2", + "web3-eth-abi": "1.2.2", + "web3-utils": "1.2.2" + } + } + } + }, + "web3-eth-iban": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.2.2.tgz", + "integrity": "sha512-gxKXBoUhaTFHr0vJB/5sd4i8ejF/7gIsbM/VvemHT3tF5smnmY6hcwSMmn7sl5Gs+83XVb/BngnnGkf+I/rsrQ==", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "web3-utils": "1.2.2" + }, + "dependencies": { + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "dev": true + } + } + }, + "web3-eth-personal": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.2.2.tgz", + "integrity": "sha512-4w+GLvTlFqW3+q4xDUXvCEMU7kRZ+xm/iJC8gm1Li1nXxwwFbs+Y+KBK6ZYtoN1qqAnHR+plYpIoVo27ixI5Rg==", + "dev": true, + "requires": { + "@types/node": "^12.6.1", + "web3-core": "1.2.2", + "web3-core-helpers": "1.2.2", + "web3-core-method": "1.2.2", + "web3-net": "1.2.2", + "web3-utils": "1.2.2" + }, + "dependencies": { + "@types/node": { + "version": "12.12.47", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.47.tgz", + "integrity": "sha512-yzBInQFhdY8kaZmqoL2+3U5dSTMrKaYcb561VU+lDzAYvqt+2lojvBEy+hmpSNuXnPTx7m9+04CzWYOUqWME2A==", + "dev": true + }, + "web3-core-helpers": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.2.tgz", + "integrity": "sha512-HJrRsIGgZa1jGUIhvGz4S5Yh6wtOIo/TMIsSLe+Xay+KVnbseJpPprDI5W3s7H2ODhMQTbogmmUFquZweW2ImQ==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-eth-iban": "1.2.2", + "web3-utils": "1.2.2" + } + } + } + }, + "web3-net": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.2.2.tgz", + "integrity": "sha512-K07j2DXq0x4UOJgae65rWZKraOznhk8v5EGSTdFqASTx7vWE/m+NqBijBYGEsQY1lSMlVaAY9UEQlcXK5HzXTw==", + "dev": true, + "requires": { + "web3-core": "1.2.2", + "web3-core-method": "1.2.2", + "web3-utils": "1.2.2" + } + }, + "web3-providers-http": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.2.2.tgz", + "integrity": "sha512-BNZ7Hguy3eBszsarH5gqr9SIZNvqk9eKwqwmGH1LQS1FL3NdoOn7tgPPdddrXec4fL94CwgNk4rCU+OjjZRNDg==", + "dev": true, + "requires": { + "web3-core-helpers": "1.2.2", + "xhr2-cookies": "1.1.0" + }, + "dependencies": { + "web3-core-helpers": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.2.tgz", + "integrity": "sha512-HJrRsIGgZa1jGUIhvGz4S5Yh6wtOIo/TMIsSLe+Xay+KVnbseJpPprDI5W3s7H2ODhMQTbogmmUFquZweW2ImQ==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-eth-iban": "1.2.2", + "web3-utils": "1.2.2" + } + } + } + }, + "web3-providers-ipc": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.2.2.tgz", + "integrity": "sha512-t97w3zi5Kn/LEWGA6D9qxoO0LBOG+lK2FjlEdCwDQatffB/+vYrzZ/CLYVQSoyFZAlsDoBasVoYSWZK1n39aHA==", + "dev": true, + "requires": { + "oboe": "2.1.4", + "underscore": "1.9.1", + "web3-core-helpers": "1.2.2" + }, + "dependencies": { + "web3-core-helpers": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.2.tgz", + "integrity": "sha512-HJrRsIGgZa1jGUIhvGz4S5Yh6wtOIo/TMIsSLe+Xay+KVnbseJpPprDI5W3s7H2ODhMQTbogmmUFquZweW2ImQ==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-eth-iban": "1.2.2", + "web3-utils": "1.2.2" + } + } + } + }, + "web3-providers-ws": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.2.2.tgz", + "integrity": "sha512-Wb1mrWTGMTXOpJkL0yGvL/WYLt8fUIXx8k/l52QB2IiKzvyd42dTWn4+j8IKXGSYYzOm7NMqv6nhA5VDk12VfA==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-core-helpers": "1.2.2", + "websocket": "github:web3-js/WebSocket-Node#polyfill/globalThis" + }, + "dependencies": { + "web3-core-helpers": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.2.tgz", + "integrity": "sha512-HJrRsIGgZa1jGUIhvGz4S5Yh6wtOIo/TMIsSLe+Xay+KVnbseJpPprDI5W3s7H2ODhMQTbogmmUFquZweW2ImQ==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-eth-iban": "1.2.2", + "web3-utils": "1.2.2" + } + } + } + }, + "web3-shh": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.2.2.tgz", + "integrity": "sha512-og258NPhlBn8yYrDWjoWBBb6zo1OlBgoWGT+LL5/LPqRbjPe09hlOYHgscAAr9zZGtohTOty7RrxYw6Z6oDWCg==", + "dev": true, + "requires": { + "web3-core": "1.2.2", + "web3-core-method": "1.2.2", + "web3-core-subscriptions": "1.2.2", + "web3-net": "1.2.2" + } + }, + "web3-utils": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.2.2.tgz", + "integrity": "sha512-joF+s3243TY5cL7Z7y4h1JsJpUCf/kmFmj+eJar7Y2yNIGVcW961VyrAms75tjUysSuHaUQ3eQXjBEUJueT52A==", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "eth-lib": "0.2.7", + "ethereum-bloom-filters": "^1.0.6", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "underscore": "1.9.1", + "utf8": "3.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "dev": true + }, + "eth-lib": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.7.tgz", + "integrity": "sha1-L5Pxex4jrsN1nNSj/iDBKGo/wco=", + "dev": true, + "requires": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + } + } + } + }, + "websocket": { + "version": "github:web3-js/WebSocket-Node#ef5ea2f41daf4a2113b80c9223df884b4d56c400", + "from": "github:web3-js/WebSocket-Node#polyfill/globalThis", + "dev": true, + "requires": { + "debug": "^2.2.0", + "es5-ext": "^0.10.50", + "nan": "^2.14.0", + "typedarray-to-buffer": "^3.1.5", + "yaeti": "^0.0.6" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "which-typed-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.2.tgz", + "integrity": "sha512-KT6okrd1tE6JdZAy3o2VhMoYPh3+J6EMZLyrxBQsZflI1QCZIxMrIYLkosd8Twf+YfknVIHmYQPgJt238p8dnQ==", + "requires": { + "available-typed-arrays": "^1.0.2", + "es-abstract": "^1.17.5", + "foreach": "^2.0.5", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.1", + "is-typed-array": "^1.1.3" + } + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "requires": { + "string-width": "^1.0.2 || 2" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "xhr": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.5.0.tgz", + "integrity": "sha512-4nlO/14t3BNUZRXIXfXe+3N6w3s1KoxcJUUURctd64BLRe67E4gRwp4PjywtDY72fXpZ1y6Ch0VZQRY/gMPzzQ==", + "requires": { + "global": "~4.3.0", + "is-function": "^1.0.1", + "parse-headers": "^2.0.0", + "xtend": "^4.0.0" + } + }, + "xhr-request": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xhr-request/-/xhr-request-1.1.0.tgz", + "integrity": "sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA==", + "requires": { + "buffer-to-arraybuffer": "^0.0.5", + "object-assign": "^4.1.1", + "query-string": "^5.0.1", + "simple-get": "^2.7.0", + "timed-out": "^4.0.1", + "url-set-query": "^1.0.0", + "xhr": "^2.0.4" + } + }, + "xhr-request-promise": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz", + "integrity": "sha512-YUBytBsuwgitWtdRzXDDkWAXzhdGB8bYm0sSzMPZT7Z2MBjMSTHFsyCT1yCRATY+XC69DUrQraRAEgcoCRaIPg==", + "requires": { + "xhr-request": "^1.1.0" + } + }, + "xhr2-cookies": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz", + "integrity": "sha1-fXdEnQmZGX8VXLc7I99yUF7YnUg=", + "requires": { + "cookiejar": "^2.1.1" + } + }, + "xmlhttprequest": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", + "integrity": "sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw=" + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" + }, + "yaeti": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=" + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "requires": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + } + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..123c39c --- /dev/null +++ b/package.json @@ -0,0 +1,55 @@ +{ + "name": "dodo", + "version": "1.0.0", + "description": "a kind of bird", + "main": "index.js", + "author": "dodo breeder", + "license": "Apache-2.0", + "keywords": [ + "dodo", + "ethereum", + "lmm" + ], + "scripts": { + "prettier": "prettier --write **/*.sol", + "migrate": "truffle migrate", + "compile": "truffle compile", + "coverage": "NETWORK_ID=1002 RPC_NODE_URI=http://127.0.0.1:6545 COVERAGE=true truffle run coverage", + "test": "truffle compile && truffle test", + "test_only": "truffle test", + "deploy": "truffle migrate --network=$NETWORK --reset", + "deploy_kovan": "NETWORK=kovan npm run deploy", + "deploy_mainnet": "NETWORK=mainnet npm run deploy", + "deploy_test": "NETWORK=development npm run deploy", + "node": "ganache-cli --port 8545 -l 0x1fffffffffffff -i 5777 -g 1 --allowUnlimitedContractSize" + }, + "dependencies": { + "@types/chai": "^4.2.11", + "@types/es6-promisify": "^6.0.0", + "@types/mocha": "^7.0.2", + "assert": "^2.0.0", + "babel-cli": "^6.26.0", + "babel-eslint": "^10.1.0", + "bignumber.js": "^9.0.0", + "chai": "^4.2.0", + "chai-bignumber": "^3.0.0", + "debug": "^4.1.1", + "dotenv-flow": "^3.1.0", + "es6-promisify": "^6.1.1", + "ethereumjs-util": "^7.0.2", + "lodash": "^4.17.15", + "mocha": "^7.2.0", + "truffle-hdwallet-provider": "^1.0.17", + "ts-node": "^8.10.2", + "typescript": "^3.9.5", + "web3": "^1.2.8", + "web3-core-helpers": "^1.2.8", + "web3-eth-contract": "^1.2.8" + }, + "devDependencies": { + "ganache-cli": "^6.9.1", + "prettier": "^2.0.5", + "prettier-plugin-solidity": "^1.0.0-alpha.52", + "solidity-coverage": "^0.7.7" + } +} diff --git a/test/Admin.test.ts b/test/Admin.test.ts new file mode 100644 index 0000000..f559996 --- /dev/null +++ b/test/Admin.test.ts @@ -0,0 +1,340 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +import { DODOContext, getDODOContext } from './utils/Context'; +import { decimalStr } from './utils/Converter'; +// import BigNumber from "bignumber.js"; +import * as assert from "assert" + +let lp1: string +let lp2: string +let trader: string +let tempAccount: string + +async function init(ctx: DODOContext): Promise { + await ctx.setOraclePrice(decimalStr("100")) + tempAccount = ctx.spareAccounts[5] + lp1 = ctx.spareAccounts[0] + lp2 = ctx.spareAccounts[1] + trader = ctx.spareAccounts[2] + await ctx.mintTestToken(lp1, decimalStr("100"), decimalStr("10000")) + await ctx.mintTestToken(lp2, decimalStr("100"), decimalStr("10000")) + await ctx.mintTestToken(trader, decimalStr("100"), decimalStr("10000")) + await ctx.approveDODO(lp1) + await ctx.approveDODO(lp2) + await ctx.approveDODO(trader) +} + +describe("Admin", () => { + + let snapshotId: string + let ctx: DODOContext + + before(async () => { + ctx = await getDODOContext() + await init(ctx); + }) + + beforeEach(async () => { + snapshotId = await ctx.EVM.snapshot(); + }); + + afterEach(async () => { + await ctx.EVM.reset(snapshotId) + }); + + describe("Settings", () => { + it("set oracle", async () => { + await ctx.DODO.methods.setOracle(tempAccount).send(ctx.sendParam(ctx.Deployer)) + assert.equal(await ctx.DODO.methods._ORACLE_().call(), tempAccount) + }) + + it("set suprevisor", async () => { + await ctx.DODO.methods.setSupervisor(tempAccount).send(ctx.sendParam(ctx.Deployer)) + assert.equal(await ctx.DODO.methods._SUPERVISOR_().call(), tempAccount) + }) + + it("set maintainer", async () => { + await ctx.DODO.methods.setMaintainer(tempAccount).send(ctx.sendParam(ctx.Deployer)) + assert.equal(await ctx.DODO.methods._MAINTAINER_().call(), tempAccount) + }) + + it("set liquidity provider fee rate", async () => { + await ctx.DODO.methods.setLiquidityProviderFeeRate(decimalStr("0.01")).send(ctx.sendParam(ctx.Deployer)) + assert.equal(await ctx.DODO.methods._LP_FEE_RATE_().call(), decimalStr("0.01")) + }) + + it("set maintainer fee rate", async () => { + await ctx.DODO.methods.setMaintainerFeeRate(decimalStr("0.01")).send(ctx.sendParam(ctx.Deployer)) + assert.equal(await ctx.DODO.methods._MT_FEE_RATE_().call(), decimalStr("0.01")) + }) + + it("set k", async () => { + await ctx.DODO.methods.setK(decimalStr("0.2")).send(ctx.sendParam(ctx.Deployer)) + assert.equal(await ctx.DODO.methods._K_().call(), decimalStr("0.2")) + }) + + it("set gas price limit", async () => { + await ctx.DODO.methods.setGasPriceLimit(decimalStr("100")).send(ctx.sendParam(ctx.Deployer)) + assert.equal(await ctx.DODO.methods._GAS_PRICE_LIMIT_().call(), decimalStr("100")) + }) + }) + + describe("Controls", () => { + it("control flow", async () => { + await ctx.DODO.methods.disableBaseDeposit().send(ctx.sendParam(ctx.Supervisor)) + await assert.rejects( + ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)), + /DEPOSIT_BASE_NOT_ALLOWED/ + ) + + await ctx.DODO.methods.enableBaseDeposit().send(ctx.sendParam(ctx.Deployer)) + await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) + assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), decimalStr("10")) + + await ctx.DODO.methods.disableQuoteDeposit().send(ctx.sendParam(ctx.Supervisor)) + await assert.rejects( + ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)), + /DEPOSIT_QUOTE_NOT_ALLOWED/ + ) + + await ctx.DODO.methods.enableQuoteDeposit().send(ctx.sendParam(ctx.Deployer)) + await ctx.DODO.methods.depositQuote(decimalStr("10")).send(ctx.sendParam(lp1)) + assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), decimalStr("10")) + + await ctx.DODO.methods.disableTrading().send(ctx.sendParam(ctx.Supervisor)) + await assert.rejects( + ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("200")).send(ctx.sendParam(trader)), + /TRADE_NOT_ALLOWED/ + ) + + await ctx.DODO.methods.enableTrading().send(ctx.sendParam(ctx.Deployer)) + await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("200")).send(ctx.sendParam(trader)) + assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("101")) + }) + + it("control flow premission", async () => { + await assert.rejects( + ctx.DODO.methods.setGasPriceLimit("1").send(ctx.sendParam(trader)), + /NOT_SUPERVISOR_OR_OWNER/ + ) + await assert.rejects( + ctx.DODO.methods.disableTrading().send(ctx.sendParam(trader)), + /NOT_SUPERVISOR_OR_OWNER/ + ) + await assert.rejects( + ctx.DODO.methods.disableQuoteDeposit().send(ctx.sendParam(trader)), + /NOT_SUPERVISOR_OR_OWNER/ + ) + await assert.rejects( + ctx.DODO.methods.disableBaseDeposit().send(ctx.sendParam(trader)), + /NOT_SUPERVISOR_OR_OWNER/ + ) + + await assert.rejects( + ctx.DODO.methods.setOracle(trader).send(ctx.sendParam(trader)), + /NOT_OWNER/ + ) + await assert.rejects( + ctx.DODO.methods.setSupervisor(trader).send(ctx.sendParam(trader)), + /NOT_OWNER/ + ) + await assert.rejects( + ctx.DODO.methods.setMaintainer(trader).send(ctx.sendParam(trader)), + /NOT_OWNER/ + ) + await assert.rejects( + ctx.DODO.methods.setLiquidityProviderFeeRate(decimalStr("0.1")).send(ctx.sendParam(trader)), + /NOT_OWNER/ + ) + await assert.rejects( + ctx.DODO.methods.setMaintainerFeeRate(decimalStr("0.1")).send(ctx.sendParam(trader)), + /NOT_OWNER/ + ) + await assert.rejects( + ctx.DODO.methods.setK(decimalStr("0.1")).send(ctx.sendParam(trader)), + /NOT_OWNER/ + ) + + await assert.rejects( + ctx.DODO.methods.enableTrading().send(ctx.sendParam(trader)), + /NOT_OWNER/ + ) + await assert.rejects( + ctx.DODO.methods.enableQuoteDeposit().send(ctx.sendParam(trader)), + /NOT_OWNER/ + ) + await assert.rejects( + ctx.DODO.methods.enableBaseDeposit().send(ctx.sendParam(trader)), + /NOT_OWNER/ + ) + }) + }) + + describe("Final settlement", () => { + it("final settlement when R is ONE", async () => { + await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) + + await ctx.DODO.methods.finalSettlement().send(ctx.sendParam(ctx.Deployer)) + + await ctx.DODO.methods.claim().send(ctx.sendParam(lp1)) + await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp1)) + await ctx.DODO.methods.withdrawAllQuote().send(ctx.sendParam(lp1)) + + assert.equal(await ctx.BASE.methods.balanceOf(lp1).call(), decimalStr("100")) + assert.equal(await ctx.QUOTE.methods.balanceOf(lp1).call(), decimalStr("10000")) + }) + + it("final settlement when R is ABOVE ONE", async () => { + await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) + + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.finalSettlement().send(ctx.sendParam(ctx.Deployer)) + assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0") + + await ctx.DODO.methods.claim().send(ctx.sendParam(lp1)) + assert.equal(await ctx.BASE.methods.balanceOf(lp1).call(), decimalStr("90")) + assert.equal(await ctx.QUOTE.methods.balanceOf(lp1).call(), "9551951805416248746110") + await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp1)) + await ctx.DODO.methods.withdrawAllQuote().send(ctx.sendParam(lp1)) + assert.equal(await ctx.BASE.methods.balanceOf(lp1).call(), decimalStr("94.995")) + assert.equal(await ctx.QUOTE.methods.balanceOf(lp1).call(), "10551951805416248746110") + }) + + it("final settlement when R is BELOW ONE", async () => { + await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) + + await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("100")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.finalSettlement().send(ctx.sendParam(ctx.Deployer)) + assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0") + + await ctx.DODO.methods.claim().send(ctx.sendParam(lp1)) + assert.equal(await ctx.BASE.methods.balanceOf(lp1).call(), decimalStr("95")) + assert.equal(await ctx.QUOTE.methods.balanceOf(lp1).call(), decimalStr("9000")) + await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp1)) + await ctx.DODO.methods.withdrawAllQuote().send(ctx.sendParam(lp1)) + assert.equal(await ctx.BASE.methods.balanceOf(lp1).call(), decimalStr("105")) + assert.equal(await ctx.QUOTE.methods.balanceOf(lp1).call(), "9540265973590798352834") + }) + + it("final settlement revert cases", async () => { + await assert.rejects( + ctx.DODO.methods.claim().send(ctx.sendParam(lp1)), + /DODO_IS_NOT_CLOSED/ + ) + await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.depositQuote(decimalStr("500")).send(ctx.sendParam(lp2)) + + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.finalSettlement().send(ctx.sendParam(ctx.Deployer)) + await assert.rejects( + ctx.DODO.methods.finalSettlement().send(ctx.sendParam(ctx.Deployer)), + / DODO_IS_CLOSED/ + ) + + await ctx.DODO.methods.claim().send(ctx.sendParam(lp2)) + await assert.rejects( + ctx.DODO.methods.claim().send(ctx.sendParam(lp2)), + /ALREADY_CLAIMED/ + ) + + await assert.rejects( + ctx.DODO.methods.enableQuoteDeposit().send(ctx.sendParam(ctx.Deployer)), + /DODO_IS_CLOSED/ + ) + await assert.rejects( + ctx.DODO.methods.enableBaseDeposit().send(ctx.sendParam(ctx.Deployer)), + /DODO_IS_CLOSED/ + ) + await assert.rejects( + ctx.DODO.methods.enableTrading().send(ctx.sendParam(ctx.Deployer)), + /DODO_IS_CLOSED/ + ) + }) + }) + + describe("donate", () => { + it("donate quote & base token", async () => { + await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.depositBase(decimalStr("20")).send(ctx.sendParam(lp2)) + await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.depositQuote(decimalStr("2000")).send(ctx.sendParam(lp2)) + + await ctx.DODO.methods.donateBaseToken(decimalStr("2")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.donateQuoteToken(decimalStr("500")).send(ctx.sendParam(trader)) + + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "10666666666666666666") + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), "1166666666666666666666") + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp2).call(), "21333333333333333333") + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp2).call(), "2333333333333333333333") + + await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp1)) + await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp2)) + + await ctx.DODO.methods.withdrawAllQuote().send(ctx.sendParam(lp1)) + await ctx.DODO.methods.withdrawAllQuote().send(ctx.sendParam(lp2)) + + assert.equal(await ctx.BASE.methods.balanceOf(lp1).call(), "100666666666666666666") + assert.equal(await ctx.BASE.methods.balanceOf(lp2).call(), "101333333333333333334") + assert.equal(await ctx.QUOTE.methods.balanceOf(lp1).call(), "10166666666666666666666") + assert.equal(await ctx.QUOTE.methods.balanceOf(lp2).call(), "10333333333333333333334") + }) + }) + + describe("retrieve", () => { + it("retrieve base token", async () => { + await ctx.BASE.methods.transfer(ctx.DODO.options.address, decimalStr("1")).send(ctx.sendParam(trader)) + await assert.rejects( + ctx.DODO.methods.retrieve(ctx.BASE.options.address, decimalStr("1")).send(ctx.sendParam(trader)), + /NOT_OWNER/ + ) + await assert.rejects( + ctx.DODO.methods.retrieve(ctx.BASE.options.address, decimalStr("2")).send(ctx.sendParam(ctx.Deployer)), + /DODO_BASE_BALANCE_NOT_ENOUGH/ + ) + await ctx.DODO.methods.retrieve(ctx.BASE.options.address, decimalStr("1")).send(ctx.sendParam(ctx.Deployer)) + assert.equal(await ctx.BASE.methods.balanceOf(ctx.Deployer).call(), decimalStr("1")) + }) + + it("retrieve quote token", async () => { + await ctx.QUOTE.methods.transfer(ctx.DODO.options.address, decimalStr("1")).send(ctx.sendParam(trader)) + await assert.rejects( + ctx.DODO.methods.retrieve(ctx.QUOTE.options.address, decimalStr("2")).send(ctx.sendParam(ctx.Deployer)), + /DODO_QUOTE_BALANCE_NOT_ENOUGH/ + ) + await ctx.DODO.methods.retrieve(ctx.QUOTE.options.address, decimalStr("1")).send(ctx.sendParam(ctx.Deployer)) + assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Deployer).call(), decimalStr("1")) + }) + }) + + describe("revert cases", () => { + it("k revert cases", async () => { + await assert.rejects( + ctx.DODO.methods.setK(decimalStr("1")).send(ctx.sendParam(ctx.Deployer)), + /K_MUST_BE_LESS_THAN_ONE/ + ) + await assert.rejects( + ctx.DODO.methods.setK(decimalStr("0")).send(ctx.sendParam(ctx.Deployer)), + /K_MUST_BE_GREATER_THAN_ZERO/ + ) + }) + + it("fee revert cases", async () => { + await assert.rejects( + ctx.DODO.methods.setLiquidityProviderFeeRate(decimalStr("0.999")).send(ctx.sendParam(ctx.Deployer)), + /FEE_MUST_BE_LESS_THAN_ONE/ + ) + await assert.rejects( + ctx.DODO.methods.setMaintainerFeeRate(decimalStr("0.998")).send(ctx.sendParam(ctx.Deployer)), + /FEE_MUST_BE_LESS_THAN_ONE/ + ) + }) + }) +}) \ No newline at end of file diff --git a/test/Attacks.test.ts b/test/Attacks.test.ts new file mode 100644 index 0000000..288f34b --- /dev/null +++ b/test/Attacks.test.ts @@ -0,0 +1,157 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +import { DODOContext, getDODOContext } from './utils/Context'; +import { decimalStr, gweiStr } from './utils/Converter'; +import BigNumber from "bignumber.js"; +import * as assert from "assert" + +let lp1: string +let lp2: string +let trader: string +let hacker: string + +async function init(ctx: DODOContext): Promise { + await ctx.setOraclePrice(decimalStr("100")) + lp1 = ctx.spareAccounts[0] + lp2 = ctx.spareAccounts[1] + trader = ctx.spareAccounts[2] + hacker = ctx.spareAccounts[3] + await ctx.mintTestToken(lp1, decimalStr("100"), decimalStr("10000")) + await ctx.mintTestToken(lp2, decimalStr("100"), decimalStr("10000")) + await ctx.mintTestToken(trader, decimalStr("100"), decimalStr("10000")) + await ctx.mintTestToken(hacker, decimalStr("10000"), decimalStr("1000000")) + await ctx.approveDODO(lp1) + await ctx.approveDODO(lp2) + await ctx.approveDODO(trader) + await ctx.approveDODO(hacker) +} + +describe("Attacks", () => { + + let snapshotId: string + let ctx: DODOContext + + before(async () => { + ctx = await getDODOContext() + await init(ctx); + }) + + beforeEach(async () => { + snapshotId = await ctx.EVM.snapshot(); + }); + + afterEach(async () => { + await ctx.EVM.reset(snapshotId) + }); + + describe("Price offset attack", () => { + /* + attack describe: + 1. hacker deposit a great number of base token + 2. hacker buy base token + 3. hacker withdraw a great number of base token + 4. hacker sell or buy base token to finish the arbitrage loop + + expected: + 1. hacker won't earn any quote token or sell base token with price better than what dodo provides + 2. quote token lp and base token lp have no loss + + Same in quote direction + */ + it("attack on base token", async () => { + await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) + let hackerInitBaseBalance = new BigNumber(await ctx.BASE.methods.balanceOf(hacker).call()) + let hackerInitQuoteBalance = new BigNumber(await ctx.QUOTE.methods.balanceOf(hacker).call()) + // attack step 1 + await ctx.DODO.methods.depositBase(decimalStr("5000")).send(ctx.sendParam(hacker)) + // attack step 2 + await ctx.DODO.methods.buyBaseToken(decimalStr("9.5"), decimalStr("2000")).send(ctx.sendParam(hacker)) + // attack step 3 + await ctx.DODO.methods.withdrawBase(decimalStr("5000")).send(ctx.sendParam(hacker)) + // attack step 4 + let hackerTempBaseBalance = new BigNumber(await ctx.BASE.methods.balanceOf(hacker).call()) + if (hackerTempBaseBalance.isGreaterThan(hackerInitBaseBalance)) { + await ctx.DODO.methods.sellBaseToken(hackerTempBaseBalance.minus(hackerInitBaseBalance).toString(), "0").send(ctx.sendParam(hacker)) + } else { + await ctx.DODO.methods.buyBaseToken(hackerInitBaseBalance.minus(hackerTempBaseBalance).toString(), decimalStr("5000")).send(ctx.sendParam(hacker)) + } + + // expected hacker no profit + let hackerBaseBalance = new BigNumber(await ctx.BASE.methods.balanceOf(hacker).call()) + let hackerQuoteBalance = new BigNumber(await ctx.QUOTE.methods.balanceOf(hacker).call()) + + assert.ok(hackerBaseBalance.isLessThanOrEqualTo(hackerInitBaseBalance)) + assert.ok(hackerQuoteBalance.isLessThanOrEqualTo(hackerInitQuoteBalance)) + + // expected lp no loss + let lpBaseBalance = new BigNumber(await ctx.DODO.methods.getLpBaseBalance(lp1).call()) + let lpQuoteBalance = new BigNumber(await ctx.DODO.methods.getLpQuoteBalance(lp1).call()) + + assert.ok(lpBaseBalance.isGreaterThanOrEqualTo(decimalStr("10"))) + assert.ok(lpQuoteBalance.isGreaterThanOrEqualTo(decimalStr("1000"))) + }) + + it("attack on quote token", async () => { + await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) + let hackerInitBaseBalance = new BigNumber(await ctx.BASE.methods.balanceOf(hacker).call()) + let hackerInitQuoteBalance = new BigNumber(await ctx.QUOTE.methods.balanceOf(hacker).call()) + + // attack step 1 + await ctx.DODO.methods.depositQuote(decimalStr("100000")).send(ctx.sendParam(hacker)) + // attack step 2 + await ctx.DODO.methods.sellBaseToken(decimalStr("9"), decimalStr("500")).send(ctx.sendParam(hacker)) + // attack step 3 + await ctx.DODO.methods.withdrawQuote(decimalStr("100000")).send(ctx.sendParam(hacker)) + // attack step 4 + let hackerTempBaseBalance = new BigNumber(await ctx.BASE.methods.balanceOf(hacker).call()) + if (hackerTempBaseBalance.isGreaterThan(hackerInitBaseBalance)) { + await ctx.DODO.methods.sellBaseToken(hackerTempBaseBalance.minus(hackerInitBaseBalance).toString(), "0").send(ctx.sendParam(hacker)) + } else { + await ctx.DODO.methods.buyBaseToken(hackerInitBaseBalance.minus(hackerTempBaseBalance).toString(), decimalStr("5000")).send(ctx.sendParam(hacker)) + } + + // expected hacker no profit + let hackerBaseBalance = new BigNumber(await ctx.BASE.methods.balanceOf(hacker).call()) + let hackerQuoteBalance = new BigNumber(await ctx.QUOTE.methods.balanceOf(hacker).call()) + + assert.ok(hackerBaseBalance.isLessThanOrEqualTo(hackerInitBaseBalance)) + assert.ok(hackerQuoteBalance.isLessThanOrEqualTo(hackerInitQuoteBalance)) + + // expected lp no loss + let lpBaseBalance = new BigNumber(await ctx.DODO.methods.getLpBaseBalance(lp1).call()) + let lpQuoteBalance = new BigNumber(await ctx.DODO.methods.getLpQuoteBalance(lp1).call()) + + assert.ok(lpBaseBalance.isGreaterThanOrEqualTo(decimalStr("10"))) + assert.ok(lpQuoteBalance.isGreaterThanOrEqualTo(decimalStr("1000"))) + }) + }) + + describe("Front run attack", () => { + /* + attack describe: + hacker tries to front run oracle updating by sending tx with higher gas price + + expected: + revert tx + */ + it("front run", async () => { + await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) + await assert.rejects( + ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("200")).send({ from: trader, gas: 300000, gasPrice: gweiStr("200") }), /GAS_PRICE_EXCEED/ + ) + await assert.rejects( + ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("200")).send({ from: trader, gas: 300000, gasPrice: gweiStr("200") }), /GAS_PRICE_EXCEED/ + ) + }) + + }) + +}) \ No newline at end of file diff --git a/test/DODOEthProxy.test.ts b/test/DODOEthProxy.test.ts new file mode 100644 index 0000000..db3e7d7 --- /dev/null +++ b/test/DODOEthProxy.test.ts @@ -0,0 +1,104 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +import { DODOContext, getDODOContext, DefaultDODOContextInitConfig } from './utils/Context'; +import * as contracts from "./utils/Contracts"; +import * as assert from "assert" +import { decimalStr, MAX_UINT256 } from './utils/Converter'; +import { Contract } from "web3-eth-contract"; + +let lp: string +let trader: string +let DODOEthProxy: Contract + +async function init(ctx: DODOContext): Promise { + // switch ctx to eth proxy mode + let WETH = await contracts.newContract(contracts.WETH_CONTRACT_NAME) + await ctx.DODOZoo.methods.breedDODO( + ctx.Supervisor, + ctx.Maintainer, + WETH.options.address, + ctx.QUOTE.options.address, + ctx.ORACLE.options.address, + DefaultDODOContextInitConfig.lpFeeRate, + DefaultDODOContextInitConfig.mtFeeRate, + DefaultDODOContextInitConfig.k, + DefaultDODOContextInitConfig.gasPriceLimit + ).send(ctx.sendParam(ctx.Deployer)) + + ctx.DODO = await contracts.getContractWithAddress(contracts.DODO_CONTRACT_NAME, await ctx.DODOZoo.methods.getDODO(WETH.options.address, ctx.QUOTE.options.address).call()) + + ctx.BASE = WETH + ctx.BaseCapital = await contracts.getContractWithAddress(contracts.DODO_LP_TOKEN_CONTRACT_NAME, await ctx.DODO.methods._BASE_CAPITAL_TOKEN_().call()) + + DODOEthProxy = await contracts.newContract(contracts.DODO_ETH_PROXY_CONTRACT_NAME, [ctx.DODOZoo.options.address, WETH.options.address]) + + + // env + lp = ctx.spareAccounts[0] + trader = ctx.spareAccounts[1] + await ctx.setOraclePrice(decimalStr("100")) + await ctx.approveDODO(lp) + await ctx.approveDODO(trader) + + await ctx.QUOTE.methods.mint(lp, decimalStr("1000")).send(ctx.sendParam(ctx.Deployer)) + await ctx.QUOTE.methods.mint(trader, decimalStr("1000")).send(ctx.sendParam(ctx.Deployer)) + await ctx.QUOTE.methods.approve(DODOEthProxy.options.address, MAX_UINT256).send(ctx.sendParam(trader)) + + await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp)) +} + +describe("DODO ETH PROXY", () => { + + let snapshotId: string + let ctx: DODOContext + + before(async () => { + ctx = await getDODOContext() + await init(ctx) + await ctx.QUOTE.methods.approve(DODOEthProxy.options.address, MAX_UINT256).send(ctx.sendParam(trader)) + }) + + beforeEach(async () => { + snapshotId = await ctx.EVM.snapshot(); + let depositAmount = "10" + await DODOEthProxy.methods.depositEth(decimalStr(depositAmount), ctx.QUOTE.options.address).send(ctx.sendParam(lp, depositAmount)) + }); + + afterEach(async () => { + await ctx.EVM.reset(snapshotId) + }); + + describe("buy&sell eth directly", () => { + it("buy", async () => { + let buyAmount = "1" + await DODOEthProxy.methods.buyEthWith(ctx.QUOTE.options.address, decimalStr(buyAmount), decimalStr("200")).send(ctx.sendParam(trader)) + assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("8.999")) + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "898581839502056240973") + ctx.Web3 + }) + it("sell", async () => { + let sellAmount = "1" + await DODOEthProxy.methods.sellEthTo(ctx.QUOTE.options.address, decimalStr(sellAmount), decimalStr("50")).send(ctx.sendParam(trader, sellAmount)) + assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("11")) + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1098617454226610630664") + }) + }) + + describe("revert cases", () => { + it("value not match", async () => { + await assert.rejects( + DODOEthProxy.methods.sellEthTo(ctx.QUOTE.options.address, decimalStr("1"), decimalStr("50")).send(ctx.sendParam(trader, "2")), + /ETH_AMOUNT_NOT_MATCH/ + ) + await assert.rejects( + DODOEthProxy.methods.depositEth(decimalStr("1"), ctx.QUOTE.options.address).send(ctx.sendParam(lp, "2")), + /ETH_AMOUNT_NOT_MATCH/ + ) + }) + }) +}) \ No newline at end of file diff --git a/test/DODOZoo.test.ts b/test/DODOZoo.test.ts new file mode 100644 index 0000000..83b0a0f --- /dev/null +++ b/test/DODOZoo.test.ts @@ -0,0 +1,68 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +import { DODOContext, getDODOContext } from './utils/Context'; +import * as assert from "assert" +import { newContract, TEST_ERC20_CONTRACT_NAME, getContractWithAddress, DODO_CONTRACT_NAME } from './utils/Contracts'; + + +async function init(ctx: DODOContext): Promise { } + +describe("DODO ZOO", () => { + + let snapshotId: string + let ctx: DODOContext + + before(async () => { + ctx = await getDODOContext() + await init(ctx); + }) + + beforeEach(async () => { + snapshotId = await ctx.EVM.snapshot(); + }); + + afterEach(async () => { + await ctx.EVM.reset(snapshotId) + }); + + describe("Breed new dodo", () => { + it("could not deploy the same dodo", async () => { + await assert.rejects( + ctx.DODOZoo.methods.breedDODO(ctx.Supervisor, ctx.Maintainer, ctx.BASE.options.address, ctx.QUOTE.options.address, ctx.ORACLE.options.address, "0", "0", "1", "0").send(ctx.sendParam(ctx.Deployer)), + /DODO_IS_REGISTERED/ + ) + + await assert.rejects( + ctx.DODOZoo.methods.breedDODO(ctx.Supervisor, ctx.Maintainer, ctx.QUOTE.options.address, ctx.BASE.options.address, ctx.ORACLE.options.address, "0", "0", "1", "0").send(ctx.sendParam(ctx.Deployer)), + /DODO_IS_REGISTERED/ + ) + }) + + it("breed new dodo", async () => { + let newBase = await newContract(TEST_ERC20_CONTRACT_NAME) + let newQuote = await newContract(TEST_ERC20_CONTRACT_NAME) + await assert.rejects( + ctx.DODOZoo.methods.breedDODO(ctx.Supervisor, ctx.Maintainer, newBase.options.address, newQuote.options.address, ctx.ORACLE.options.address, "0", "0", "1", "0").send(ctx.sendParam(ctx.Maintainer)), + /NOT_OWNER/ + ) + await ctx.DODOZoo.methods.breedDODO(ctx.Supervisor, ctx.Maintainer, newBase.options.address, newQuote.options.address, ctx.ORACLE.options.address, "0", "0", "1", "0").send(ctx.sendParam(ctx.Deployer)) + + let newDODO = getContractWithAddress(DODO_CONTRACT_NAME, await ctx.DODOZoo.methods.getDODO(newBase.options.address, newQuote.options.address).call()) + assert.equal(await newDODO.methods._BASE_TOKEN_().call(), newBase.options.address) + assert.equal(await newDODO.methods._QUOTE_TOKEN_().call(), newQuote.options.address) + + // could not init twice + await assert.rejects( + newDODO.methods.init(ctx.Supervisor, ctx.Maintainer, ctx.QUOTE.options.address, ctx.BASE.options.address, ctx.ORACLE.options.address, "0", "0", "1", "0").send(ctx.sendParam(ctx.Deployer)), + /DODO_ALREADY_INITIALIZED/ + ) + }) + + + }) +}) \ No newline at end of file diff --git a/test/LiquidityProvider.test.ts b/test/LiquidityProvider.test.ts new file mode 100644 index 0000000..c672875 --- /dev/null +++ b/test/LiquidityProvider.test.ts @@ -0,0 +1,446 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +import { DODOContext, getDODOContext } from './utils/Context'; +import { decimalStr } from './utils/Converter'; +import { logGas } from './utils/Log'; +import * as assert from "assert" + +let lp1: string +let lp2: string +let trader: string + +async function init(ctx: DODOContext): Promise { + await ctx.setOraclePrice(decimalStr("100")) + lp1 = ctx.spareAccounts[0] + lp2 = ctx.spareAccounts[1] + trader = ctx.spareAccounts[2] + await ctx.mintTestToken(lp1, decimalStr("100"), decimalStr("10000")) + await ctx.mintTestToken(lp2, decimalStr("100"), decimalStr("10000")) + await ctx.mintTestToken(trader, decimalStr("100"), decimalStr("10000")) + await ctx.approveDODO(lp1) + await ctx.approveDODO(lp2) + await ctx.approveDODO(trader) +} + +describe("LiquidityProvider", () => { + + let snapshotId: string + let ctx: DODOContext + + before(async () => { + ctx = await getDODOContext() + await init(ctx); + }) + + beforeEach(async () => { + snapshotId = await ctx.EVM.snapshot(); + }); + + afterEach(async () => { + await ctx.EVM.reset(snapshotId) + }); + + describe("R equals to ONE", () => { + it("multi lp deposit & withdraw", async () => { + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), decimalStr("0")) + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), decimalStr("0")) + + logGas(await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)), "deposit base") + assert.equal(await ctx.BASE.methods.balanceOf(lp1).call(), decimalStr("90")) + logGas(await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)), "deposit quote") + assert.equal(await ctx.QUOTE.methods.balanceOf(lp1).call(), decimalStr("9000")) + + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), decimalStr("10")) + assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("10")) + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), decimalStr("1000")) + assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), decimalStr("1000")) + + await ctx.DODO.methods.depositBase(decimalStr("3")).send(ctx.sendParam(lp2)) + await ctx.DODO.methods.depositQuote(decimalStr("70")).send(ctx.sendParam(lp2)) + + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), decimalStr("10")) + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), decimalStr("1000")) + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp2).call(), decimalStr("3")) + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp2).call(), decimalStr("70")) + assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("13")) + assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), decimalStr("1070")) + + await ctx.DODO.methods.withdrawBase(decimalStr("5")).send(ctx.sendParam(lp1)) + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), decimalStr("5")) + assert.equal(await ctx.BASE.methods.balanceOf(lp1).call(), decimalStr("95")) + await ctx.DODO.methods.withdrawQuote(decimalStr("100")).send(ctx.sendParam(lp1)) + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), decimalStr("900")) + assert.equal(await ctx.QUOTE.methods.balanceOf(lp1).call(), decimalStr("9100")) + + await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp1)) + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "0") + assert.equal(await ctx.BASE.methods.balanceOf(lp1).call(), decimalStr("100")) + await ctx.DODO.methods.withdrawAllQuote().send(ctx.sendParam(lp1)) + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), "0") + assert.equal(await ctx.QUOTE.methods.balanceOf(lp1).call(), decimalStr("10000")) + }) + }) + + describe("R is ABOVE ONE", () => { + it("deposit", async () => { + await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000")).send(ctx.sendParam(trader)) + + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "10010841132009222923") + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), decimalStr("1000")) + + await ctx.DODO.methods.depositBase(decimalStr("5")).send(ctx.sendParam(lp2)) + await ctx.DODO.methods.depositQuote(decimalStr("100")).send(ctx.sendParam(lp2)) + + // lp1 & lp2 would both have profit because the curve becomes flatter + // but the withdraw penalty is greater than this free profit + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "10163234422929069690") + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), decimalStr("1000")) + + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp2).call(), "5076114129127759275") + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp2).call(), decimalStr("100")) + + assert.equal(await ctx.DODO.methods.getWithdrawBasePenalty(decimalStr("5")).call(), "228507420047606043") + assert.equal(await ctx.DODO.methods.getWithdrawQuotePenalty(decimalStr("100")).call(), "0") + }) + + it("withdraw", async () => { + await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000")).send(ctx.sendParam(trader)) + + assert.equal(await ctx.DODO.methods.getWithdrawBasePenalty(decimalStr("4")).call(), "1065045389392391670") + assert.equal(await ctx.DODO.methods.getWithdrawQuotePenalty(decimalStr("100")).call(), "0") + + await ctx.DODO.methods.withdrawBase(decimalStr("4")).send(ctx.sendParam(lp1)) + assert.equal(await ctx.BASE.methods.balanceOf(lp1).call(), "92934954610607608330") + assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), "2060045389392391670") + assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "7075045389392391670") + + await ctx.DODO.methods.withdrawQuote(decimalStr("100")).send(ctx.sendParam(lp1)) + assert.equal(await ctx.QUOTE.methods.balanceOf(lp1).call(), decimalStr("9100")) + assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "1451951805416248746119") + assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), decimalStr("900")) + }) + }) + + describe("R is BELOW ONE", () => { + it("deposit", async () => { + await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("200")).send(ctx.sendParam(trader)) + + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), decimalStr("10")) + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), "1000978629616255274293") + + await ctx.DODO.methods.depositQuote(decimalStr("500")).send(ctx.sendParam(lp2)) + await ctx.DODO.methods.depositBase(decimalStr("5")).send(ctx.sendParam(lp2)) + + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), decimalStr("10")) + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), "1012529270910521748792") + + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp2).call(), decimalStr("5")) + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp2).call(), "505769674273013520099") + + assert.equal(await ctx.DODO.methods.getWithdrawBasePenalty(decimalStr("5")).call(), "0") + assert.equal(await ctx.DODO.methods.getWithdrawQuotePenalty(decimalStr("500")).call(), "17320315567279994599") + }) + + it("withdraw", async () => { + await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("200")).send(ctx.sendParam(trader)) + + assert.equal(await ctx.DODO.methods.getWithdrawBasePenalty(decimalStr("4")).call(), "0") + assert.equal(await ctx.DODO.methods.getWithdrawQuotePenalty(decimalStr("100")).call(), "7389428846238898052") + + await ctx.DODO.methods.withdrawQuote(decimalStr("100")).send(ctx.sendParam(lp1)) + assert.equal(await ctx.QUOTE.methods.balanceOf(lp1).call(), "9092610571153761101948") + assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "447655402437037250886") + assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), "908310739520405634819") + + await ctx.DODO.methods.withdrawBase(decimalStr("4")).send(ctx.sendParam(lp1)) + assert.equal(await ctx.BASE.methods.balanceOf(lp1).call(), decimalStr("94")) + assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("11")) + assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), decimalStr("6")) + }) + }) + + describe("Oracle changes", () => { + it("base side lp don't has pnl when R is BELOW ONE", async () => { + await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("200")).send(ctx.sendParam(trader)) + + await ctx.setOraclePrice(decimalStr("80")); + + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), decimalStr("10")) + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), "914362409397559034505") + + await ctx.setOraclePrice(decimalStr("120")) + + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), decimalStr("10")) + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), "1085284653936129403614") + }) + + it("quote side lp don't has pnl when R is ABOVE ONE", async () => { + await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("600")).send(ctx.sendParam(trader)) + + await ctx.setOraclePrice(decimalStr("80")); + + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "11138732839027528597") + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), decimalStr("1000")) + + await ctx.setOraclePrice(decimalStr("120")) + + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "9234731968726215538") + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), decimalStr("1000")) + }) + + }) + + describe("Transfer lp token", () => { + it("transfer", async () => { + await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) + + await ctx.BaseCapital.methods.transfer(lp2, decimalStr("5")).send(ctx.sendParam(lp1)) + await ctx.QuoteCapital.methods.transfer(lp2, decimalStr("5")).send(ctx.sendParam(lp1)) + + await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp2)) + await ctx.DODO.methods.withdrawAllQuote().send(ctx.sendParam(lp2)) + + assert.equal(await ctx.BASE.methods.balanceOf(lp2).call(), decimalStr("105")) + assert.equal(await ctx.QUOTE.methods.balanceOf(lp2).call(), decimalStr("10005")) + }) + }) + + describe("Deposit & transfer to other account", () => { + it("base token", async () => { + await ctx.DODO.methods.depositBaseTo(lp2, decimalStr("10")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.withdrawBaseTo(trader, decimalStr("5")).send(ctx.sendParam(lp2)) + await ctx.DODO.methods.withdrawAllBaseTo(ctx.Supervisor).send(ctx.sendParam(lp2)) + + assert.equal(await ctx.BASE.methods.balanceOf(lp1).call(), decimalStr("90")) + assert.equal(await ctx.BASE.methods.balanceOf(lp2).call(), decimalStr("100")) + assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("105")) + assert.equal(await ctx.BASE.methods.balanceOf(ctx.Supervisor).call(), decimalStr("5")) + }) + + it("quote token", async () => { + await ctx.DODO.methods.depositQuoteTo(lp2, decimalStr("1000")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.withdrawQuoteTo(trader, decimalStr("500")).send(ctx.sendParam(lp2)) + await ctx.DODO.methods.withdrawAllQuoteTo(ctx.Supervisor).send(ctx.sendParam(lp2)) + + assert.equal(await ctx.QUOTE.methods.balanceOf(lp1).call(), decimalStr("9000")) + assert.equal(await ctx.QUOTE.methods.balanceOf(lp2).call(), decimalStr("10000")) + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), decimalStr("10500")) + assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Supervisor).call(), decimalStr("500")) + }) + }) + + describe("Corner cases", () => { + it("single side deposit", async () => { + await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken("5015841132009222923", decimalStr("0")).send(ctx.sendParam(trader)) + + assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0") + assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "10010841132009222923") + assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), "1103903610832497492") + + await ctx.DODO.methods.depositQuote("1").send(ctx.sendParam(lp2)) + + assert.equal(await ctx.DODO.methods.getQuoteCapitalBalanceOf(lp2).call(), "1103903610832497493") + }) + + it("single side deposit & lp deposit when R isn't equal to ONE", async () => { + await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000")).send(ctx.sendParam(trader)) + + await ctx.DODO.methods.depositQuote("1").send(ctx.sendParam(lp2)) + + assert.equal(await ctx.DODO.methods.getQuoteCapitalBalanceOf(lp2).call(), "1") + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp2).call(), "1") + }) + + it("single side deposit (base) & oracle change introduces loss", async () => { + await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000")).send(ctx.sendParam(trader)) + + await ctx.setOraclePrice(decimalStr("120")) + await ctx.DODO.methods.sellBaseToken(decimalStr("4"), decimalStr("0")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("0")).send(ctx.sendParam(trader)) + + assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "2") + assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "9234731968726215513") + assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), "1105993618321025490") + + await ctx.DODO.methods.depositQuote("1").send(ctx.sendParam(lp2)) + assert.equal(await ctx.DODO.methods.getQuoteCapitalBalanceOf(lp2).call(), "7221653398290522326") + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp2).call(), "7221653398290522382") + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "9234731968726215513") + }) + + it("single side deposit (base) & oracle change introduces profit", async () => { + await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000")).send(ctx.sendParam(trader)) + + await ctx.setOraclePrice(decimalStr("80")) + await ctx.DODO.methods.sellBaseToken(decimalStr("4"), decimalStr("0")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("4"), decimalStr("0")).send(ctx.sendParam(trader)) + + assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "2") + assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "11138732839027528584") + assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), "1105408308382702868") + + await ctx.DODO.methods.depositQuote("1").send(ctx.sendParam(lp2)) + assert.equal(await ctx.DODO.methods.getQuoteCapitalBalanceOf(lp2).call(), "21553269260529319697") + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp2).call(), "21553269260529319725") + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "11138732839027528584") + }) + + it("single side deposit (quote) & oracle change introduces loss", async () => { + await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("0")).send(ctx.sendParam(trader)) + + await ctx.setOraclePrice(decimalStr("80")) + await ctx.DODO.methods.buyBaseToken(decimalStr("4"), decimalStr("600")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("0.99"), decimalStr("500")).send(ctx.sendParam(trader)) + + assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "1") + assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "9980000000000000") + assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), "914362409397559031579") + + await ctx.DODO.methods.depositBase("1").send(ctx.sendParam(lp2)) + assert.equal(await ctx.DODO.methods.getBaseCapitalBalanceOf(lp2).call(), "10247647352975730") + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp2).call(), "10247647352975730") + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), "914362409397559031579") + }) + + it("deposit and withdraw immediately", async () => { + await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000")).send(ctx.sendParam(trader)) + + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "10010841132009222923") + + await ctx.DODO.methods.depositBase(decimalStr("5")).send(ctx.sendParam(lp2)) + + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "10163234422929069690") + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp2).call(), "5076114129127759275") + + await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp2)) + + assert.equal(await ctx.BASE.methods.balanceOf(lp2).call(), "99841132414635941818") + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "10182702153814588570") + }) + }) + + describe("Revert cases", () => { + it("withdraw base amount exceeds DODO balance", async () => { + await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000")).send(ctx.sendParam(trader)) + + await assert.rejects( + ctx.DODO.methods.withdrawBase(decimalStr("6")).send(ctx.sendParam(lp1)), + /DODO_BASE_TOKEN_BALANCE_NOT_ENOUGH/ + ) + + await assert.rejects( + ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp1)), + /DODO_BASE_TOKEN_BALANCE_NOT_ENOUGH/ + ) + }) + + it("withdraw quote amount exceeds DODO balance", async () => { + await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("0")).send(ctx.sendParam(trader)) + + await assert.rejects( + ctx.DODO.methods.withdrawQuote(decimalStr("600")).send(ctx.sendParam(lp1)), + /DODO_QUOTE_TOKEN_BALANCE_NOT_ENOUGH/ + ) + + await assert.rejects( + ctx.DODO.methods.withdrawAllQuote().send(ctx.sendParam(lp1)), + /DODO_QUOTE_TOKEN_BALANCE_NOT_ENOUGH/ + ) + }) + + it("withdraw base could not afford penalty", async () => { + await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.buyBaseToken(decimalStr("9"), decimalStr("10000")).send(ctx.sendParam(trader)) + + await assert.rejects( + ctx.DODO.methods.withdrawBase(decimalStr("0.5")).send(ctx.sendParam(lp1)), + /COULD_NOT_AFFORD_LIQUIDITY_PENALTY/ + ) + + await assert.rejects( + ctx.DODO.methods.getWithdrawBasePenalty(decimalStr("10")).call(), + /DODO_BASE_BALANCE_NOT_ENOUGH/ + ) + }) + + it("withdraw quote could not afford penalty", async () => { + await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.sellBaseToken(decimalStr("10"), decimalStr("0")).send(ctx.sendParam(trader)) + + await assert.rejects( + ctx.DODO.methods.withdrawQuote(decimalStr("200")).send(ctx.sendParam(lp1)), + /COULD_NOT_AFFORD_LIQUIDITY_PENALTY/ + ) + + await assert.rejects( + ctx.DODO.methods.getWithdrawQuotePenalty(decimalStr("1000")).call(), + /DODO_QUOTE_BALANCE_NOT_ENOUGH/ + ) + }) + + it("withdraw all base could not afford penalty", async () => { + await ctx.DODO.methods.depositBase(decimalStr("9.5")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.depositBase(decimalStr("0.5")).send(ctx.sendParam(lp2)) + await ctx.DODO.methods.buyBaseToken(decimalStr("9"), decimalStr("10000")).send(ctx.sendParam(trader)) + + await assert.rejects( + ctx.DODO.methods.withdrawBase(decimalStr("0.5")).send(ctx.sendParam(lp2)), + /COULD_NOT_AFFORD_LIQUIDITY_PENALTY/ + ) + }) + + it("withdraw all quote could not afford penalty", async () => { + await ctx.DODO.methods.depositQuote(decimalStr("800")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.depositQuote(decimalStr("200")).send(ctx.sendParam(lp2)) + await ctx.DODO.methods.sellBaseToken(decimalStr("10"), decimalStr("0")).send(ctx.sendParam(trader)) + + await assert.rejects( + ctx.DODO.methods.withdrawQuote(decimalStr("200")).send(ctx.sendParam(lp2)), + /COULD_NOT_AFFORD_LIQUIDITY_PENALTY/ + ) + }) + + it("withdraw amount exceeds lp balance", async () => { + await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp2)) + await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp2)) + await assert.rejects( + ctx.DODO.methods.withdrawBase(decimalStr("11")).send(ctx.sendParam(lp1)), + /LP_BASE_CAPITAL_BALANCE_NOT_ENOUGH/ + ) + await assert.rejects( + ctx.DODO.methods.withdrawQuote(decimalStr("1100")).send(ctx.sendParam(lp1)), + /LP_QUOTE_CAPITAL_BALANCE_NOT_ENOUGH/ + ) + }) + }) + +}) \ No newline at end of file diff --git a/test/LongTailTokenlMode.test.ts b/test/LongTailTokenlMode.test.ts new file mode 100644 index 0000000..bdc7707 --- /dev/null +++ b/test/LongTailTokenlMode.test.ts @@ -0,0 +1,94 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +import { DODOContext, getDODOContext } from './utils/Context'; +import { decimalStr, gweiStr } from './utils/Converter'; +import * as assert from "assert" + +let lp: string +let trader: string + +async function init(ctx: DODOContext): Promise { + await ctx.setOraclePrice(decimalStr("10")) + + lp = ctx.spareAccounts[0] + trader = ctx.spareAccounts[1] + await ctx.approveDODO(lp) + await ctx.approveDODO(trader) + + await ctx.mintTestToken(lp, decimalStr("10000"), decimalStr("10000000")) + await ctx.mintTestToken(trader, decimalStr("0"), decimalStr("10000000")) + + await ctx.DODO.methods.depositBase(decimalStr("10000")).send(ctx.sendParam(lp)) +} + +describe("Trader", () => { + + let snapshotId: string + let ctx: DODOContext + + before(async () => { + let dodoContextInitConfig = { + lpFeeRate: decimalStr("0"), + mtFeeRate: decimalStr("0"), + k: decimalStr("0.99"), // nearly one + gasPriceLimit: gweiStr("100"), + } + ctx = await getDODOContext(dodoContextInitConfig) + await init(ctx); + }) + + beforeEach(async () => { + snapshotId = await ctx.EVM.snapshot(); + }); + + afterEach(async () => { + await ctx.EVM.reset(snapshotId) + }); + + // price change quickly + describe("Trade long tail coin", () => { + it("price discover", async () => { + // 10% depth + // avg price = 11.137 + await ctx.DODO.methods.buyBaseToken(decimalStr("1000"), decimalStr("100000")).send(ctx.sendParam(trader)) + assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("1000")) + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "9988900000000000000000000") + + // 20% depth + // avg price = 12.475 + await ctx.DODO.methods.buyBaseToken(decimalStr("1000"), decimalStr("100000")).send(ctx.sendParam(trader)) + assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("2000")) + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "9975050000000000000020000") + + // 50% depth + // avg price = 19.9 + await ctx.DODO.methods.buyBaseToken(decimalStr("3000"), decimalStr("300000")).send(ctx.sendParam(trader)) + assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("5000")) + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "9900500000000000000260000") + + // 80% depth + // avg price = 49.6 + await ctx.DODO.methods.buyBaseToken(decimalStr("3000"), decimalStr("300000")).send(ctx.sendParam(trader)) + assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("8000")) + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "9603200000000000001130000") + }) + + it("user has no pnl if buy and sell immediately", async () => { + // lp buy + await ctx.DODO.methods.buyBaseToken(decimalStr("1000"), decimalStr("100000")).send(ctx.sendParam(lp)) + + // trader buy and sell + await ctx.DODO.methods.buyBaseToken(decimalStr("1000"), decimalStr("100000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("1000"), decimalStr("0")).send(ctx.sendParam(trader)) + + // no profit or loss (may have precision problems) + assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), "0") + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "9999999999999999999970000") + }) + }) +}) \ No newline at end of file diff --git a/test/StableCoinMode.test.ts b/test/StableCoinMode.test.ts new file mode 100644 index 0000000..c1bd248 --- /dev/null +++ b/test/StableCoinMode.test.ts @@ -0,0 +1,103 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +import { DODOContext, getDODOContext } from './utils/Context'; +import { decimalStr, gweiStr } from './utils/Converter'; +import * as assert from "assert" + +let lp: string +let trader: string + +async function init(ctx: DODOContext): Promise { + await ctx.setOraclePrice(decimalStr("1")) + + lp = ctx.spareAccounts[0] + trader = ctx.spareAccounts[1] + await ctx.approveDODO(lp) + await ctx.approveDODO(trader) + + await ctx.mintTestToken(lp, decimalStr("10000"), decimalStr("10000")) + await ctx.mintTestToken(trader, decimalStr("10000"), decimalStr("10000")) + + await ctx.DODO.methods.depositBase(decimalStr("10000")).send(ctx.sendParam(lp)) + await ctx.DODO.methods.depositQuote(decimalStr("10000")).send(ctx.sendParam(lp)) +} + +describe("Trader", () => { + + let snapshotId: string + let ctx: DODOContext + + before(async () => { + let dodoContextInitConfig = { + lpFeeRate: decimalStr("0.0001"), + mtFeeRate: decimalStr("0"), + k: gweiStr("1"), // nearly zero + gasPriceLimit: gweiStr("100"), + } + ctx = await getDODOContext(dodoContextInitConfig) + await init(ctx); + }) + + beforeEach(async () => { + snapshotId = await ctx.EVM.snapshot(); + }); + + afterEach(async () => { + await ctx.EVM.reset(snapshotId) + }); + + describe("Trade stable coin", () => { + it("trade with tiny slippage", async () => { + // 10% depth avg price 1.000100000111135 + await ctx.DODO.methods.buyBaseToken(decimalStr("1000"), decimalStr("1001")).send(ctx.sendParam(trader)) + assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("11000")) + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "8999899999888865431655") + + // 99.9% depth avg price 1.00010109 + await ctx.DODO.methods.buyBaseToken(decimalStr("8990"), decimalStr("10000")).send(ctx.sendParam(trader)) + assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("19990")) + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "8990031967821738650") + + // sell to 99.9% depth avg price 0.9999 + await ctx.DODO.methods.sellBaseToken(decimalStr("19980"), decimalStr("19970")).send(ctx.sendParam(trader)) + assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("10")) + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "19986992950440794519885") + }) + + it("huge sell trading amount", async () => { + // trader could sell any number of base token + // but the price will drop quickly + await ctx.mintTestToken(trader, decimalStr("10000"), decimalStr("0")) + await ctx.DODO.methods.sellBaseToken(decimalStr("20000"), decimalStr("0")).send(ctx.sendParam(trader)) + + assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("0")) + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "19998999990001000029998") + }) + + it("huge buy trading amount", async () => { + // could not buy all base balance + await assert.rejects( + ctx.DODO.methods.buyBaseToken(decimalStr("10000"), decimalStr("10010")).send(ctx.sendParam(trader)), + /DODO_BASE_TOKEN_BALANCE_NOT_ENOUGH/ + ) + + // when buy amount close to base balance, price will increase quickly + await ctx.mintTestToken(trader, decimalStr("0"), decimalStr("10000")) + await ctx.DODO.methods.buyBaseToken(decimalStr("9999"), decimalStr("20000")).send(ctx.sendParam(trader)) + assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("19999")) + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "9000000119999999900000") + }) + + it("tiny withdraw penalty", async () => { + await ctx.DODO.methods.buyBaseToken(decimalStr("9990"), decimalStr("10000")).send(ctx.sendParam(trader)) + + // penalty only 0.2% even if withdraw make pool utilization rate raise to 99.5% + assert.equal(await ctx.DODO.methods.getWithdrawBasePenalty(decimalStr("5")).call(), "9981962500000000") + }) + }) +}) \ No newline at end of file diff --git a/test/Trader.test.ts b/test/Trader.test.ts new file mode 100644 index 0000000..0843233 --- /dev/null +++ b/test/Trader.test.ts @@ -0,0 +1,281 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +import { DODOContext, getDODOContext } from './utils/Context'; +import { decimalStr } from './utils/Converter'; +import { logGas } from './utils/Log'; +import * as assert from "assert" + +let lp: string +let trader: string + +async function init(ctx: DODOContext): Promise { + await ctx.setOraclePrice(decimalStr("100")) + + lp = ctx.spareAccounts[0] + trader = ctx.spareAccounts[1] + await ctx.approveDODO(lp) + await ctx.approveDODO(trader) + + await ctx.mintTestToken(lp, decimalStr("10"), decimalStr("1000")) + await ctx.mintTestToken(trader, decimalStr("10"), decimalStr("1000")) + + await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp)) + await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp)) +} + +describe("Trader", () => { + + let snapshotId: string + let ctx: DODOContext + + before(async () => { + ctx = await getDODOContext() + await init(ctx); + }) + + beforeEach(async () => { + snapshotId = await ctx.EVM.snapshot(); + }); + + afterEach(async () => { + await ctx.EVM.reset(snapshotId) + }); + + describe("R goes above ONE", () => { + it("buy when R equals ONE", async () => { + logGas(await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110")).send(ctx.sendParam(trader)), "buy base token") + // trader balances + assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("11")) + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "898581839502056240973") + // maintainer balances + assert.equal(await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), decimalStr("0.001")) + assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), decimalStr("0")) + // dodo balances + assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("8.999")) + assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "1101418160497943759027") + }) + + it("buy when R is ABOVE ONE", async () => { + await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("4"), decimalStr("500")).send(ctx.sendParam(trader)) + // trader balances + assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("15")) + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "448068135932873382076") + // maintainer balances + assert.equal(await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), decimalStr("0.005")) + assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), decimalStr("0")) + // dodo balances + assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("4.995")) + assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "1551931864067126617924") + }) + + it("sell when R is ABOVE ONE", async () => { + await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("0.5"), decimalStr("40")).send(ctx.sendParam(trader)) + // trader balances + assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("10.5")) + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "949280846351657143136") + // maintainer balances + assert.equal(await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), decimalStr("0.001")) + assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), "50851561534203512") + // dodo balances + assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("9.499")) + assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "1050668302086808653352") + }) + + it("sell when R is ABOVE ONE and RStatus back to ONE", async () => { + await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken("1003002430889317763", decimalStr("90")).send(ctx.sendParam(trader)) + // R status + assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0") + // trader balances + assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), "9996997569110682237") + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "999695745518506168723") + // maintainer balances + assert.equal(await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), decimalStr("0.001")) + assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), "101418160497943759") + // dodo balances + assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), "10002002430889317763") + assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "1000202836320995887518") + // target status + assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "10002002430889317763") + assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), "1000202836320995887518") + }) + + it("sell when R is ABOVE ONE and RStatus becomes BELOW ONE", async () => { + await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110")).send(ctx.sendParam(trader)) + logGas(await ctx.DODO.methods.sellBaseToken(decimalStr("2"), decimalStr("90")).send(ctx.sendParam(trader)), "sell base token gas cost worst case") + // R status + assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "2") + // trader balances + assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("9")) + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1098020621600061709145") + // maintainer balances + assert.equal(await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), decimalStr("0.001")) + assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), "200038898794388634") + // dodo balances + assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("10.999")) + assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "901779339501143902221") + // target status + assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "10002002430889317763") + assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), "1000400077797588777268") + }) + }) + + describe("R goes below ONE", () => { + it("sell when R equals ONE", async () => { + logGas(await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90")).send(ctx.sendParam(trader)), "sell base token") + // trader balances + assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("9")) + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1098617454226610630664") + // maintainer balances + assert.equal(await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), "0") + assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), "98914196817061816") + // dodo balances + assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("11")) + assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "901283631576572307520") + }) + + it.only("sell when R is BELOW ONE", async () => { + await ctx.DODO.methods.sellBaseToken(decimalStr("3"), decimalStr("90")).send(ctx.sendParam(trader)) + console.log(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("8")) + console.log(await ctx.QUOTE.methods.balanceOf(trader).call(), "1197235140964438116338") + console.log(await ctx.DODO.methods._QUOTE_BALANCE_().call()) + + await ctx.DODO.methods.sellBaseToken(decimalStr("3"), decimalStr("90")).send(ctx.sendParam(trader)) + // trader balances + console.log(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("8")) + console.log(await ctx.QUOTE.methods.balanceOf(trader).call(), "1197235140964438116338") + // maintainer balances + console.log(await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), "0") + console.log(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), "197828626844973035") + // dodo balances + console.log(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("12")) + console.log(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "802567030408716910627") + }) + + it("buy when R is BELOW ONE", async () => { + await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("0.5"), decimalStr("60")).send(ctx.sendParam(trader)) + // trader balances + assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("9.5")) + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1049294316148665165351") + // maintainer balances + assert.equal(await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), decimalStr("0.0005")) + assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), "98914196817061816") + // dodo balances + assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("10.4995")) + assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "950606769654517772833") + }) + + it("buy when R is BELOW ONE and RStatus back to ONE", async () => { + await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken("997008973080757728", decimalStr("110")).send(ctx.sendParam(trader)) + // R status + assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0") + // trader balances + assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), "9997008973080757728") + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "999703024198699420514") + // maintainer balances + assert.equal(await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), "997008973080757") + assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), "98914196817061816") + // dodo balances + assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), "10001994017946161515") + assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "1000198061604483517670") + // target status + assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "10001994017946161515") + assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), "1000198061604483517670") + }) + + it("buy when R is BELOW ONE and RStatus becomes ABOVE ONE", async () => { + await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90")).send(ctx.sendParam(trader)) + logGas(await ctx.DODO.methods.buyBaseToken(decimalStr("2"), decimalStr("220")).send(ctx.sendParam(trader)), "buy base token gas cost worst case") + // R status + assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "1") + // trader balances + assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("11")) + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "897977789597854412810") + // maintainer balances + assert.equal(await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), decimalStr("0.002")) + assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), "98914196817061816") + // dodo balances + assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("8.998")) + assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "1101923296205328525374") + // target status + assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "10004000000000000000") + assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), "1000198061604483517670") + }) + }) + + describe("Corner cases", () => { + it("buy or sell 0", async () => { + await ctx.DODO.methods.sellBaseToken(decimalStr("0"), decimalStr("0")).send(ctx.sendParam(trader)) + assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("10")) + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), decimalStr("1000")) + + await ctx.DODO.methods.buyBaseToken(decimalStr("0"), decimalStr("0")).send(ctx.sendParam(trader)) + assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("10")) + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), decimalStr("1000")) + }) + + it("buy or sell a tiny amount", async () => { + // no precision problem + await ctx.DODO.methods.sellBaseToken("1", decimalStr("0")).send(ctx.sendParam(trader)) + assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), "9999999999999999999") + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1000000000000000000100") + + // have precision problem, charge 0 + await ctx.DODO.methods.buyBaseToken("1", decimalStr("1")).send(ctx.sendParam(trader)) + assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), "10000000000000000000") + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1000000000000000000100") + assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0") + + // no precision problem if trading amount is extremely small + await ctx.DODO.methods.buyBaseToken("10", decimalStr("1")).send(ctx.sendParam(trader)) + assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), "10000000000000000010") + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "999999999999999999100") + }) + + it("sell a huge amount of base token", async () => { + await ctx.mintTestToken(trader, decimalStr("10000"), "0") + await ctx.DODO.methods.sellBaseToken(decimalStr("10000"), "0").send(ctx.sendParam(trader)) + // nearly drain out quote pool + // because the fee donated is greater than remaining quote pool + // quote lp earn a considerable profit + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1996900220185135480814") + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp).call(), "4574057156329524018663") + }) + }) + + describe("Revert cases", () => { + it("price limit", async () => { + await assert.rejects( + ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("100")).send(ctx.sendParam(trader)), + /BUY_BASE_COST_TOO_MUCH/ + ) + await assert.rejects( + ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("100")).send(ctx.sendParam(trader)), + /SELL_BASE_RECEIVE_NOT_ENOUGH/ + ) + }) + + it("base balance limit", async () => { + await assert.rejects( + ctx.DODO.methods.buyBaseToken(decimalStr("11"), decimalStr("10000")).send(ctx.sendParam(trader)), + /DODO_BASE_TOKEN_BALANCE_NOT_ENOUGH/ + ) + + await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("200")).send(ctx.sendParam(trader)) + + await assert.rejects( + ctx.DODO.methods.buyBaseToken(decimalStr("11"), decimalStr("10000")).send(ctx.sendParam(trader)), + /DODO_BASE_TOKEN_BALANCE_NOT_ENOUGH/ + ) + }) + }) +}) \ No newline at end of file diff --git a/test/utils/Context.ts b/test/utils/Context.ts new file mode 100644 index 0000000..945da2e --- /dev/null +++ b/test/utils/Context.ts @@ -0,0 +1,127 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +import { EVM, getDefaultWeb3 } from "./EVM"; +import Web3 from "web3"; +import { Contract } from "web3-eth-contract"; +import BigNumber from "bignumber.js"; +import * as contracts from "./Contracts"; +import { decimalStr, gweiStr, MAX_UINT256 } from "./Converter"; +import * as log from "./Log"; + +BigNumber.config({ + EXPONENTIAL_AT: 1000, + DECIMAL_PLACES: 80, +}); + +export interface DODOContextInitConfig { + lpFeeRate: string, + mtFeeRate: string, + k: string, + gasPriceLimit: string, +} + +/* + price curve when k=0.1 + +──────────────────────+───────────────+ + | purchase percentage | avg slippage | + +──────────────────────+───────────────+ + | 1% | 0.1% | + | 5% | 0.5% | + | 10% | 1.1% | + | 20% | 2.5% | + | 50% | 10% | + | 70% | 23.3% | + +──────────────────────+───────────────+ +*/ +export let DefaultDODOContextInitConfig = { + lpFeeRate: decimalStr("0.002"), + mtFeeRate: decimalStr("0.001"), + k: decimalStr("0.1"), + gasPriceLimit: gweiStr("100"), +} + +export class DODOContext { + EVM: EVM + Web3: Web3 + DODO: Contract + DODOZoo: Contract + BASE: Contract + BaseCapital: Contract + QUOTE: Contract + QuoteCapital: Contract + ORACLE: Contract + Deployer: string + Supervisor: string + Maintainer: string + spareAccounts: string[] + + constructor() { } + + async init(config: DODOContextInitConfig) { + this.EVM = new EVM + this.Web3 = getDefaultWeb3() + this.DODOZoo = await contracts.newContract(contracts.DODO_ZOO_CONTRACT_NAME) + this.BASE = await contracts.newContract(contracts.TEST_ERC20_CONTRACT_NAME) + this.QUOTE = await contracts.newContract(contracts.TEST_ERC20_CONTRACT_NAME) + this.ORACLE = await contracts.newContract(contracts.NAIVE_ORACLE_CONTRACT_NAME) + + const allAccounts = await this.Web3.eth.getAccounts(); + this.Deployer = allAccounts[0] + this.Supervisor = allAccounts[1] + this.Maintainer = allAccounts[2] + this.spareAccounts = allAccounts.slice(3, 10) + + await this.DODOZoo.methods.breedDODO( + this.Supervisor, + this.Maintainer, + this.BASE.options.address, + this.QUOTE.options.address, + this.ORACLE.options.address, + config.lpFeeRate, + config.mtFeeRate, + config.k, + config.gasPriceLimit + ).send(this.sendParam(this.Deployer)) + + this.DODO = contracts.getContractWithAddress(contracts.DODO_CONTRACT_NAME, await this.DODOZoo.methods.getDODO(this.BASE.options.address, this.QUOTE.options.address).call()) + + this.BaseCapital = contracts.getContractWithAddress(contracts.DODO_LP_TOKEN_CONTRACT_NAME, await this.DODO.methods._BASE_CAPITAL_TOKEN_().call()) + this.QuoteCapital = contracts.getContractWithAddress(contracts.DODO_LP_TOKEN_CONTRACT_NAME, await this.DODO.methods._QUOTE_CAPITAL_TOKEN_().call()) + + console.log(log.blueText("[Init dodo context]")) + } + + sendParam(sender, value = "0") { + return { + from: sender, + gas: process.env["COVERAGE"] ? 10000000000 : 7000000, + gasPrice: process.env.GAS_PRICE, + value: decimalStr(value) + } + } + + async setOraclePrice(price: string) { + await this.ORACLE.methods.setPrice(price).send(this.sendParam(this.Deployer)) + } + + async mintTestToken(to: string, base: string, quote: string) { + await this.BASE.methods.mint(to, base).send(this.sendParam(this.Deployer)) + await this.QUOTE.methods.mint(to, quote).send(this.sendParam(this.Deployer)) + } + + async approveDODO(account: string) { + await this.BASE.methods.approve(this.DODO.options.address, MAX_UINT256).send(this.sendParam(account)) + await this.QUOTE.methods.approve(this.DODO.options.address, MAX_UINT256).send(this.sendParam(account)) + } +} + +export async function getDODOContext(config: DODOContextInitConfig = DefaultDODOContextInitConfig): Promise { + var context = new DODOContext() + await context.init(config) + return context +} \ No newline at end of file diff --git a/test/utils/Contracts.ts b/test/utils/Contracts.ts new file mode 100644 index 0000000..7901049 --- /dev/null +++ b/test/utils/Contracts.ts @@ -0,0 +1,112 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ +var jsonPath: string = "../../build/contracts/" +if (process.env["COVERAGE"]) { + console.log("[Coverage mode]") + jsonPath = "../../.coverage_artifacts/contracts/" +} + +const DODO = require(`${jsonPath}DODO.json`) +const DODOZoo = require(`${jsonPath}DODOZoo.json`) +const DODOEthProxy = require(`${jsonPath}DODOEthProxy.json`) +const WETH = require(`${jsonPath}WETH9.json`) +const TestERC20 = require(`${jsonPath}TestERC20.json`) +const NaiveOracle = require(`${jsonPath}NaiveOracle.json`) +const DODOLpToken = require(`${jsonPath}DODOLpToken.json`) + +import { getDefaultWeb3 } from './EVM'; +import { Contract } from 'web3-eth-contract'; + +export const DODO_CONTRACT_NAME = "DODO" +export const TEST_ERC20_CONTRACT_NAME = "TestERC20" +export const NAIVE_ORACLE_CONTRACT_NAME = "NaiveOracle" +export const DODO_LP_TOKEN_CONTRACT_NAME = "DODOLpToken" +export const DODO_ZOO_CONTRACT_NAME = "DOOZoo" +export const DODO_ETH_PROXY_CONTRACT_NAME = "DODOEthProxy" +export const WETH_CONTRACT_NAME = "WETH" + +interface ContractJson { + abi: any; + networks: { [network: number]: any }; + byteCode: string; +} + +function _getContractJSON(contractName: string): ContractJson { + switch (contractName) { + case DODO_CONTRACT_NAME: + return { + abi: DODO.abi, + networks: DODO.networks, + byteCode: DODO.bytecode + }; + case TEST_ERC20_CONTRACT_NAME: + return { + abi: TestERC20.abi, + networks: TestERC20.networks, + byteCode: TestERC20.bytecode + }; + case NAIVE_ORACLE_CONTRACT_NAME: + return { + abi: NaiveOracle.abi, + networks: NaiveOracle.networks, + byteCode: NaiveOracle.bytecode + }; + case DODO_LP_TOKEN_CONTRACT_NAME: + return { + abi: DODOLpToken.abi, + networks: DODOLpToken.networks, + byteCode: DODOLpToken.bytecode + }; + case DODO_ZOO_CONTRACT_NAME: + return { + abi: DODOZoo.abi, + networks: DODOZoo.networks, + byteCode: DODOZoo.bytecode + }; + case DODO_ETH_PROXY_CONTRACT_NAME: + return { + abi: DODOEthProxy.abi, + networks: DODOEthProxy.networks, + byteCode: DODOEthProxy.bytecode + }; + case WETH_CONTRACT_NAME: + return { + abi: WETH.abi, + networks: WETH.networks, + byteCode: WETH.bytecode + }; + default: + throw "CONTRACT_NAME_NOT_FOUND"; + } +} + +export function getContractWithAddress(contractName: string, address: string) { + var Json = _getContractJSON(contractName) + var web3 = getDefaultWeb3() + return new web3.eth.Contract(Json.abi, address) +} + +export function getDepolyedContract(contractName: string): Contract { + var Json = _getContractJSON(contractName) + var networkId = process.env.NETWORK_ID + var deployedAddress = _getContractJSON(contractName).networks[networkId].address + var web3 = getDefaultWeb3() + return new web3.eth.Contract(Json.abi, deployedAddress) +} + +export async function newContract(contractName: string, args: any[] = []): Promise { + var web3 = getDefaultWeb3() + var Json = _getContractJSON(contractName) + var contract = new web3.eth.Contract(Json.abi) + var adminAccount = (await web3.eth.getAccounts())[0] + let parameter = { + from: adminAccount, + gas: process.env["COVERAGE"] ? 10000000000 : 7000000, + gasPrice: web3.utils.toHex(web3.utils.toWei('1', 'wei')) + } + return await contract.deploy({ data: Json.byteCode, arguments: args }).send(parameter) +} \ No newline at end of file diff --git a/test/utils/Converter.ts b/test/utils/Converter.ts new file mode 100644 index 0000000..ba7269d --- /dev/null +++ b/test/utils/Converter.ts @@ -0,0 +1,11 @@ +import BigNumber from "bignumber.js"; + +export const MAX_UINT256 = "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + +export function decimalStr(value: string): string { + return new BigNumber(value).multipliedBy(10 ** 18).toFixed(0, BigNumber.ROUND_DOWN) +} + +export function gweiStr(gwei: string): string { + return new BigNumber(gwei).multipliedBy(10 ** 9).toFixed(0, BigNumber.ROUND_DOWN) +} \ No newline at end of file diff --git a/test/utils/EVM.ts b/test/utils/EVM.ts new file mode 100644 index 0000000..a1afc9d --- /dev/null +++ b/test/utils/EVM.ts @@ -0,0 +1,83 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +// require('dotenv-flow').config(); + +import { JsonRpcPayload, JsonRpcResponse } from 'web3-core-helpers'; +import Web3 from 'web3'; + +export function getDefaultWeb3() { + return new Web3(process.env.RPC_NODE_URI) +} + +export class EVM { + private provider = new Web3.providers.HttpProvider(process.env.RPC_NODE_URI); + + public async reset(id: string): Promise { + if (!id) { + throw new Error('id must be set'); + } + + await this.callJsonrpcMethod('evm_revert', [id]); + + return this.snapshot(); + } + + public async snapshot(): Promise { + return this.callJsonrpcMethod('evm_snapshot'); + } + + public async evmRevert(id: string): Promise { + return this.callJsonrpcMethod('evm_revert', [id]); + } + + public async stopMining(): Promise { + return this.callJsonrpcMethod('miner_stop'); + } + + public async startMining(): Promise { + return this.callJsonrpcMethod('miner_start'); + } + + public async mineBlock(): Promise { + return this.callJsonrpcMethod('evm_mine'); + } + + public async increaseTime(duration: number): Promise { + return this.callJsonrpcMethod('evm_increaseTime', [duration]); + } + + public async callJsonrpcMethod(method: string, params?: (any[])): Promise { + const args: JsonRpcPayload = { + method, + params, + jsonrpc: '2.0', + id: new Date().getTime(), + }; + + const response = await this.send(args); + + return response.result; + } + + private async send(args: JsonRpcPayload): Promise { + return new Promise((resolve, reject) => { + const callback: any = (error: Error, val: JsonRpcResponse): void => { + if (error) { + reject(error); + } else { + resolve(val); + } + }; + + this.provider.send( + args, + callback, + ); + }); + } +} diff --git a/test/utils/Log.ts b/test/utils/Log.ts new file mode 100644 index 0000000..c2bc65d --- /dev/null +++ b/test/utils/Log.ts @@ -0,0 +1,29 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +import { TransactionReceipt } from "web3-core" + +export const blueText = x => `\x1b[36m${x}\x1b[0m`; +export const yellowText = x => `\x1b[33m${x}\x1b[0m`; +export const greenText = x => `\x1b[32m${x}\x1b[0m`; +export const redText = x => `\x1b[31m${x}\x1b[0m`; +export const numberWithCommas = x => x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); + +export function logGas(receipt: TransactionReceipt, desc: string) { + const gasUsed = receipt.gasUsed; + let colorFn; + + if (gasUsed < 80000) { + colorFn = greenText; + } else if (gasUsed < 200000) { + colorFn = yellowText; + } else { + colorFn = redText; + } + + console.log(("Gas used:").padEnd(60, '.'), blueText(desc) + " ", colorFn(numberWithCommas(gasUsed).padStart(5))); +} \ No newline at end of file diff --git a/test/utils/SlippageFormula.ts b/test/utils/SlippageFormula.ts new file mode 100644 index 0000000..9f90189 --- /dev/null +++ b/test/utils/SlippageFormula.ts @@ -0,0 +1,11 @@ +function calculateSlippage(buyPercentage: number) { + const k = 0.1 + console.log(buyPercentage, ":", ((1 / (1 - buyPercentage)) * k - k) * 100, "%") +} + +// calculateSlippage(0.01) +// calculateSlippage(0.05) +// calculateSlippage(0.1) +// calculateSlippage(0.2) +// calculateSlippage(0.5) +// calculateSlippage(0.7) diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..5ecfa5e --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "lib": ["es2015", "es2016", "es2017", "dom"], + "strict": false, + "sourceMap": true, + "declaration": true, + "downlevelIteration": true, + "noUnusedLocals": true, + "esModuleInterop": true, + "outDir": "dist", + "resolveJsonModule": true, + "allowSyntheticDefaultImports": true, + "typeRoots": ["node_modules/@types"], + "types": ["node", "mocha", "chai"] + }, + "include": ["src", "test"], + "exclude": ["scripts/**/*", "build/**/*", "migrations/**/*"], + "compileOnSave": true +} diff --git a/tslint.json b/tslint.json new file mode 100644 index 0000000..8014982 --- /dev/null +++ b/tslint.json @@ -0,0 +1,13 @@ +{ + "extends": ["tslint-config-airbnb", "tslint-no-focused-test"], + "rules": { + "import-name": false, + "no-floating-promises": true, + "no-focused-test": true, + "variable-name": [ + true, + "allow-pascal-case", + "ban-keywords" + ] + } +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..f554761 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,5667 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.1": + version "7.10.1" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.1.tgz#d5481c5095daa1c57e16e54c6f9198443afb49ff" + dependencies: + "@babel/highlight" "^7.10.1" + +"@babel/generator@^7.10.1": + version "7.10.2" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.10.2.tgz#0fa5b5b2389db8bfdfcc3492b551ee20f5dd69a9" + dependencies: + "@babel/types" "^7.10.2" + jsesc "^2.5.1" + lodash "^4.17.13" + source-map "^0.5.0" + +"@babel/helper-function-name@^7.10.1": + version "7.10.1" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.1.tgz#92bd63829bfc9215aca9d9defa85f56b539454f4" + dependencies: + "@babel/helper-get-function-arity" "^7.10.1" + "@babel/template" "^7.10.1" + "@babel/types" "^7.10.1" + +"@babel/helper-get-function-arity@^7.10.1": + version "7.10.1" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.1.tgz#7303390a81ba7cb59613895a192b93850e373f7d" + dependencies: + "@babel/types" "^7.10.1" + +"@babel/helper-split-export-declaration@^7.10.1": + version "7.10.1" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.1.tgz#c6f4be1cbc15e3a868e4c64a17d5d31d754da35f" + dependencies: + "@babel/types" "^7.10.1" + +"@babel/helper-validator-identifier@^7.10.1": + version "7.10.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.1.tgz#5770b0c1a826c4f53f5ede5e153163e0318e94b5" + +"@babel/highlight@^7.10.1": + version "7.10.1" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.1.tgz#841d098ba613ba1a427a2b383d79e35552c38ae0" + dependencies: + "@babel/helper-validator-identifier" "^7.10.1" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.10.1", "@babel/parser@^7.7.0": + version "7.10.2" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.10.2.tgz#871807f10442b92ff97e4783b9b54f6a0ca812d0" + +"@babel/template@^7.10.1": + version "7.10.1" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.1.tgz#e167154a94cb5f14b28dc58f5356d2162f539811" + dependencies: + "@babel/code-frame" "^7.10.1" + "@babel/parser" "^7.10.1" + "@babel/types" "^7.10.1" + +"@babel/traverse@^7.7.0": + version "7.10.1" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.10.1.tgz#bbcef3031e4152a6c0b50147f4958df54ca0dd27" + dependencies: + "@babel/code-frame" "^7.10.1" + "@babel/generator" "^7.10.1" + "@babel/helper-function-name" "^7.10.1" + "@babel/helper-split-export-declaration" "^7.10.1" + "@babel/parser" "^7.10.1" + "@babel/types" "^7.10.1" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.13" + +"@babel/types@^7.10.1", "@babel/types@^7.10.2", "@babel/types@^7.7.0": + version "7.10.2" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.10.2.tgz#30283be31cad0dbf6fb00bd40641ca0ea675172d" + dependencies: + "@babel/helper-validator-identifier" "^7.10.1" + lodash "^4.17.13" + to-fast-properties "^2.0.0" + +"@ethersproject/abi@5.0.0-beta.153": + version "5.0.0-beta.153" + resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.0.0-beta.153.tgz#43a37172b33794e4562999f6e2d555b7599a8eee" + dependencies: + "@ethersproject/address" ">=5.0.0-beta.128" + "@ethersproject/bignumber" ">=5.0.0-beta.130" + "@ethersproject/bytes" ">=5.0.0-beta.129" + "@ethersproject/constants" ">=5.0.0-beta.128" + "@ethersproject/hash" ">=5.0.0-beta.128" + "@ethersproject/keccak256" ">=5.0.0-beta.127" + "@ethersproject/logger" ">=5.0.0-beta.129" + "@ethersproject/properties" ">=5.0.0-beta.131" + "@ethersproject/strings" ">=5.0.0-beta.130" + +"@ethersproject/address@>=5.0.0-beta.128": + version "5.0.0-beta.135" + resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.0.0-beta.135.tgz#8d4697c81dc27758b05e7eb7507c254f2ef0e5dc" + dependencies: + "@ethersproject/bignumber" ">=5.0.0-beta.138" + "@ethersproject/bytes" ">=5.0.0-beta.137" + "@ethersproject/keccak256" ">=5.0.0-beta.131" + "@ethersproject/logger" ">=5.0.0-beta.137" + "@ethersproject/rlp" ">=5.0.0-beta.132" + bn.js "^4.4.0" + +"@ethersproject/bignumber@>=5.0.0-beta.130", "@ethersproject/bignumber@>=5.0.0-beta.138": + version "5.0.0-beta.139" + resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.0.0-beta.139.tgz#12a4fa5a76ee90f77932326311caf04e1de1cae0" + dependencies: + "@ethersproject/bytes" ">=5.0.0-beta.137" + "@ethersproject/logger" ">=5.0.0-beta.137" + "@ethersproject/properties" ">=5.0.0-beta.140" + bn.js "^4.4.0" + +"@ethersproject/bytes@>=5.0.0-beta.129", "@ethersproject/bytes@>=5.0.0-beta.137": + version "5.0.0-beta.138" + resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.0.0-beta.138.tgz#86e1f6c4016443f2b5236627fa656e7c56077a56" + dependencies: + "@ethersproject/logger" ">=5.0.0-beta.137" + +"@ethersproject/constants@>=5.0.0-beta.128", "@ethersproject/constants@>=5.0.0-beta.133": + version "5.0.0-beta.134" + resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.0.0-beta.134.tgz#b81c42373a00cb21604a94aa8642454fb35bb764" + dependencies: + "@ethersproject/bignumber" ">=5.0.0-beta.138" + +"@ethersproject/hash@>=5.0.0-beta.128": + version "5.0.0-beta.134" + resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.0.0-beta.134.tgz#e1fdb69b42f5d31c343bcbf183043853b9b8e9dd" + dependencies: + "@ethersproject/bytes" ">=5.0.0-beta.137" + "@ethersproject/keccak256" ">=5.0.0-beta.131" + "@ethersproject/logger" ">=5.0.0-beta.137" + "@ethersproject/strings" ">=5.0.0-beta.136" + +"@ethersproject/keccak256@>=5.0.0-beta.127", "@ethersproject/keccak256@>=5.0.0-beta.131": + version "5.0.0-beta.132" + resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.0.0-beta.132.tgz#38c128194a88aba690b6aca43cae57df420408d7" + dependencies: + "@ethersproject/bytes" ">=5.0.0-beta.137" + js-sha3 "0.5.7" + +"@ethersproject/logger@>=5.0.0-beta.129", "@ethersproject/logger@>=5.0.0-beta.137": + version "5.0.0-beta.137" + resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.0.0-beta.137.tgz#781582b8b04d0ced01e9c1608c9887d31d95b8ee" + +"@ethersproject/properties@>=5.0.0-beta.131", "@ethersproject/properties@>=5.0.0-beta.140": + version "5.0.0-beta.143" + resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.0.0-beta.143.tgz#604ba072ee91e386e1bfab70413c34165fa9c913" + dependencies: + "@ethersproject/logger" ">=5.0.0-beta.137" + +"@ethersproject/rlp@>=5.0.0-beta.132": + version "5.0.0-beta.133" + resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.0.0-beta.133.tgz#e51b2e8d51fd70a5872f85f11741193a6b118110" + dependencies: + "@ethersproject/bytes" ">=5.0.0-beta.137" + "@ethersproject/logger" ">=5.0.0-beta.137" + +"@ethersproject/strings@>=5.0.0-beta.130", "@ethersproject/strings@>=5.0.0-beta.136": + version "5.0.0-beta.137" + resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.0.0-beta.137.tgz#1e9730a701e7a44c3f1b4e1c7e134665cdd51d7b" + dependencies: + "@ethersproject/bytes" ">=5.0.0-beta.137" + "@ethersproject/constants" ">=5.0.0-beta.133" + "@ethersproject/logger" ">=5.0.0-beta.137" + +"@nodelib/fs.scandir@2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b" + dependencies: + "@nodelib/fs.stat" "2.0.3" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.3", "@nodelib/fs.stat@^2.0.2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz#34dc5f4cabbc720f4e60f75a747e7ecd6c175bd3" + +"@nodelib/fs.walk@^1.2.3": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz#011b9202a70a6366e436ca5c065844528ab04976" + dependencies: + "@nodelib/fs.scandir" "2.1.3" + fastq "^1.6.0" + +"@sindresorhus/is@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" + +"@solidity-parser/parser@^0.6.0", "@solidity-parser/parser@^0.6.1": + version "0.6.2" + resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.6.2.tgz#49707fc4e06649d39d6b25bdab2e9093d372ce50" + +"@szmarczak/http-timer@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" + dependencies: + defer-to-connect "^1.0.1" + +"@truffle/error@^0.0.7": + version "0.0.7" + resolved "https://registry.yarnpkg.com/@truffle/error/-/error-0.0.7.tgz#e9db39885575647ef08bf624b0c13fe46d41a209" + +"@truffle/interface-adapter@^0.3.0": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@truffle/interface-adapter/-/interface-adapter-0.3.3.tgz#61305378cf81776769ef36c60d394e568ac4a2ee" + dependencies: + bn.js "^4.11.8" + ethers "^4.0.32" + lodash "^4.17.13" + web3 "1.2.2" + +"@truffle/provider@^0.1.17": + version "0.1.19" + resolved "https://registry.yarnpkg.com/@truffle/provider/-/provider-0.1.19.tgz#3e6f15fdd8475ca5d0c846d2b412cc823f1fb767" + dependencies: + "@truffle/error" "^0.0.7" + "@truffle/interface-adapter" "^0.3.0" + web3 "1.2.1" + +"@types/bn.js@^4.11.3", "@types/bn.js@^4.11.4": + version "4.11.6" + resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c" + dependencies: + "@types/node" "*" + +"@types/chai@^4.2.11": + version "4.2.11" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.11.tgz#d3614d6c5f500142358e6ed24e1bf16657536c50" + +"@types/es6-promisify@^6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@types/es6-promisify/-/es6-promisify-6.0.0.tgz#a554e8c9c28466720a96b20c9f6b139249b7d375" + +"@types/events@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" + +"@types/glob@^7.1.1": + version "7.1.1" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575" + dependencies: + "@types/events" "*" + "@types/minimatch" "*" + "@types/node" "*" + +"@types/minimatch@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" + +"@types/mocha@^7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-7.0.2.tgz#b17f16cf933597e10d6d78eae3251e692ce8b0ce" + +"@types/node@*": + version "14.0.10" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.10.tgz#dbfaa170bd9eafccccb6d7060743a761b0844afd" + +"@types/node@^10.12.18", "@types/node@^10.3.2": + version "10.17.24" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.24.tgz#c57511e3a19c4b5e9692bb2995c40a3a52167944" + +"@types/node@^12.6.1": + version "12.12.43" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.43.tgz#b60ce047822e526e7a9252e50844eee79d5386ff" + +"@web3-js/scrypt-shim@^0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@web3-js/scrypt-shim/-/scrypt-shim-0.1.0.tgz#0bf7529ab6788311d3e07586f7d89107c3bea2cc" + dependencies: + scryptsy "^2.1.0" + semver "^6.3.0" + +"@web3-js/websocket@^1.0.29": + version "1.0.30" + resolved "https://registry.yarnpkg.com/@web3-js/websocket/-/websocket-1.0.30.tgz#9ea15b7b582cf3bf3e8bc1f4d3d54c0731a87f87" + dependencies: + debug "^2.2.0" + es5-ext "^0.10.50" + nan "^2.14.0" + typedarray-to-buffer "^3.1.5" + yaeti "^0.0.6" + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + +abbrev@1.0.x: + version "1.0.9" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" + +accepts@~1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" + dependencies: + mime-types "~2.1.24" + negotiator "0.6.2" + +address@^1.0.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/address/-/address-1.1.2.tgz#bf1116c9c758c51b7a933d296b72c221ed9428b6" + +aes-js@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" + +ajv@^6.5.5: + version "6.12.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.2.tgz#c629c5eced17baf314437918d2da88c99d5958cd" + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +amdefine@>=0.0.4: + version "1.0.1" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + +ansi-colors@3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + +ansi-regex@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + dependencies: + color-convert "^1.9.0" + +any-promise@1.3.0, any-promise@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + +anymatch@^1.3.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" + dependencies: + micromatch "^2.1.5" + normalize-path "^2.0.0" + +anymatch@~3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + dependencies: + arr-flatten "^1.0.1" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + +arr-flatten@^1.0.1, arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + +array-filter@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-1.0.0.tgz#baf79e62e6ef4c2a4c0b831232daffec251f9d83" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + +array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + +asn1.js@^4.0.0: + version "4.10.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +asn1@~0.2.3: + version "0.2.4" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + +assert@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/assert/-/assert-2.0.0.tgz#95fc1c616d48713510680f2eaf2d10dd22e02d32" + dependencies: + es6-object-assign "^1.1.0" + is-nan "^1.2.1" + object-is "^1.0.1" + util "^0.12.0" + +assertion-error@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + +async-each@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" + +async-limiter@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" + +async@1.x: + version "1.5.2" + resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +atob@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + +available-typed-arrays@^1.0.0, available-typed-arrays@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz#6b098ca9d8039079ee3f77f7b783c4480ba513f5" + dependencies: + array-filter "^1.0.0" + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + +aws4@^1.8.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.10.0.tgz#a17b3a8ea811060e74d47d306122400ad4497ae2" + +babel-cli@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-cli/-/babel-cli-6.26.0.tgz#502ab54874d7db88ad00b887a06383ce03d002f1" + dependencies: + babel-core "^6.26.0" + babel-polyfill "^6.26.0" + babel-register "^6.26.0" + babel-runtime "^6.26.0" + commander "^2.11.0" + convert-source-map "^1.5.0" + fs-readdir-recursive "^1.0.0" + glob "^7.1.2" + lodash "^4.17.4" + output-file-sync "^1.1.2" + path-is-absolute "^1.0.1" + slash "^1.0.0" + source-map "^0.5.6" + v8flags "^2.1.1" + optionalDependencies: + chokidar "^1.6.1" + +babel-code-frame@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + dependencies: + chalk "^1.1.3" + esutils "^2.0.2" + js-tokens "^3.0.2" + +babel-core@^6.26.0: + version "6.26.3" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" + dependencies: + babel-code-frame "^6.26.0" + babel-generator "^6.26.0" + babel-helpers "^6.24.1" + babel-messages "^6.23.0" + babel-register "^6.26.0" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + convert-source-map "^1.5.1" + debug "^2.6.9" + json5 "^0.5.1" + lodash "^4.17.4" + minimatch "^3.0.4" + path-is-absolute "^1.0.1" + private "^0.1.8" + slash "^1.0.0" + source-map "^0.5.7" + +babel-eslint@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232" + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.7.0" + "@babel/traverse" "^7.7.0" + "@babel/types" "^7.7.0" + eslint-visitor-keys "^1.0.0" + resolve "^1.12.0" + +babel-generator@^6.26.0: + version "6.26.1" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" + dependencies: + babel-messages "^6.23.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + detect-indent "^4.0.0" + jsesc "^1.3.0" + lodash "^4.17.4" + source-map "^0.5.7" + trim-right "^1.0.1" + +babel-helpers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-messages@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" + dependencies: + babel-runtime "^6.22.0" + +babel-polyfill@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" + dependencies: + babel-runtime "^6.26.0" + core-js "^2.5.0" + regenerator-runtime "^0.10.5" + +babel-register@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" + dependencies: + babel-core "^6.26.0" + babel-runtime "^6.26.0" + core-js "^2.5.0" + home-or-tmp "^2.0.0" + lodash "^4.17.4" + mkdirp "^0.5.1" + source-map-support "^0.4.15" + +babel-runtime@^6.22.0, babel-runtime@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + +babel-template@^6.24.1, babel-template@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" + dependencies: + babel-runtime "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + lodash "^4.17.4" + +babel-traverse@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" + dependencies: + babel-code-frame "^6.26.0" + babel-messages "^6.23.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + debug "^2.6.8" + globals "^9.18.0" + invariant "^2.2.2" + lodash "^4.17.4" + +babel-types@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" + dependencies: + babel-runtime "^6.26.0" + esutils "^2.0.2" + lodash "^4.17.4" + to-fast-properties "^1.0.3" + +babylon@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + +base-x@^3.0.8: + version "3.0.8" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.8.tgz#1e1106c2537f0162e8b52474a557ebb09000018d" + dependencies: + safe-buffer "^5.0.1" + +base64-js@^1.0.2: + version "1.3.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + dependencies: + tweetnacl "^0.14.3" + +bignumber.js@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.0.tgz#805880f84a329b5eac6e7cb6f8274b6d82bdf075" + +binary-extensions@^1.0.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" + +binary-extensions@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c" + +bindings@^1.2.1, bindings@^1.3.1, bindings@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + dependencies: + file-uri-to-path "1.0.0" + +bip66@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/bip66/-/bip66-1.1.5.tgz#01fa8748785ca70955d5011217d1b3139969ca22" + dependencies: + safe-buffer "^5.0.1" + +bl@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" + dependencies: + readable-stream "^2.3.5" + safe-buffer "^5.1.1" + +bluebird@^3.5.0: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + +bn.js@4.11.6: + version "4.11.6" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" + +bn.js@4.11.8: + version "4.11.8" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.0, bn.js@^4.11.1, bn.js@^4.11.6, bn.js@^4.11.8, bn.js@^4.4.0: + version "4.11.9" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.9.tgz#26d556829458f9d1e81fc48952493d0ba3507828" + +bn.js@^5.1.1, bn.js@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.2.tgz#c9686902d3c9a27729f43ab10f9d79c2004da7b0" + +body-parser@1.19.0, body-parser@^1.16.0: + version "1.19.0" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" + dependencies: + bytes "3.1.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "1.7.2" + iconv-lite "0.4.24" + on-finished "~2.3.0" + qs "6.7.0" + raw-body "2.4.0" + type-is "~1.6.17" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + +braces@^2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +braces@^3.0.1, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + dependencies: + fill-range "^7.0.1" + +brorand@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + +browser-stdout@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + +browserify-aes@^1.0.0, browserify-aes@^1.0.4, browserify-aes@^1.0.6: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" + dependencies: + bn.js "^4.1.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.0.tgz#545d0b1b07e6b2c99211082bf1b12cce7a0b0e11" + dependencies: + bn.js "^5.1.1" + browserify-rsa "^4.0.1" + create-hash "^1.2.0" + create-hmac "^1.1.7" + elliptic "^6.5.2" + inherits "^2.0.4" + parse-asn1 "^5.1.5" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +buffer-alloc-unsafe@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" + +buffer-alloc@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" + dependencies: + buffer-alloc-unsafe "^1.1.0" + buffer-fill "^1.0.0" + +buffer-crc32@~0.2.3: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + +buffer-fill@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" + +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + +buffer-to-arraybuffer@^0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz#6064a40fa76eb43c723aba9ef8f6e1216d10511a" + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + +buffer@^5.0.5, buffer@^5.2.1, buffer@^5.5.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.6.0.tgz#a31749dc7d81d84db08abf937b6b8c4033f62786" + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + +bytes@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +cacheable-request@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" + dependencies: + clone-response "^1.0.2" + get-stream "^5.1.0" + http-cache-semantics "^4.0.0" + keyv "^3.0.0" + lowercase-keys "^2.0.0" + normalize-url "^4.1.0" + responselike "^1.0.2" + +camelcase@^5.0.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + +chai-bignumber@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chai-bignumber/-/chai-bignumber-3.0.0.tgz#e90cf1f468355bbb11a9acd051222586cd2648a9" + +chai@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5" + dependencies: + assertion-error "^1.1.0" + check-error "^1.0.2" + deep-eql "^3.0.1" + get-func-name "^2.0.0" + pathval "^1.1.0" + type-detect "^4.0.5" + +chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chalk@^2.0.0, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +check-error@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" + +chokidar@3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.0.tgz#12c0714668c55800f659e262d4962a97faf554a6" + dependencies: + anymatch "~3.1.1" + braces "~3.0.2" + glob-parent "~5.1.0" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.2.0" + optionalDependencies: + fsevents "~2.1.1" + +chokidar@^1.6.1: + version "1.7.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" + dependencies: + anymatch "^1.3.0" + async-each "^1.0.0" + glob-parent "^2.0.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^2.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + optionalDependencies: + fsevents "^1.0.0" + +chownr@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + +cids@^0.7.1: + version "0.7.5" + resolved "https://registry.yarnpkg.com/cids/-/cids-0.7.5.tgz#60a08138a99bfb69b6be4ceb63bfef7a396b28b2" + dependencies: + buffer "^5.5.0" + class-is "^1.1.0" + multibase "~0.6.0" + multicodec "^1.0.0" + multihashes "~0.4.15" + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +class-is@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/class-is/-/class-is-1.1.0.tgz#9d3c0fba0440d211d843cec3dedfa48055005825" + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +cliui@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" + dependencies: + string-width "^3.1.0" + strip-ansi "^5.2.0" + wrap-ansi "^5.1.0" + +clone-response@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" + dependencies: + mimic-response "^1.0.0" + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + +combined-stream@^1.0.6, combined-stream@~1.0.6: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + dependencies: + delayed-stream "~1.0.0" + +commander@^2.11.0, commander@~2.20.3: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + +commander@~2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" + dependencies: + graceful-readlink ">= 1.0.0" + +component-emitter@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +content-disposition@0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" + dependencies: + safe-buffer "5.1.2" + +content-hash@^2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/content-hash/-/content-hash-2.5.2.tgz#bbc2655e7c21f14fd3bfc7b7d4bfe6e454c9e211" + dependencies: + cids "^0.7.1" + multicodec "^0.5.5" + multihashes "^0.4.15" + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + +convert-source-map@^1.5.0, convert-source-map@^1.5.1: + version "1.7.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" + dependencies: + safe-buffer "~5.1.1" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + +cookie@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" + +cookiejar@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c" + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + +core-js@^2.4.0, core-js@^2.5.0: + version "2.6.11" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +cors@^2.8.1: + version "2.8.5" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + dependencies: + object-assign "^4" + vary "^1" + +create-ecdh@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" + dependencies: + bn.js "^4.1.0" + elliptic "^6.0.0" + +create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +cross-spawn@^6.0.0: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +crypto-browserify@3.12.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + +d@1, d@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" + dependencies: + es5-ext "^0.10.50" + type "^1.0.1" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + +death@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/death/-/death-1.1.0.tgz#01aa9c401edd92750514470b8266390c66c67318" + +debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.8, debug@^2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + dependencies: + ms "2.0.0" + +debug@3.2.6: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + dependencies: + ms "^2.1.1" + +debug@^4.1.0, debug@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + dependencies: + ms "^2.1.1" + +decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + +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" + +decompress-response@^3.2.0, decompress-response@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + dependencies: + mimic-response "^1.0.0" + +decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/decompress-tar/-/decompress-tar-4.1.1.tgz#718cbd3fcb16209716e70a26b84e7ba4592e5af1" + dependencies: + file-type "^5.2.0" + is-stream "^1.1.0" + tar-stream "^1.5.2" + +decompress-tarbz2@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz#3082a5b880ea4043816349f378b56c516be1a39b" + dependencies: + decompress-tar "^4.1.0" + file-type "^6.1.0" + is-stream "^1.1.0" + seek-bzip "^1.0.5" + unbzip2-stream "^1.0.9" + +decompress-targz@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/decompress-targz/-/decompress-targz-4.1.1.tgz#c09bc35c4d11f3de09f2d2da53e9de23e7ce1eee" + dependencies: + decompress-tar "^4.1.1" + file-type "^5.2.0" + is-stream "^1.1.0" + +decompress-unzip@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/decompress-unzip/-/decompress-unzip-4.0.1.tgz#deaaccdfd14aeaf85578f733ae8210f9b4848f69" + dependencies: + file-type "^3.8.0" + get-stream "^2.2.0" + pify "^2.3.0" + yauzl "^2.4.2" + +decompress@^4.0.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/decompress/-/decompress-4.2.1.tgz#007f55cc6a62c055afa37c07eb6a4ee1b773f118" + dependencies: + decompress-tar "^4.0.0" + decompress-tarbz2 "^4.0.0" + decompress-targz "^4.0.0" + decompress-unzip "^4.0.1" + graceful-fs "^4.1.10" + make-dir "^1.0.0" + pify "^2.3.0" + strip-dirs "^2.0.0" + +deep-eql@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" + dependencies: + type-detect "^4.0.0" + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + +defer-to-connect@^1.0.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" + +define-properties@^1.1.2, define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + dependencies: + object-keys "^1.0.12" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + +des.js@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + +detect-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + dependencies: + repeating "^2.0.0" + +detect-port@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/detect-port/-/detect-port-1.3.0.tgz#d9c40e9accadd4df5cac6a782aefd014d573d1f1" + dependencies: + address "^1.0.1" + debug "^2.6.0" + +diff@3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + dependencies: + path-type "^4.0.0" + +dir-to-object@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dir-to-object/-/dir-to-object-2.0.0.tgz#29723e9bd1c3e58e4f307bd04ff634c0370c8f8a" + +dom-walk@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" + +dotenv-flow@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/dotenv-flow/-/dotenv-flow-3.1.0.tgz#2abcb4661cf2d0ca5b46d8ff5e95c1045ade9938" + dependencies: + dotenv "^8.0.0" + +dotenv@^8.0.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" + +drbg.js@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/drbg.js/-/drbg.js-1.0.1.tgz#3e36b6c42b37043823cdbc332d58f31e2445480b" + dependencies: + browserify-aes "^1.0.6" + create-hash "^1.1.2" + create-hmac "^1.1.4" + +duplexer3@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + +elliptic@6.3.3: + version "6.3.3" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.3.3.tgz#5482d9646d54bcb89fd7d994fc9e2e9568876e3f" + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + inherits "^2.0.1" + +elliptic@6.5.2, elliptic@^6.0.0, elliptic@^6.4.0, elliptic@^6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.2.tgz#05c5678d7173c049d8ca433552224a495d0e3762" + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + hmac-drbg "^1.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.0" + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + +emoji-regex@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.0.0.tgz#48a2309cc8a1d2e9d23bc6a67c39b63032e76ea4" + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + +end-of-stream@^1.0.0, end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + dependencies: + once "^1.4.0" + +es-abstract@^1.17.0-next.1, es-abstract@^1.17.4, es-abstract@^1.17.5: + version "1.17.5" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.5.tgz#d8c9d1d66c8981fb9200e2251d799eee92774ae9" + dependencies: + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + is-callable "^1.1.5" + is-regex "^1.0.5" + object-inspect "^1.7.0" + object-keys "^1.1.1" + object.assign "^4.1.0" + string.prototype.trimleft "^2.1.1" + string.prototype.trimright "^2.1.1" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +es5-ext@^0.10.35, es5-ext@^0.10.50: + version "0.10.53" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1" + dependencies: + es6-iterator "~2.0.3" + es6-symbol "~3.1.3" + next-tick "~1.0.0" + +es6-iterator@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + +es6-object-assign@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/es6-object-assign/-/es6-object-assign-1.1.0.tgz#c2c3582656247c39ea107cb1e6652b6f9f24523c" + +es6-promisify@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-6.1.1.tgz#46837651b7b06bf6fff893d03f29393668d01621" + +es6-symbol@^3.1.1, es6-symbol@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" + dependencies: + d "^1.0.1" + ext "^1.1.2" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + +escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + +escodegen@1.8.x: + version "1.8.1" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018" + dependencies: + esprima "^2.7.1" + estraverse "^1.9.1" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.2.0" + +eslint-visitor-keys@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.2.0.tgz#74415ac884874495f78ec2a97349525344c981fa" + +esprima-extract-comments@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/esprima-extract-comments/-/esprima-extract-comments-1.1.0.tgz#0dacab567a5900240de6d344cf18c33617becbc9" + dependencies: + esprima "^4.0.0" + +esprima@2.7.x, esprima@^2.7.1: + version "2.7.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + +estraverse@^1.9.1: + version "1.9.3" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44" + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + +eth-ens-namehash@2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz#229ac46eca86d52e0c991e7cb2aef83ff0f68bcf" + dependencies: + idna-uts46-hx "^2.3.1" + js-sha3 "^0.5.7" + +eth-lib@0.2.7: + version "0.2.7" + resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.2.7.tgz#2f93f17b1e23aec3759cd4a3fe20c1286a3fc1ca" + dependencies: + bn.js "^4.11.6" + elliptic "^6.4.0" + xhr-request-promise "^0.1.2" + +eth-lib@^0.1.26: + version "0.1.29" + resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.1.29.tgz#0c11f5060d42da9f931eab6199084734f4dbd1d9" + dependencies: + bn.js "^4.11.6" + elliptic "^6.4.0" + nano-json-stream-parser "^0.1.2" + servify "^0.1.12" + ws "^3.0.0" + xhr-request-promise "^0.1.2" + +eth-lib@^0.2.8: + version "0.2.8" + resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.2.8.tgz#b194058bef4b220ad12ea497431d6cb6aa0623c8" + dependencies: + bn.js "^4.11.6" + elliptic "^6.4.0" + xhr-request-promise "^0.1.2" + +ethereum-bloom-filters@^1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.7.tgz#b7b80735e385dbb7f944ce6b4533e24511306060" + dependencies: + js-sha3 "^0.8.0" + +ethereumjs-common@^1.3.2, ethereumjs-common@^1.5.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/ethereumjs-common/-/ethereumjs-common-1.5.1.tgz#4e75042473a64daec0ed9fe84323dd9576aa5dba" + +ethereumjs-tx@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ethereumjs-tx/-/ethereumjs-tx-2.1.2.tgz#5dfe7688bf177b45c9a23f86cf9104d47ea35fed" + dependencies: + ethereumjs-common "^1.5.0" + ethereumjs-util "^6.0.0" + +ethereumjs-util@6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-6.1.0.tgz#e9c51e5549e8ebd757a339cc00f5380507e799c8" + dependencies: + bn.js "^4.11.0" + create-hash "^1.1.2" + ethjs-util "0.1.6" + keccak "^1.0.2" + rlp "^2.0.0" + safe-buffer "^5.1.1" + secp256k1 "^3.0.1" + +ethereumjs-util@^6.0.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-6.2.0.tgz#23ec79b2488a7d041242f01e25f24e5ad0357960" + dependencies: + "@types/bn.js" "^4.11.3" + bn.js "^4.11.0" + create-hash "^1.1.2" + ethjs-util "0.1.6" + keccak "^2.0.0" + rlp "^2.2.3" + secp256k1 "^3.0.1" + +ethereumjs-util@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.0.2.tgz#7e0d9fcd225ece6e49ee4ea65609d124715f1d15" + dependencies: + "@types/bn.js" "^4.11.3" + bn.js "^5.1.2" + create-hash "^1.1.2" + ethjs-util "0.1.6" + keccak "^3.0.0" + rlp "^2.2.4" + secp256k1 "^4.0.1" + +ethers@4.0.0-beta.3: + version "4.0.0-beta.3" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.0-beta.3.tgz#15bef14e57e94ecbeb7f9b39dd0a4bd435bc9066" + dependencies: + "@types/node" "^10.3.2" + aes-js "3.0.0" + bn.js "^4.4.0" + elliptic "6.3.3" + hash.js "1.1.3" + js-sha3 "0.5.7" + scrypt-js "2.0.3" + setimmediate "1.0.4" + uuid "2.0.1" + xmlhttprequest "1.8.0" + +ethers@^4.0.32: + version "4.0.47" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.47.tgz#91b9cd80473b1136dd547095ff9171bd1fc68c85" + dependencies: + aes-js "3.0.0" + bn.js "^4.4.0" + elliptic "6.5.2" + hash.js "1.1.3" + js-sha3 "0.5.7" + scrypt-js "2.0.4" + setimmediate "1.0.4" + uuid "2.0.1" + xmlhttprequest "1.8.0" + +ethjs-unit@0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" + dependencies: + bn.js "4.11.6" + number-to-bn "1.7.0" + +ethjs-util@0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/ethjs-util/-/ethjs-util-0.1.6.tgz#f308b62f185f9fe6237132fb2a9818866a5cd536" + dependencies: + is-hex-prefixed "1.0.0" + strip-hex-prefix "1.0.0" + +eventemitter3@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7" + +eventemitter3@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.4.tgz#b5463ace635a083d018bdc7c917b4c5f10a85384" + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + dependencies: + is-posix-bracket "^0.1.0" + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + dependencies: + fill-range "^2.1.0" + +express@^4.14.0: + version "4.17.1" + resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" + dependencies: + accepts "~1.3.7" + array-flatten "1.1.1" + body-parser "1.19.0" + content-disposition "0.5.3" + content-type "~1.0.4" + cookie "0.4.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "~1.1.2" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.5" + qs "6.7.0" + range-parser "~1.2.1" + safe-buffer "5.1.2" + send "0.17.1" + serve-static "1.14.1" + setprototypeof "1.1.1" + statuses "~1.5.0" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +ext@^1.1.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/ext/-/ext-1.4.0.tgz#89ae7a07158f79d35517882904324077e4379244" + dependencies: + type "^2.0.0" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + dependencies: + is-extglob "^1.0.0" + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extract-comments@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/extract-comments/-/extract-comments-1.1.0.tgz#b90bca033a056bd69b8ba1c6b6b120fc2ee95c18" + dependencies: + esprima-extract-comments "^1.1.0" + parse-code-context "^1.0.0" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + +fast-deep-equal@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4" + +fast-glob@^3.0.3: + version "3.2.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.2.tgz#ade1a9d91148965d4bf7c51f72e1ca662d32e63d" + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.0" + merge2 "^1.3.0" + micromatch "^4.0.2" + picomatch "^2.2.1" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + +fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + +fastq@^1.6.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.8.0.tgz#550e1f9f59bbc65fe185cb6a9b4d95357107f481" + dependencies: + reusify "^1.0.4" + +fd-slicer@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" + dependencies: + pend "~1.2.0" + +file-type@^3.8.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9" + +file-type@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-5.2.0.tgz#2ddbea7c73ffe36368dfae49dc338c058c2b8ad6" + +file-type@^6.1.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-6.2.0.tgz#e50cd75d356ffed4e306dc4f5bcf52a79903a919" + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + +filename-regex@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" + +fill-range@^2.1.0: + version "2.2.4" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^3.0.0" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + dependencies: + to-regex-range "^5.0.1" + +finalhandler@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.0.0" + +find-up@3.0.0, find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + dependencies: + locate-path "^3.0.0" + +flat@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2" + dependencies: + is-buffer "~2.0.3" + +for-in@^1.0.1, for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + +for-own@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" + dependencies: + for-in "^1.0.1" + +foreach@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +forwarded@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + dependencies: + map-cache "^0.2.2" + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + +fs-extra@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-minipass@^1.2.5: + version "1.2.7" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" + dependencies: + minipass "^2.6.0" + +fs-readdir-recursive@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +fsevents@^1.0.0: + version "1.2.13" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" + dependencies: + bindings "^1.5.0" + nan "^2.12.1" + +fsevents@~2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + +ganache-cli@6.9.0: + version "6.9.0" + resolved "https://registry.yarnpkg.com/ganache-cli/-/ganache-cli-6.9.0.tgz#94d7e26964dff80b7382a33829ec75e15709a948" + dependencies: + ethereumjs-util "6.1.0" + source-map-support "0.5.12" + yargs "13.2.4" + +ganache-cli@^6.9.1: + version "6.9.1" + resolved "https://registry.yarnpkg.com/ganache-cli/-/ganache-cli-6.9.1.tgz#1e13eee098fb9f19b031a191ec3f62ae926ea8b3" + dependencies: + ethereumjs-util "6.1.0" + source-map-support "0.5.12" + yargs "13.2.4" + +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + +get-func-name@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" + +get-stream@^2.2.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-2.3.1.tgz#5f38f93f346009666ee0150a054167f91bdd95de" + dependencies: + object-assign "^4.0.1" + pinkie-promise "^2.0.0" + +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + +get-stream@^4.0.0, get-stream@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + dependencies: + pump "^3.0.0" + +get-stream@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.1.0.tgz#01203cdc92597f9b909067c3e656cc1f4d3c4dc9" + dependencies: + pump "^3.0.0" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + dependencies: + assert-plus "^1.0.0" + +ghost-testrpc@^0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/ghost-testrpc/-/ghost-testrpc-0.0.2.tgz#c4de9557b1d1ae7b2d20bbe474a91378ca90ce92" + dependencies: + chalk "^2.4.2" + node-emoji "^1.10.0" + +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + dependencies: + is-glob "^2.0.0" + +glob-parent@^5.1.0, glob-parent@~5.1.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" + dependencies: + is-glob "^4.0.1" + +glob@7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^5.0.15: + version "5.0.15" + resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.0.0, glob@^7.1.2, glob@^7.1.3: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global-modules@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" + dependencies: + global-prefix "^3.0.0" + +global-prefix@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97" + dependencies: + ini "^1.3.5" + kind-of "^6.0.2" + which "^1.3.1" + +global@~4.3.0: + version "4.3.2" + resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f" + dependencies: + min-document "^2.19.0" + process "~0.5.1" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + +globals@^9.18.0: + version "9.18.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" + +globby@^10.0.1: + version "10.0.2" + resolved "https://registry.yarnpkg.com/globby/-/globby-10.0.2.tgz#277593e745acaa4646c3ab411289ec47a0392543" + dependencies: + "@types/glob" "^7.1.1" + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.0.3" + glob "^7.1.3" + ignore "^5.1.1" + merge2 "^1.2.3" + slash "^3.0.0" + +got@9.6.0: + version "9.6.0" + resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" + dependencies: + "@sindresorhus/is" "^0.14.0" + "@szmarczak/http-timer" "^1.1.2" + cacheable-request "^6.0.0" + decompress-response "^3.3.0" + duplexer3 "^0.1.4" + get-stream "^4.1.0" + lowercase-keys "^1.0.1" + mimic-response "^1.0.1" + p-cancelable "^1.0.0" + to-readable-stream "^1.0.0" + url-parse-lax "^3.0.0" + +got@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/got/-/got-7.1.0.tgz#05450fd84094e6bbea56f451a43a9c289166385a" + dependencies: + decompress-response "^3.2.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + is-plain-obj "^1.1.0" + is-retry-allowed "^1.0.0" + is-stream "^1.0.0" + isurl "^1.0.0-alpha5" + lowercase-keys "^1.0.0" + p-cancelable "^0.3.0" + p-timeout "^1.1.1" + safe-buffer "^5.0.1" + timed-out "^4.0.0" + url-parse-lax "^1.0.0" + url-to-options "^1.0.1" + +graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.2.0: + version "4.2.4" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" + +"graceful-readlink@>= 1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + +growl@1.10.5: + version "1.10.5" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" + +handlebars@^4.0.1: + version "4.7.6" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.6.tgz#d4c05c1baf90e9945f77aa68a7a219aa4a7df74e" + dependencies: + minimist "^1.2.5" + neo-async "^2.6.0" + source-map "^0.6.1" + wordwrap "^1.0.0" + optionalDependencies: + uglify-js "^3.1.4" + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + +har-validator@~5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" + dependencies: + ajv "^6.5.5" + har-schema "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + +has-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + +has-symbol-support-x@^1.4.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" + +has-symbols@^1.0.0, has-symbols@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" + +has-to-string-tag-x@^1.2.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" + dependencies: + has-symbol-support-x "^1.4.1" + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + dependencies: + function-bind "^1.1.1" + +hash-base@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" + dependencies: + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +hash.js@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.3.tgz#340dedbe6290187151c1ea1d777a3448935df846" + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.0" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +he@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + +hmac-drbg@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +home-or-tmp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.1" + +http-cache-semantics@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" + +http-errors@1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-errors@~1.7.2: + version "1.7.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-https@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/http-https/-/http-https-1.0.0.tgz#2f908dd5f1db4068c058cd6e6d4ce392c913389b" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + dependencies: + safer-buffer ">= 2.1.2 < 3" + +idna-uts46-hx@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz#a1dc5c4df37eee522bf66d969cc980e00e8711f9" + dependencies: + punycode "2.1.0" + +ieee754@^1.1.4: + version "1.1.13" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" + +ignore@^5.1.1: + version "5.1.8" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +ini@^1.3.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + +interpret@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" + +invariant@^2.2.2: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + dependencies: + loose-envify "^1.0.0" + +invert-kv@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + dependencies: + kind-of "^6.0.0" + +is-arguments@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.0.4.tgz#3faf966c7cba0ff437fb31f6250082fcf0448cf3" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + dependencies: + binary-extensions "^1.0.0" + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + dependencies: + binary-extensions "^2.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + +is-buffer@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.4.tgz#3e572f23c8411a5cfd9557c849e3665e0b290623" + +is-callable@^1.1.4, is-callable@^1.1.5: + version "1.2.0" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.0.tgz#83336560b54a38e35e3a2df7afd0454d691468bb" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + dependencies: + kind-of "^6.0.0" + +is-date-object@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-dotfile@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + dependencies: + is-primitive "^2.0.0" + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + +is-finite@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + +is-function@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.2.tgz#4f097f30abf6efadac9833b17ca5dc03f8144e08" + +is-generator-function@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.7.tgz#d2132e529bb0000a7f80794d4bdf5cd5e5813522" + +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + dependencies: + is-extglob "^1.0.0" + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + dependencies: + is-extglob "^2.1.1" + +is-hex-prefixed@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" + +is-nan@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.0.tgz#85d1f5482f7051c2019f5673ccebdb06f3b0db03" + dependencies: + define-properties "^1.1.3" + +is-natural-number@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-natural-number/-/is-natural-number-4.0.1.tgz#ab9d76e1db4ced51e35de0c72ebecf09f734cde8" + +is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + dependencies: + kind-of "^3.0.2" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + dependencies: + kind-of "^3.0.2" + +is-number@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + +is-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" + +is-plain-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + +is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + dependencies: + isobject "^3.0.1" + +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + +is-regex@^1.0.5: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.0.tgz#ece38e389e490df0dc21caea2bd596f987f767ff" + dependencies: + has-symbols "^1.0.1" + +is-retry-allowed@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" + +is-stream@^1.0.0, is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + +is-symbol@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" + dependencies: + has-symbols "^1.0.1" + +is-typed-array@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.3.tgz#a4ff5a5e672e1a55f99c7f54e59597af5c1df04d" + dependencies: + available-typed-arrays "^1.0.0" + es-abstract "^1.17.4" + foreach "^2.0.5" + has-symbols "^1.0.1" + +is-typedarray@^1.0.0, is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + +isarray@1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + +isurl@^1.0.0-alpha5: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" + dependencies: + has-to-string-tag-x "^1.2.0" + is-object "^1.0.1" + +js-sha3@0.5.7, js-sha3@^0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" + +js-sha3@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + +js-tokens@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + +js-yaml@3.13.1: + version "3.13.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@3.x: + version "3.14.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482" + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + +jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + +json-buffer@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + +json5@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonschema@^1.2.4: + version "1.2.6" + resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.2.6.tgz#52b0a8e9dc06bbae7295249d03e4b9faee8a0c0b" + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +keccak@^1.0.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/keccak/-/keccak-1.4.0.tgz#572f8a6dbee8e7b3aa421550f9e6408ca2186f80" + dependencies: + bindings "^1.2.1" + inherits "^2.0.3" + nan "^2.2.1" + safe-buffer "^5.1.0" + +keccak@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/keccak/-/keccak-2.1.0.tgz#734ea53f2edcfd0f42cdb8d5f4c358fef052752b" + dependencies: + bindings "^1.5.0" + inherits "^2.0.4" + nan "^2.14.0" + safe-buffer "^5.2.0" + +keccak@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.0.tgz#420d1de4a38a04f33ff8401f0535fb93756861d4" + dependencies: + node-addon-api "^2.0.0" + node-gyp-build "^4.2.0" + +keyv@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" + dependencies: + json-buffer "3.0.0" + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + +lcid@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" + dependencies: + invert-kv "^2.0.0" + +levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +lodash.toarray@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.toarray/-/lodash.toarray-4.4.0.tgz#24c4bfcd6b2fba38bfd0594db1179d8e9b656561" + +lodash@^4.17.13, lodash@^4.17.15, lodash@^4.17.4: + version "4.17.15" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" + +log-symbols@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4" + dependencies: + chalk "^2.4.2" + +loose-envify@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + +lowercase-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" + +make-dir@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" + dependencies: + pify "^3.0.0" + +make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + +map-age-cleaner@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" + dependencies: + p-defer "^1.0.0" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + dependencies: + object-visit "^1.0.0" + +math-random@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.4.tgz#5dd6943c938548267016d4e34f057583080c514c" + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + +mem@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" + dependencies: + map-age-cleaner "^0.1.1" + mimic-fn "^2.0.0" + p-is-promise "^2.0.0" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + +merge2@^1.2.3, merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + +micromatch@^2.1.5: + version "2.3.11" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + +micromatch@^3.1.10: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +micromatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" + dependencies: + braces "^3.0.1" + picomatch "^2.0.5" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +mime-db@1.44.0: + version "1.44.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" + +mime-types@^2.1.12, mime-types@^2.1.16, mime-types@~2.1.19, mime-types@~2.1.24: + version "2.1.27" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" + dependencies: + mime-db "1.44.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + +mimic-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + +mimic-response@^1.0.0, mimic-response@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + +min-document@^2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" + dependencies: + dom-walk "^0.1.0" + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + +minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + +"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + +minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.2.1: + version "1.3.3" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" + dependencies: + minipass "^2.9.0" + +mixin-deep@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp-promise@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz#e9b8f68e552c68a9c1713b84883f7a1dd039b8a1" + dependencies: + mkdirp "*" + +mkdirp@*: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + +mkdirp@0.5.5, mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1: + version "0.5.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + dependencies: + minimist "^1.2.5" + +mocha@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-7.2.0.tgz#01cc227b00d875ab1eed03a75106689cfed5a604" + dependencies: + ansi-colors "3.2.3" + browser-stdout "1.3.1" + chokidar "3.3.0" + debug "3.2.6" + diff "3.5.0" + escape-string-regexp "1.0.5" + find-up "3.0.0" + glob "7.1.3" + growl "1.10.5" + he "1.2.0" + js-yaml "3.13.1" + log-symbols "3.0.0" + minimatch "3.0.4" + mkdirp "0.5.5" + ms "2.1.1" + node-environment-flags "1.0.6" + object.assign "4.1.0" + strip-json-comments "2.0.1" + supports-color "6.0.0" + which "1.3.1" + wide-align "1.1.3" + yargs "13.3.2" + yargs-parser "13.1.2" + yargs-unparser "1.6.0" + +mock-fs@^4.1.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.12.0.tgz#a5d50b12d2d75e5bec9dac3b67ffe3c41d31ade4" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + +ms@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + +ms@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + +multibase@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.7.0.tgz#1adfc1c50abe05eefeb5091ac0c2728d6b84581b" + dependencies: + base-x "^3.0.8" + buffer "^5.5.0" + +multibase@~0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.6.1.tgz#b76df6298536cc17b9f6a6db53ec88f85f8cc12b" + dependencies: + base-x "^3.0.8" + buffer "^5.5.0" + +multicodec@^0.5.5: + version "0.5.7" + resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-0.5.7.tgz#1fb3f9dd866a10a55d226e194abba2dcc1ee9ffd" + dependencies: + varint "^5.0.0" + +multicodec@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-1.0.1.tgz#4e2812d726b9f7c7d615d3ebc5787d36a08680f9" + dependencies: + buffer "^5.5.0" + varint "^5.0.0" + +multihashes@^0.4.15, multihashes@~0.4.15: + version "0.4.19" + resolved "https://registry.yarnpkg.com/multihashes/-/multihashes-0.4.19.tgz#d7493cf028e48747122f350908ea13d12d204813" + dependencies: + buffer "^5.5.0" + multibase "^0.7.0" + varint "^5.0.0" + +nan@^2.12.1, nan@^2.14.0, nan@^2.2.1: + version "2.14.1" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01" + +nano-json-stream-parser@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz#0cc8f6d0e2b622b479c40d499c46d64b755c6f5f" + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +negotiator@0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + +neo-async@^2.6.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" + +next-tick@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + +node-addon-api@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.1.tgz#4fd0931bf6d7e48b219ff3e6abc73cbb0252b7a3" + +node-emoji@^1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.10.0.tgz#8886abd25d9c7bb61802a658523d1f8d2a89b2da" + dependencies: + lodash.toarray "^4.4.0" + +node-environment-flags@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.6.tgz#a30ac13621f6f7d674260a54dede048c3982c088" + dependencies: + object.getownpropertydescriptors "^2.0.3" + semver "^5.7.0" + +node-gyp-build@^4.2.0: + version "4.2.2" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.2.2.tgz#3f44b65adaafd42fb6c3d81afd630e45c847eb66" + +nopt@3.x: + version "3.0.6" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + dependencies: + abbrev "1" + +normalize-path@^2.0.0, normalize-path@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + +normalize-url@^4.1.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + dependencies: + path-key "^2.0.0" + +number-to-bn@1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/number-to-bn/-/number-to-bn-1.7.0.tgz#bb3623592f7e5f9e0030b1977bd41a0c53fe1ea0" + dependencies: + bn.js "4.11.6" + strip-hex-prefix "1.0.0" + +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + +object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-inspect@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" + +object-is@^1.0.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.2.tgz#c5d2e87ff9e119f78b7a088441519e2eec1573b6" + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + +object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + dependencies: + isobject "^3.0.0" + +object.assign@4.1.0, object.assign@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.1" + has-symbols "^1.0.0" + object-keys "^1.0.11" + +object.getownpropertydescriptors@^2.0.3: + version "2.1.0" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649" + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + +object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + dependencies: + isobject "^3.0.1" + +oboe@2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/oboe/-/oboe-2.1.4.tgz#20c88cdb0c15371bb04119257d4fdd34b0aa49f6" + dependencies: + http-https "^1.0.0" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + dependencies: + ee-first "1.1.1" + +once@1.x, once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +optionator@^0.8.1: + version "0.8.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-locale@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" + dependencies: + execa "^1.0.0" + lcid "^2.0.0" + mem "^4.0.0" + +os-tmpdir@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + +output-file-sync@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" + dependencies: + graceful-fs "^4.1.4" + mkdirp "^0.5.1" + object-assign "^4.1.0" + +p-cancelable@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa" + +p-cancelable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" + +p-defer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + +p-is-promise@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" + +p-limit@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + dependencies: + p-try "^2.0.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + dependencies: + p-limit "^2.0.0" + +p-timeout@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-1.2.1.tgz#5eb3b353b7fce99f101a1038880bb054ebbea386" + dependencies: + p-finally "^1.0.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + +parse-asn1@^5.0.0, parse-asn1@^5.1.5: + version "5.1.5" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.5.tgz#003271343da58dc94cace494faef3d2147ecea0e" + dependencies: + asn1.js "^4.0.0" + browserify-aes "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + safe-buffer "^5.1.1" + +parse-code-context@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/parse-code-context/-/parse-code-context-1.0.0.tgz#718c295c593d0d19a37f898473268cc75e98de1e" + +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + +parse-headers@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.3.tgz#5e8e7512383d140ba02f0c7aa9f49b4399c92515" + +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + +path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + +path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + +pathval@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" + +pbkdf2@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.0.tgz#8839d778223e922164803a411dc62fddb57d3b02" + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + +picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" + +pify@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + +prepend-http@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + +prepend-http@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" + +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + +prettier-plugin-solidity@^1.0.0-alpha.52: + version "1.0.0-alpha.53" + resolved "https://registry.yarnpkg.com/prettier-plugin-solidity/-/prettier-plugin-solidity-1.0.0-alpha.53.tgz#42ef3435fb179bc41fe83f08d7b9327c88bf4a01" + dependencies: + "@solidity-parser/parser" "^0.6.1" + dir-to-object "^2.0.0" + emoji-regex "^9.0.0" + escape-string-regexp "^4.0.0" + extract-comments "^1.1.0" + prettier "^2.0.5" + semver "^7.3.2" + string-width "^4.2.0" + +prettier@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.0.5.tgz#d6d56282455243f2f92cc1716692c08aa31522d4" + +private@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + +process@~0.5.1: + version "0.5.2" + resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" + +proxy-addr@~2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" + dependencies: + forwarded "~0.1.2" + ipaddr.js "1.9.1" + +psl@^1.1.28: + version "1.8.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" + +public-encrypt@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + safe-buffer "^5.1.2" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +punycode@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" + +punycode@^2.1.0, punycode@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + +qs@6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" + +qs@~6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + +query-string@^5.0.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" + dependencies: + decode-uri-component "^0.2.0" + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + +randomatic@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" + dependencies: + is-number "^4.0.0" + kind-of "^6.0.0" + math-random "^1.0.1" + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +randomhex@0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/randomhex/-/randomhex-0.1.5.tgz#baceef982329091400f2a2912c6cd02f1094f585" + +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + +raw-body@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" + dependencies: + bytes "3.1.0" + http-errors "1.7.2" + iconv-lite "0.4.24" + unpipe "1.0.0" + +readable-stream@^2.0.2, readable-stream@^2.3.0, readable-stream@^2.3.5: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + dependencies: + graceful-fs "^4.1.11" + micromatch "^3.1.10" + readable-stream "^2.0.2" + +readdirp@~3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.2.0.tgz#c30c33352b12c96dfb4b895421a49fd5a9593839" + dependencies: + picomatch "^2.0.4" + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + dependencies: + resolve "^1.1.6" + +recursive-readdir@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.2.tgz#9946fb3274e1628de6e36b2f6714953b4845094f" + dependencies: + minimatch "3.0.4" + +regenerator-runtime@^0.10.5: + version "0.10.5" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" + +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + +regex-cache@^0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" + dependencies: + is-equal-shallow "^0.1.3" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + +repeat-element@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" + +repeat-string@^1.5.2, repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + dependencies: + is-finite "^1.0.0" + +request@^2.79.0: + version "2.88.2" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.5.0" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + +resolve@1.1.x: + version "1.1.7" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" + +resolve@^1.1.6, resolve@^1.12.0: + version "1.17.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" + dependencies: + path-parse "^1.0.6" + +responselike@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" + dependencies: + lowercase-keys "^1.0.0" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +rlp@^2.0.0, rlp@^2.2.3, rlp@^2.2.4: + version "2.2.5" + resolved "https://registry.yarnpkg.com/rlp/-/rlp-2.2.5.tgz#b0577b763e909f21a9dea31b4b235b2393f15ef1" + dependencies: + bn.js "^4.11.1" + +run-parallel@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + +sc-istanbul@^0.4.5: + version "0.4.5" + resolved "https://registry.yarnpkg.com/sc-istanbul/-/sc-istanbul-0.4.5.tgz#1896066484d55336cf2cdbcc7884dc79da50dc76" + dependencies: + abbrev "1.0.x" + async "1.x" + escodegen "1.8.x" + esprima "2.7.x" + glob "^5.0.15" + handlebars "^4.0.1" + js-yaml "3.x" + mkdirp "0.5.x" + nopt "3.x" + once "1.x" + resolve "1.1.x" + supports-color "^3.1.0" + which "^1.1.1" + wordwrap "^1.0.0" + +scrypt-js@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-2.0.3.tgz#bb0040be03043da9a012a2cea9fc9f852cfc87d4" + +scrypt-js@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-2.0.4.tgz#32f8c5149f0797672e551c07e230f834b6af5f16" + +"scrypt-shim@github:web3-js/scrypt-shim": + version "0.1.0" + resolved "https://codeload.github.com/web3-js/scrypt-shim/tar.gz/aafdadda13e660e25e1c525d1f5b2443f5eb1ebb" + dependencies: + scryptsy "^2.1.0" + semver "^6.3.0" + +scryptsy@2.1.0, scryptsy@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/scryptsy/-/scryptsy-2.1.0.tgz#8d1e8d0c025b58fdd25b6fa9a0dc905ee8faa790" + +secp256k1@^3.0.1: + version "3.8.0" + resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-3.8.0.tgz#28f59f4b01dbee9575f56a47034b7d2e3b3b352d" + dependencies: + bindings "^1.5.0" + bip66 "^1.1.5" + bn.js "^4.11.8" + create-hash "^1.2.0" + drbg.js "^1.0.1" + elliptic "^6.5.2" + nan "^2.14.0" + safe-buffer "^5.1.2" + +secp256k1@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-4.0.1.tgz#b9570ca26ace9e74c3171512bba253da9c0b6d60" + dependencies: + elliptic "^6.5.2" + node-addon-api "^2.0.0" + node-gyp-build "^4.2.0" + +seek-bzip@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-1.0.5.tgz#cfe917cb3d274bcffac792758af53173eb1fabdc" + dependencies: + commander "~2.8.1" + +semver@6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.2.0.tgz#4d813d9590aaf8a9192693d6c85b9344de5901db" + +semver@^5.5.0, semver@^5.7.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + +semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + +semver@^7.3.2: + version "7.3.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" + +send@0.17.1: + version "0.17.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.7.2" + mime "1.6.0" + ms "2.1.1" + on-finished "~2.3.0" + range-parser "~1.2.1" + statuses "~1.5.0" + +serve-static@1.14.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.17.1" + +servify@^0.1.12: + version "0.1.12" + resolved "https://registry.yarnpkg.com/servify/-/servify-0.1.12.tgz#142ab7bee1f1d033b66d0707086085b17c06db95" + dependencies: + body-parser "^1.16.0" + cors "^2.8.1" + express "^4.14.0" + request "^2.79.0" + xhr "^2.3.3" + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setimmediate@1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.4.tgz#20e81de622d4a02588ce0c8da8973cbcf1d3138f" + +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + +setprototypeof@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + +shelljs@^0.8.3: + version "0.8.4" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.4.tgz#de7684feeb767f8716b326078a8a00875890e3c2" + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + +signal-exit@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" + +simple-concat@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.0.tgz#7344cbb8b6e26fb27d66b2fc86f9f6d5997521c6" + +simple-get@^2.7.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.8.1.tgz#0e22e91d4575d87620620bc91308d57a77f44b5d" + dependencies: + decompress-response "^3.3.0" + once "^1.3.1" + simple-concat "^1.0.0" + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +solidity-coverage@^0.7.7: + version "0.7.7" + resolved "https://registry.yarnpkg.com/solidity-coverage/-/solidity-coverage-0.7.7.tgz#e6d98436d529707c64c1d6d3355590031a724777" + dependencies: + "@solidity-parser/parser" "^0.6.0" + "@truffle/provider" "^0.1.17" + chalk "^2.4.2" + death "^1.1.0" + detect-port "^1.3.0" + fs-extra "^8.1.0" + ganache-cli "6.9.0" + ghost-testrpc "^0.0.2" + global-modules "^2.0.0" + globby "^10.0.1" + jsonschema "^1.2.4" + lodash "^4.17.15" + node-emoji "^1.10.0" + pify "^4.0.1" + recursive-readdir "^2.2.2" + sc-istanbul "^0.4.5" + shelljs "^0.8.3" + web3 "1.2.6" + +source-map-resolve@^0.5.0: + version "0.5.3" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" + dependencies: + atob "^2.1.2" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@0.5.12: + version "0.5.12" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599" + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-support@^0.4.15: + version "0.4.18" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" + dependencies: + source-map "^0.5.6" + +source-map-support@^0.5.17: + version "0.5.19" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + +source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + +source-map@^0.6.0, source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + +source-map@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d" + dependencies: + amdefine ">=0.0.4" + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + dependencies: + extend-shallow "^3.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + +sshpk@^1.7.0: + version "1.16.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +"statuses@>= 1.5.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + +strict-uri-encode@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + +"string-width@^1.0.2 || 2": + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string-width@^3.0.0, string-width@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string-width@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.0" + +string.prototype.trimend@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913" + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + +string.prototype.trimleft@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz#4408aa2e5d6ddd0c9a80739b087fbc067c03b3cc" + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + string.prototype.trimstart "^1.0.0" + +string.prototype.trimright@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz#c76f1cef30f21bbad8afeb8db1511496cfb0f2a3" + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + string.prototype.trimend "^1.0.0" + +string.prototype.trimstart@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54" + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + dependencies: + ansi-regex "^3.0.0" + +strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + dependencies: + ansi-regex "^4.1.0" + +strip-ansi@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" + dependencies: + ansi-regex "^5.0.0" + +strip-dirs@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/strip-dirs/-/strip-dirs-2.1.0.tgz#4987736264fc344cf20f6c34aca9d13d1d4ed6c5" + dependencies: + is-natural-number "^4.0.1" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + +strip-hex-prefix@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz#0c5f155fef1151373377de9dbb588da05500e36f" + dependencies: + is-hex-prefixed "1.0.0" + +strip-json-comments@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + +supports-color@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a" + dependencies: + has-flag "^3.0.0" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +supports-color@^3.1.0: + version "3.2.3" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" + dependencies: + has-flag "^1.0.0" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + dependencies: + has-flag "^3.0.0" + +swarm-js@0.1.39: + version "0.1.39" + resolved "https://registry.yarnpkg.com/swarm-js/-/swarm-js-0.1.39.tgz#79becb07f291d4b2a178c50fee7aa6e10342c0e8" + dependencies: + bluebird "^3.5.0" + buffer "^5.0.5" + decompress "^4.0.0" + eth-lib "^0.1.26" + fs-extra "^4.0.2" + got "^7.1.0" + mime-types "^2.1.16" + mkdirp-promise "^5.0.1" + mock-fs "^4.1.0" + setimmediate "^1.0.5" + tar "^4.0.2" + xhr-request-promise "^0.1.2" + +swarm-js@^0.1.40: + version "0.1.40" + resolved "https://registry.yarnpkg.com/swarm-js/-/swarm-js-0.1.40.tgz#b1bc7b6dcc76061f6c772203e004c11997e06b99" + dependencies: + bluebird "^3.5.0" + buffer "^5.0.5" + eth-lib "^0.1.26" + fs-extra "^4.0.2" + got "^7.1.0" + mime-types "^2.1.16" + mkdirp-promise "^5.0.1" + mock-fs "^4.1.0" + setimmediate "^1.0.5" + tar "^4.0.2" + xhr-request "^1.0.1" + +tar-stream@^1.5.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" + dependencies: + bl "^1.0.0" + buffer-alloc "^1.2.0" + end-of-stream "^1.0.0" + fs-constants "^1.0.0" + readable-stream "^2.3.0" + to-buffer "^1.1.1" + xtend "^4.0.0" + +tar@^4.0.2: + version "4.4.13" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" + dependencies: + chownr "^1.1.1" + fs-minipass "^1.2.5" + minipass "^2.8.6" + minizlib "^1.2.1" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.3" + +through@^2.3.8: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + +timed-out@^4.0.0, timed-out@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" + +to-buffer@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" + +to-fast-properties@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + dependencies: + kind-of "^3.0.2" + +to-readable-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + dependencies: + is-number "^7.0.0" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +toidentifier@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" + +tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + +trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + +truffle-hdwallet-provider@^1.0.17: + version "1.0.17" + resolved "https://registry.yarnpkg.com/truffle-hdwallet-provider/-/truffle-hdwallet-provider-1.0.17.tgz#fe8edd0d6974eeb31af9959e41525fb19abd74ca" + dependencies: + any-promise "^1.3.0" + bindings "^1.3.1" + web3 "1.2.1" + websocket "^1.0.28" + +ts-node@^8.10.2: + version "8.10.2" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.10.2.tgz#eee03764633b1234ddd37f8db9ec10b75ec7fb8d" + dependencies: + arg "^4.1.0" + diff "^4.0.1" + make-error "^1.1.1" + source-map-support "^0.5.17" + yn "3.1.1" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + dependencies: + prelude-ls "~1.1.2" + +type-detect@^4.0.0, type-detect@^4.0.5: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + +type-is@~1.6.17, type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +type@^1.0.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" + +type@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/type/-/type-2.0.0.tgz#5f16ff6ef2eb44f260494dae271033b29c09a9c3" + +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + dependencies: + is-typedarray "^1.0.0" + +typescript@^3.9.5: + version "3.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.5.tgz#586f0dba300cde8be52dd1ac4f7e1009c1b13f36" + +uglify-js@^3.1.4: + version "3.9.4" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.9.4.tgz#867402377e043c1fc7b102253a22b64e5862401b" + dependencies: + commander "~2.20.3" + +ultron@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" + +unbzip2-stream@^1.0.9: + version "1.4.3" + resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7" + dependencies: + buffer "^5.2.1" + through "^2.3.8" + +underscore@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" + +union-value@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^2.0.1" + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +uri-js@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + dependencies: + punycode "^2.1.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + +url-parse-lax@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" + dependencies: + prepend-http "^1.0.1" + +url-parse-lax@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" + dependencies: + prepend-http "^2.0.0" + +url-set-query@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/url-set-query/-/url-set-query-1.0.0.tgz#016e8cfd7c20ee05cafe7795e892bd0702faa339" + +url-to-options@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + +user-home@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" + +utf8@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1" + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +util@^0.12.0: + version "0.12.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.12.3.tgz#971bb0292d2cc0c892dab7c6a5d37c2bec707888" + dependencies: + inherits "^2.0.3" + is-arguments "^1.0.4" + is-generator-function "^1.0.7" + is-typed-array "^1.1.3" + safe-buffer "^5.1.2" + which-typed-array "^1.1.2" + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + +uuid@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.1.tgz#c2a30dedb3e535d72ccf82e343941a50ba8533ac" + +uuid@3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" + +uuid@^3.3.2: + version "3.4.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + +v8flags@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.1.1.tgz#aab1a1fa30d45f88dd321148875ac02c0b55e5b4" + dependencies: + user-home "^1.1.1" + +varint@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/varint/-/varint-5.0.0.tgz#d826b89f7490732fabc0c0ed693ed475dcb29ebf" + +vary@^1, vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +web3-bzz@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.2.1.tgz#c3bd1e8f0c02a13cd6d4e3c3e9e1713f144f6f0d" + dependencies: + got "9.6.0" + swarm-js "0.1.39" + underscore "1.9.1" + +web3-bzz@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.2.2.tgz#a3b9f613c49fd3e120e0997088a73557d5adb724" + dependencies: + "@types/node" "^10.12.18" + got "9.6.0" + swarm-js "0.1.39" + underscore "1.9.1" + +web3-bzz@1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.2.6.tgz#0b88c0b96029eaf01b10cb47c4d5f79db4668883" + dependencies: + "@types/node" "^10.12.18" + got "9.6.0" + swarm-js "0.1.39" + underscore "1.9.1" + +web3-bzz@1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.2.8.tgz#7ff2c2de362f82ae3825e48c70ec63b3aca2b8ef" + dependencies: + "@types/node" "^10.12.18" + got "9.6.0" + swarm-js "^0.1.40" + underscore "1.9.1" + +web3-core-helpers@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.2.1.tgz#f5f32d71c60a4a3bd14786118e633ce7ca6d5d0d" + dependencies: + underscore "1.9.1" + web3-eth-iban "1.2.1" + web3-utils "1.2.1" + +web3-core-helpers@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.2.2.tgz#484974f4bd4a487217b85b0d7cfe841af0907619" + dependencies: + underscore "1.9.1" + web3-eth-iban "1.2.2" + web3-utils "1.2.2" + +web3-core-helpers@1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.2.6.tgz#7aacd25bf8015adcdfc0f3243d0dcfdff0373f7d" + dependencies: + underscore "1.9.1" + web3-eth-iban "1.2.6" + web3-utils "1.2.6" + +web3-core-helpers@1.2.8, web3-core-helpers@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.2.8.tgz#86776d8f658b63bb630c84a314686661e599aa68" + dependencies: + underscore "1.9.1" + web3-eth-iban "1.2.8" + web3-utils "1.2.8" + +web3-core-method@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.2.1.tgz#9df1bafa2cd8be9d9937e01c6a47fc768d15d90a" + dependencies: + underscore "1.9.1" + web3-core-helpers "1.2.1" + web3-core-promievent "1.2.1" + web3-core-subscriptions "1.2.1" + web3-utils "1.2.1" + +web3-core-method@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.2.2.tgz#d4fe2bb1945b7152e5f08e4ea568b171132a1e56" + dependencies: + underscore "1.9.1" + web3-core-helpers "1.2.2" + web3-core-promievent "1.2.2" + web3-core-subscriptions "1.2.2" + web3-utils "1.2.2" + +web3-core-method@1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.2.6.tgz#f5a3e4d304abaf382923c8ab88ec8eeef45c1b3b" + dependencies: + underscore "1.9.1" + web3-core-helpers "1.2.6" + web3-core-promievent "1.2.6" + web3-core-subscriptions "1.2.6" + web3-utils "1.2.6" + +web3-core-method@1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.2.8.tgz#f28a79935432aebfa019e4a50f9b6ae6c9ef4297" + dependencies: + underscore "1.9.1" + web3-core-helpers "1.2.8" + web3-core-promievent "1.2.8" + web3-core-subscriptions "1.2.8" + web3-utils "1.2.8" + +web3-core-promievent@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.2.1.tgz#003e8a3eb82fb27b6164a6d5b9cad04acf733838" + dependencies: + any-promise "1.3.0" + eventemitter3 "3.1.2" + +web3-core-promievent@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.2.2.tgz#3b60e3f2a0c96db8a891c927899d29d39e66ab1c" + dependencies: + any-promise "1.3.0" + eventemitter3 "3.1.2" + +web3-core-promievent@1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.2.6.tgz#b1550a3a4163e48b8b704c1fe4b0084fc2dad8f5" + dependencies: + any-promise "1.3.0" + eventemitter3 "3.1.2" + +web3-core-promievent@1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.2.8.tgz#a93ca2a19cae8b60883412619e04e69e11804eb5" + dependencies: + eventemitter3 "3.1.2" + +web3-core-requestmanager@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.2.1.tgz#fa2e2206c3d738db38db7c8fe9c107006f5c6e3d" + dependencies: + underscore "1.9.1" + web3-core-helpers "1.2.1" + web3-providers-http "1.2.1" + web3-providers-ipc "1.2.1" + web3-providers-ws "1.2.1" + +web3-core-requestmanager@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.2.2.tgz#667ba9ac724c9c76fa8965ae8a3c61f66e68d8d6" + dependencies: + underscore "1.9.1" + web3-core-helpers "1.2.2" + web3-providers-http "1.2.2" + web3-providers-ipc "1.2.2" + web3-providers-ws "1.2.2" + +web3-core-requestmanager@1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.2.6.tgz#5808c0edc0d6e2991a87b65508b3a1ab065b68ec" + dependencies: + underscore "1.9.1" + web3-core-helpers "1.2.6" + web3-providers-http "1.2.6" + web3-providers-ipc "1.2.6" + web3-providers-ws "1.2.6" + +web3-core-requestmanager@1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.2.8.tgz#da7259e72a433858d04c59b999c5116bfb797c09" + dependencies: + underscore "1.9.1" + web3-core-helpers "1.2.8" + web3-providers-http "1.2.8" + web3-providers-ipc "1.2.8" + web3-providers-ws "1.2.8" + +web3-core-subscriptions@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.2.1.tgz#8c2368a839d4eec1c01a4b5650bbeb82d0e4a099" + dependencies: + eventemitter3 "3.1.2" + underscore "1.9.1" + web3-core-helpers "1.2.1" + +web3-core-subscriptions@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.2.2.tgz#bf4ba23a653a003bdc3551649958cc0b080b068e" + dependencies: + eventemitter3 "3.1.2" + underscore "1.9.1" + web3-core-helpers "1.2.2" + +web3-core-subscriptions@1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.2.6.tgz#9d44189e2321f8f1abc31f6c09103b5283461b57" + dependencies: + eventemitter3 "3.1.2" + underscore "1.9.1" + web3-core-helpers "1.2.6" + +web3-core-subscriptions@1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.2.8.tgz#50945498fb0bd655f842cbcc13873d96956aa93e" + dependencies: + eventemitter3 "3.1.2" + underscore "1.9.1" + web3-core-helpers "1.2.8" + +web3-core@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.2.1.tgz#7278b58fb6495065e73a77efbbce781a7fddf1a9" + dependencies: + web3-core-helpers "1.2.1" + web3-core-method "1.2.1" + web3-core-requestmanager "1.2.1" + web3-utils "1.2.1" + +web3-core@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.2.2.tgz#334b99c8222ef9cfd0339e27352f0b58ea789a2f" + dependencies: + "@types/bn.js" "^4.11.4" + "@types/node" "^12.6.1" + web3-core-helpers "1.2.2" + web3-core-method "1.2.2" + web3-core-requestmanager "1.2.2" + web3-utils "1.2.2" + +web3-core@1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.2.6.tgz#bb42a1d7ae49a7258460f0d95ddb00906f59ef92" + dependencies: + "@types/bn.js" "^4.11.4" + "@types/node" "^12.6.1" + web3-core-helpers "1.2.6" + web3-core-method "1.2.6" + web3-core-requestmanager "1.2.6" + web3-utils "1.2.6" + +web3-core@1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.2.8.tgz#2a488bb11519b71e7738265329bddc00fc200dd3" + dependencies: + "@types/bn.js" "^4.11.4" + "@types/node" "^12.6.1" + bignumber.js "^9.0.0" + web3-core-helpers "1.2.8" + web3-core-method "1.2.8" + web3-core-requestmanager "1.2.8" + web3-utils "1.2.8" + +web3-eth-abi@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.2.1.tgz#9b915b1c9ebf82f70cca631147035d5419064689" + dependencies: + ethers "4.0.0-beta.3" + underscore "1.9.1" + web3-utils "1.2.1" + +web3-eth-abi@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.2.2.tgz#d5616d88a90020f894763423a9769f2da11fe37a" + dependencies: + ethers "4.0.0-beta.3" + underscore "1.9.1" + web3-utils "1.2.2" + +web3-eth-abi@1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.2.6.tgz#b495383cc5c0d8e2857b26e7fe25606685983b25" + dependencies: + ethers "4.0.0-beta.3" + underscore "1.9.1" + web3-utils "1.2.6" + +web3-eth-abi@1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.2.8.tgz#7537138f3e5cd1ccf98233fa07f388aa8dc1fff1" + dependencies: + "@ethersproject/abi" "5.0.0-beta.153" + underscore "1.9.1" + web3-utils "1.2.8" + +web3-eth-accounts@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.2.1.tgz#2741a8ef337a7219d57959ac8bd118b9d68d63cf" + dependencies: + any-promise "1.3.0" + crypto-browserify "3.12.0" + eth-lib "0.2.7" + scryptsy "2.1.0" + semver "6.2.0" + underscore "1.9.1" + uuid "3.3.2" + web3-core "1.2.1" + web3-core-helpers "1.2.1" + web3-core-method "1.2.1" + web3-utils "1.2.1" + +web3-eth-accounts@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.2.2.tgz#c187e14bff6baa698ac352220290222dbfd332e5" + dependencies: + any-promise "1.3.0" + crypto-browserify "3.12.0" + eth-lib "0.2.7" + ethereumjs-common "^1.3.2" + ethereumjs-tx "^2.1.1" + scrypt-shim "github:web3-js/scrypt-shim" + underscore "1.9.1" + uuid "3.3.2" + web3-core "1.2.2" + web3-core-helpers "1.2.2" + web3-core-method "1.2.2" + web3-utils "1.2.2" + +web3-eth-accounts@1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.2.6.tgz#a1ba4bf75fa8102a3ec6cddd0eccd72462262720" + dependencies: + "@web3-js/scrypt-shim" "^0.1.0" + any-promise "1.3.0" + crypto-browserify "3.12.0" + eth-lib "^0.2.8" + ethereumjs-common "^1.3.2" + ethereumjs-tx "^2.1.1" + underscore "1.9.1" + uuid "3.3.2" + web3-core "1.2.6" + web3-core-helpers "1.2.6" + web3-core-method "1.2.6" + web3-utils "1.2.6" + +web3-eth-accounts@1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.2.8.tgz#e63afc6d4902f2beb0cf60e6b755c86fa5b5ccd7" + dependencies: + "@web3-js/scrypt-shim" "^0.1.0" + crypto-browserify "3.12.0" + eth-lib "^0.2.8" + ethereumjs-common "^1.3.2" + ethereumjs-tx "^2.1.1" + underscore "1.9.1" + uuid "3.3.2" + web3-core "1.2.8" + web3-core-helpers "1.2.8" + web3-core-method "1.2.8" + web3-utils "1.2.8" + +web3-eth-contract@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.2.1.tgz#3542424f3d341386fd9ff65e78060b85ac0ea8c4" + dependencies: + underscore "1.9.1" + web3-core "1.2.1" + web3-core-helpers "1.2.1" + web3-core-method "1.2.1" + web3-core-promievent "1.2.1" + web3-core-subscriptions "1.2.1" + web3-eth-abi "1.2.1" + web3-utils "1.2.1" + +web3-eth-contract@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.2.2.tgz#84e92714918a29e1028ee7718f0712536e14e9a1" + dependencies: + "@types/bn.js" "^4.11.4" + underscore "1.9.1" + web3-core "1.2.2" + web3-core-helpers "1.2.2" + web3-core-method "1.2.2" + web3-core-promievent "1.2.2" + web3-core-subscriptions "1.2.2" + web3-eth-abi "1.2.2" + web3-utils "1.2.2" + +web3-eth-contract@1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.2.6.tgz#39111543960035ed94c597a239cf5aa1da796741" + dependencies: + "@types/bn.js" "^4.11.4" + underscore "1.9.1" + web3-core "1.2.6" + web3-core-helpers "1.2.6" + web3-core-method "1.2.6" + web3-core-promievent "1.2.6" + web3-core-subscriptions "1.2.6" + web3-eth-abi "1.2.6" + web3-utils "1.2.6" + +web3-eth-contract@1.2.8, web3-eth-contract@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.2.8.tgz#ff75920ac698a70781edcebbf75287a6d0f14499" + dependencies: + "@types/bn.js" "^4.11.4" + underscore "1.9.1" + web3-core "1.2.8" + web3-core-helpers "1.2.8" + web3-core-method "1.2.8" + web3-core-promievent "1.2.8" + web3-core-subscriptions "1.2.8" + web3-eth-abi "1.2.8" + web3-utils "1.2.8" + +web3-eth-ens@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.2.1.tgz#a0e52eee68c42a8b9865ceb04e5fb022c2d971d5" + dependencies: + eth-ens-namehash "2.0.8" + underscore "1.9.1" + web3-core "1.2.1" + web3-core-helpers "1.2.1" + web3-core-promievent "1.2.1" + web3-eth-abi "1.2.1" + web3-eth-contract "1.2.1" + web3-utils "1.2.1" + +web3-eth-ens@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.2.2.tgz#0a4abed1d4cbdacbf5e1ab06e502d806d1192bc6" + dependencies: + eth-ens-namehash "2.0.8" + underscore "1.9.1" + web3-core "1.2.2" + web3-core-helpers "1.2.2" + web3-core-promievent "1.2.2" + web3-eth-abi "1.2.2" + web3-eth-contract "1.2.2" + web3-utils "1.2.2" + +web3-eth-ens@1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.2.6.tgz#bf86a624c4c72bc59913c2345180d3ea947e110d" + dependencies: + eth-ens-namehash "2.0.8" + underscore "1.9.1" + web3-core "1.2.6" + web3-core-helpers "1.2.6" + web3-core-promievent "1.2.6" + web3-eth-abi "1.2.6" + web3-eth-contract "1.2.6" + web3-utils "1.2.6" + +web3-eth-ens@1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.2.8.tgz#247daddfdbf7533adb0f45cd2f75c75e52f7e678" + dependencies: + content-hash "^2.5.2" + eth-ens-namehash "2.0.8" + underscore "1.9.1" + web3-core "1.2.8" + web3-core-helpers "1.2.8" + web3-core-promievent "1.2.8" + web3-eth-abi "1.2.8" + web3-eth-contract "1.2.8" + web3-utils "1.2.8" + +web3-eth-iban@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.2.1.tgz#2c3801718946bea24e9296993a975c80b5acf880" + dependencies: + bn.js "4.11.8" + web3-utils "1.2.1" + +web3-eth-iban@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.2.2.tgz#76bec73bad214df7c4192388979a59fc98b96c5a" + dependencies: + bn.js "4.11.8" + web3-utils "1.2.2" + +web3-eth-iban@1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.2.6.tgz#0b22191fd1aa6e27f7ef0820df75820bfb4ed46b" + dependencies: + bn.js "4.11.8" + web3-utils "1.2.6" + +web3-eth-iban@1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.2.8.tgz#414e80a7fb2d1ea16490bc2c8fc29a996aec5612" + dependencies: + bn.js "4.11.8" + web3-utils "1.2.8" + +web3-eth-personal@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.2.1.tgz#244e9911b7b482dc17c02f23a061a627c6e47faf" + dependencies: + web3-core "1.2.1" + web3-core-helpers "1.2.1" + web3-core-method "1.2.1" + web3-net "1.2.1" + web3-utils "1.2.1" + +web3-eth-personal@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.2.2.tgz#eee1c86a8132fa16b5e34c6d421ca92e684f0be6" + dependencies: + "@types/node" "^12.6.1" + web3-core "1.2.2" + web3-core-helpers "1.2.2" + web3-core-method "1.2.2" + web3-net "1.2.2" + web3-utils "1.2.2" + +web3-eth-personal@1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.2.6.tgz#47a0a0657ec04dd77f95451a6869d4751d324b6b" + dependencies: + "@types/node" "^12.6.1" + web3-core "1.2.6" + web3-core-helpers "1.2.6" + web3-core-method "1.2.6" + web3-net "1.2.6" + web3-utils "1.2.6" + +web3-eth-personal@1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.2.8.tgz#8ebb27210b4c9c9555a30c5bb2ce8db12f84cd24" + dependencies: + "@types/node" "^12.6.1" + web3-core "1.2.8" + web3-core-helpers "1.2.8" + web3-core-method "1.2.8" + web3-net "1.2.8" + web3-utils "1.2.8" + +web3-eth@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.2.1.tgz#b9989e2557c73a9e8ffdc107c6dafbe72c79c1b0" + dependencies: + underscore "1.9.1" + web3-core "1.2.1" + web3-core-helpers "1.2.1" + web3-core-method "1.2.1" + web3-core-subscriptions "1.2.1" + web3-eth-abi "1.2.1" + web3-eth-accounts "1.2.1" + web3-eth-contract "1.2.1" + web3-eth-ens "1.2.1" + web3-eth-iban "1.2.1" + web3-eth-personal "1.2.1" + web3-net "1.2.1" + web3-utils "1.2.1" + +web3-eth@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.2.2.tgz#65a1564634a23b990efd1655bf94ad513904286c" + dependencies: + underscore "1.9.1" + web3-core "1.2.2" + web3-core-helpers "1.2.2" + web3-core-method "1.2.2" + web3-core-subscriptions "1.2.2" + web3-eth-abi "1.2.2" + web3-eth-accounts "1.2.2" + web3-eth-contract "1.2.2" + web3-eth-ens "1.2.2" + web3-eth-iban "1.2.2" + web3-eth-personal "1.2.2" + web3-net "1.2.2" + web3-utils "1.2.2" + +web3-eth@1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.2.6.tgz#15a8c65fdde0727872848cae506758d302d8d046" + dependencies: + underscore "1.9.1" + web3-core "1.2.6" + web3-core-helpers "1.2.6" + web3-core-method "1.2.6" + web3-core-subscriptions "1.2.6" + web3-eth-abi "1.2.6" + web3-eth-accounts "1.2.6" + web3-eth-contract "1.2.6" + web3-eth-ens "1.2.6" + web3-eth-iban "1.2.6" + web3-eth-personal "1.2.6" + web3-net "1.2.6" + web3-utils "1.2.6" + +web3-eth@1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.2.8.tgz#cf6a16fae4d7c12b90cfb6ef570cb1a2acc34c1b" + dependencies: + underscore "1.9.1" + web3-core "1.2.8" + web3-core-helpers "1.2.8" + web3-core-method "1.2.8" + web3-core-subscriptions "1.2.8" + web3-eth-abi "1.2.8" + web3-eth-accounts "1.2.8" + web3-eth-contract "1.2.8" + web3-eth-ens "1.2.8" + web3-eth-iban "1.2.8" + web3-eth-personal "1.2.8" + web3-net "1.2.8" + web3-utils "1.2.8" + +web3-net@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.2.1.tgz#edd249503315dd5ab4fa00220f6509d95bb7ab10" + dependencies: + web3-core "1.2.1" + web3-core-method "1.2.1" + web3-utils "1.2.1" + +web3-net@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.2.2.tgz#5c3226ca72df7c591422440ce6f1203fd42ddad9" + dependencies: + web3-core "1.2.2" + web3-core-method "1.2.2" + web3-utils "1.2.2" + +web3-net@1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.2.6.tgz#035ca0fbe55282fda848ca17ebb4c8966147e5ea" + dependencies: + web3-core "1.2.6" + web3-core-method "1.2.6" + web3-utils "1.2.6" + +web3-net@1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.2.8.tgz#582fc2d4ba32c2e5c7761624e4be7c5434142d66" + dependencies: + web3-core "1.2.8" + web3-core-method "1.2.8" + web3-utils "1.2.8" + +web3-providers-http@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.2.1.tgz#c93ea003a42e7b894556f7e19dd3540f947f5013" + dependencies: + web3-core-helpers "1.2.1" + xhr2-cookies "1.1.0" + +web3-providers-http@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.2.2.tgz#155e55c1d69f4c5cc0b411ede40dea3d06720956" + dependencies: + web3-core-helpers "1.2.2" + xhr2-cookies "1.1.0" + +web3-providers-http@1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.2.6.tgz#3c7b1252751fb37e53b873fce9dbb6340f5e31d9" + dependencies: + web3-core-helpers "1.2.6" + xhr2-cookies "1.1.0" + +web3-providers-http@1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.2.8.tgz#cd7fc4d49df6980b5dd0fb1b5a808bc4b6a0069d" + dependencies: + web3-core-helpers "1.2.8" + xhr2-cookies "1.1.0" + +web3-providers-ipc@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.2.1.tgz#017bfc687a8fc5398df2241eb98f135e3edd672c" + dependencies: + oboe "2.1.4" + underscore "1.9.1" + web3-core-helpers "1.2.1" + +web3-providers-ipc@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.2.2.tgz#c6d165a12bc68674b4cdd543ea18aec79cafc2e8" + dependencies: + oboe "2.1.4" + underscore "1.9.1" + web3-core-helpers "1.2.2" + +web3-providers-ipc@1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.2.6.tgz#adabab5ac66b3ff8a26c7dc97af3f1a6a7609701" + dependencies: + oboe "2.1.4" + underscore "1.9.1" + web3-core-helpers "1.2.6" + +web3-providers-ipc@1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.2.8.tgz#47be918ddd077999aa14703169b76c807f45d894" + dependencies: + oboe "2.1.4" + underscore "1.9.1" + web3-core-helpers "1.2.8" + +web3-providers-ws@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.2.1.tgz#2d941eaf3d5a8caa3214eff8dc16d96252b842cb" + dependencies: + underscore "1.9.1" + web3-core-helpers "1.2.1" + websocket "github:web3-js/WebSocket-Node#polyfill/globalThis" + +web3-providers-ws@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.2.2.tgz#d2c05c68598cea5ad3fa6ef076c3bcb3ca300d29" + dependencies: + underscore "1.9.1" + web3-core-helpers "1.2.2" + websocket "github:web3-js/WebSocket-Node#polyfill/globalThis" + +web3-providers-ws@1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.2.6.tgz#3cecc49f7c99f07a75076d3c54247050bc4f7e11" + dependencies: + "@web3-js/websocket" "^1.0.29" + underscore "1.9.1" + web3-core-helpers "1.2.6" + +web3-providers-ws@1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.2.8.tgz#9e6454edc82d753d398c8d1e044632c234434a46" + dependencies: + "@web3-js/websocket" "^1.0.29" + eventemitter3 "^4.0.0" + underscore "1.9.1" + web3-core-helpers "1.2.8" + +web3-shh@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.2.1.tgz#4460e3c1e07faf73ddec24ccd00da46f89152b0c" + dependencies: + web3-core "1.2.1" + web3-core-method "1.2.1" + web3-core-subscriptions "1.2.1" + web3-net "1.2.1" + +web3-shh@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.2.2.tgz#44ed998f2a6ba0ec5cb9d455184a0f647826a49c" + dependencies: + web3-core "1.2.2" + web3-core-method "1.2.2" + web3-core-subscriptions "1.2.2" + web3-net "1.2.2" + +web3-shh@1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.2.6.tgz#2492616da4cac32d4c7534b890f43bac63190c14" + dependencies: + web3-core "1.2.6" + web3-core-method "1.2.6" + web3-core-subscriptions "1.2.6" + web3-net "1.2.6" + +web3-shh@1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.2.8.tgz#5162d9d13bc6838d390df1cd39e5f87235c1c2ae" + dependencies: + web3-core "1.2.8" + web3-core-method "1.2.8" + web3-core-subscriptions "1.2.8" + web3-net "1.2.8" + +web3-utils@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.2.1.tgz#21466e38291551de0ab34558de21512ac4274534" + dependencies: + bn.js "4.11.8" + eth-lib "0.2.7" + ethjs-unit "0.1.6" + number-to-bn "1.7.0" + randomhex "0.1.5" + underscore "1.9.1" + utf8 "3.0.0" + +web3-utils@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.2.2.tgz#b53a08c40d2c3f31d3c4a28e7d749405df99c8c0" + dependencies: + bn.js "4.11.8" + eth-lib "0.2.7" + ethereum-bloom-filters "^1.0.6" + ethjs-unit "0.1.6" + number-to-bn "1.7.0" + randombytes "^2.1.0" + underscore "1.9.1" + utf8 "3.0.0" + +web3-utils@1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.2.6.tgz#b9a25432da00976457fcc1094c4af8ac6d486db9" + dependencies: + bn.js "4.11.8" + eth-lib "0.2.7" + ethereum-bloom-filters "^1.0.6" + ethjs-unit "0.1.6" + number-to-bn "1.7.0" + randombytes "^2.1.0" + underscore "1.9.1" + utf8 "3.0.0" + +web3-utils@1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.2.8.tgz#5321d91715cd4c0869005705a33c4c042a532b18" + dependencies: + bn.js "4.11.8" + eth-lib "0.2.7" + ethereum-bloom-filters "^1.0.6" + ethjs-unit "0.1.6" + number-to-bn "1.7.0" + randombytes "^2.1.0" + underscore "1.9.1" + utf8 "3.0.0" + +web3@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3/-/web3-1.2.1.tgz#5d8158bcca47838ab8c2b784a2dee4c3ceb4179b" + dependencies: + web3-bzz "1.2.1" + web3-core "1.2.1" + web3-eth "1.2.1" + web3-eth-personal "1.2.1" + web3-net "1.2.1" + web3-shh "1.2.1" + web3-utils "1.2.1" + +web3@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/web3/-/web3-1.2.2.tgz#b1b8b69aafdf94cbaeadbb68a8aa1df2ef266aec" + dependencies: + "@types/node" "^12.6.1" + web3-bzz "1.2.2" + web3-core "1.2.2" + web3-eth "1.2.2" + web3-eth-personal "1.2.2" + web3-net "1.2.2" + web3-shh "1.2.2" + web3-utils "1.2.2" + +web3@1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/web3/-/web3-1.2.6.tgz#c497dcb14cdd8d6d9fb6b445b3b68ff83f8ccf68" + dependencies: + "@types/node" "^12.6.1" + web3-bzz "1.2.6" + web3-core "1.2.6" + web3-eth "1.2.6" + web3-eth-personal "1.2.6" + web3-net "1.2.6" + web3-shh "1.2.6" + web3-utils "1.2.6" + +web3@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/web3/-/web3-1.2.8.tgz#20b24baa769e0224a708ef5bf196a5b83d19540b" + dependencies: + web3-bzz "1.2.8" + web3-core "1.2.8" + web3-eth "1.2.8" + web3-eth-personal "1.2.8" + web3-net "1.2.8" + web3-shh "1.2.8" + web3-utils "1.2.8" + +websocket@^1.0.28: + version "1.0.31" + resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.31.tgz#e5d0f16c3340ed87670e489ecae6144c79358730" + dependencies: + debug "^2.2.0" + es5-ext "^0.10.50" + nan "^2.14.0" + typedarray-to-buffer "^3.1.5" + yaeti "^0.0.6" + +"websocket@github:web3-js/WebSocket-Node#polyfill/globalThis": + version "1.0.29" + resolved "https://codeload.github.com/web3-js/WebSocket-Node/tar.gz/ef5ea2f41daf4a2113b80c9223df884b4d56c400" + dependencies: + debug "^2.2.0" + es5-ext "^0.10.50" + nan "^2.14.0" + typedarray-to-buffer "^3.1.5" + yaeti "^0.0.6" + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + +which-typed-array@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.2.tgz#e5f98e56bda93e3dac196b01d47c1156679c00b2" + dependencies: + available-typed-arrays "^1.0.2" + es-abstract "^1.17.5" + foreach "^2.0.5" + function-bind "^1.1.1" + has-symbols "^1.0.1" + is-typed-array "^1.1.3" + +which@1.3.1, which@^1.1.1, which@^1.2.9, which@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + dependencies: + isexe "^2.0.0" + +wide-align@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + dependencies: + string-width "^1.0.2 || 2" + +word-wrap@~1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + +wordwrap@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + +wrap-ansi@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" + dependencies: + ansi-styles "^3.2.0" + string-width "^3.0.0" + strip-ansi "^5.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +ws@^3.0.0: + version "3.3.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" + dependencies: + async-limiter "~1.0.0" + safe-buffer "~5.1.0" + ultron "~1.1.0" + +xhr-request-promise@^0.1.2: + version "0.1.3" + resolved "https://registry.yarnpkg.com/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz#2d5f4b16d8c6c893be97f1a62b0ed4cf3ca5f96c" + dependencies: + xhr-request "^1.1.0" + +xhr-request@^1.0.1, xhr-request@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/xhr-request/-/xhr-request-1.1.0.tgz#f4a7c1868b9f198723444d82dcae317643f2e2ed" + dependencies: + buffer-to-arraybuffer "^0.0.5" + object-assign "^4.1.1" + query-string "^5.0.1" + simple-get "^2.7.0" + timed-out "^4.0.1" + url-set-query "^1.0.0" + xhr "^2.0.4" + +xhr2-cookies@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz#7d77449d0999197f155cb73b23df72505ed89d48" + dependencies: + cookiejar "^2.1.1" + +xhr@^2.0.4, xhr@^2.3.3: + version "2.5.0" + resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.5.0.tgz#bed8d1676d5ca36108667692b74b316c496e49dd" + dependencies: + global "~4.3.0" + is-function "^1.0.1" + parse-headers "^2.0.0" + xtend "^4.0.0" + +xmlhttprequest@1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc" + +xtend@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + +y18n@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + +yaeti@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577" + +yallist@^3.0.0, yallist@^3.0.3: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + +yargs-parser@13.1.2, yargs-parser@^13.1.0, yargs-parser@^13.1.2: + version "13.1.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-unparser@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f" + dependencies: + flat "^4.1.0" + lodash "^4.17.15" + yargs "^13.3.0" + +yargs@13.2.4: + version "13.2.4" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.4.tgz#0b562b794016eb9651b98bd37acf364aa5d6dc83" + dependencies: + cliui "^5.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + os-locale "^3.1.0" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.1.0" + +yargs@13.3.2, yargs@^13.3.0: + version "13.3.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" + dependencies: + cliui "^5.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.1.2" + +yauzl@^2.4.2: + version "2.10.0" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" + dependencies: + buffer-crc32 "~0.2.3" + fd-slicer "~1.1.0" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" From bbe8d879fb75e496f4dae9cbbc1963d9f859a999 Mon Sep 17 00:00:00 2001 From: mingda Date: Fri, 26 Jun 2020 00:56:40 +0800 Subject: [PATCH 002/118] update trader test --- test/Trader.test.ts | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/test/Trader.test.ts b/test/Trader.test.ts index 0843233..68a1b70 100644 --- a/test/Trader.test.ts +++ b/test/Trader.test.ts @@ -60,18 +60,18 @@ describe("Trader", () => { assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "1101418160497943759027") }) - it("buy when R is ABOVE ONE", async () => { + it.only("buy when R is ABOVE ONE", async () => { await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110")).send(ctx.sendParam(trader)) - await ctx.DODO.methods.buyBaseToken(decimalStr("4"), decimalStr("500")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("130")).send(ctx.sendParam(trader)) // trader balances - assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("15")) - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "448068135932873382076") + assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("12")) + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "794367183433412077753") // maintainer balances - assert.equal(await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), decimalStr("0.005")) + assert.equal(await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), decimalStr("0.002")) assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), decimalStr("0")) // dodo balances - assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("4.995")) - assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "1551931864067126617924") + assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("7.998")) + assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "1205632816566587922247") }) it("sell when R is ABOVE ONE", async () => { @@ -141,22 +141,18 @@ describe("Trader", () => { assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "901283631576572307520") }) - it.only("sell when R is BELOW ONE", async () => { + it("sell when R is BELOW ONE", async () => { await ctx.DODO.methods.sellBaseToken(decimalStr("3"), decimalStr("90")).send(ctx.sendParam(trader)) - console.log(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("8")) - console.log(await ctx.QUOTE.methods.balanceOf(trader).call(), "1197235140964438116338") - console.log(await ctx.DODO.methods._QUOTE_BALANCE_().call()) - await ctx.DODO.methods.sellBaseToken(decimalStr("3"), decimalStr("90")).send(ctx.sendParam(trader)) // trader balances - console.log(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("8")) - console.log(await ctx.QUOTE.methods.balanceOf(trader).call(), "1197235140964438116338") + assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("4")) + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1535961012052716726546") // maintainer balances - console.log(await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), "0") - console.log(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), "197828626844973035") + assert.equal(await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), "0") + assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), "537573733252474148") // dodo balances - console.log(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("12")) - console.log(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "802567030408716910627") + assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("16")) + assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "463501414214030799306") }) it("buy when R is BELOW ONE", async () => { From a4307c2f7439ff6468eaea1bfe83f4f1b073c7be Mon Sep 17 00:00:00 2001 From: mingda Date: Fri, 26 Jun 2020 13:08:22 +0800 Subject: [PATCH 003/118] refine requires & comments --- contracts/impl/LiquidityProvider.sol | 69 ++++++++++++++-------------- contracts/impl/Trader.sol | 1 + 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/contracts/impl/LiquidityProvider.sol b/contracts/impl/LiquidityProvider.sol index 9f84e3b..ed110f6 100644 --- a/contracts/impl/LiquidityProvider.sol +++ b/contracts/impl/LiquidityProvider.sol @@ -17,7 +17,6 @@ import {Storage} from "./Storage.sol"; import {Settlement} from "./Settlement.sol"; import {Pricing} from "./Pricing.sol"; - /** * @title LiquidityProvider * @author DODO Breeder @@ -87,35 +86,37 @@ contract LiquidityProvider is Storage, Pricing, Settlement { depositQuoteAllowed { (, uint256 quoteTarget) = _getExpectedTarget(); - uint256 capital = amount; uint256 totalQuoteCapital = getTotalQuoteCapital(); + uint256 capital = amount; if (totalQuoteCapital == 0) { - capital = amount.add(quoteTarget); // give remaining quote token to lp as a gift - } - if (quoteTarget > 0 && totalQuoteCapital > 0) { + // give remaining quote token to lp as a gift + capital = amount.add(quoteTarget); + } else if (quoteTarget > 0) { capital = amount.mul(totalQuoteCapital).div(quoteTarget); } + // settlement _quoteTokenTransferIn(msg.sender, amount); - _mintQuoteTokenCapital(to, capital); + _mintQuoteCapital(to, capital); _TARGET_QUOTE_TOKEN_AMOUNT_ = _TARGET_QUOTE_TOKEN_AMOUNT_.add(amount); emit DepositQuoteToken(msg.sender, to, amount); } - function depositBaseTo(address to, uint256 amount) public preventReentrant depositBaseAllowed { + function depositBaseTo(address to, uint256 amount) public preventReentrant depositQuoteAllowed { (uint256 baseTarget, ) = _getExpectedTarget(); - uint256 capital = amount; uint256 totalBaseCapital = getTotalBaseCapital(); + uint256 capital = amount; if (totalBaseCapital == 0) { - capital = amount.add(baseTarget); // give remaining base token to lp as a gift - } - if (baseTarget > 0 && totalBaseCapital > 0) { + // give remaining base token to lp as a gift + capital = amount.add(baseTarget); + } else if (baseTarget > 0) { capital = amount.mul(totalBaseCapital).div(baseTarget); } + // settlement _baseTokenTransferIn(msg.sender, amount); - _mintBaseTokenCapital(to, capital); + _mintBaseCapital(to, capital); _TARGET_BASE_TOKEN_AMOUNT_ = _TARGET_BASE_TOKEN_AMOUNT_.add(amount); emit DepositBaseToken(msg.sender, to, amount); @@ -124,12 +125,12 @@ contract LiquidityProvider is Storage, Pricing, Settlement { // ============ Withdraw Functions ============ function withdrawQuoteTo(address to, uint256 amount) public preventReentrant returns (uint256) { - uint256 Q = _QUOTE_BALANCE_; - require(amount <= Q, "DODO_QUOTE_TOKEN_BALANCE_NOT_ENOUGH"); - // calculate capital (, uint256 quoteTarget) = _getExpectedTarget(); - uint256 requireQuoteCapital = amount.mul(getTotalQuoteCapital()).divCeil(quoteTarget); + uint256 totalQuoteCapital = getTotalQuoteCapital(); + require(totalQuoteCapital > 0, "NO_QUOTE_LP"); + + uint256 requireQuoteCapital = amount.mul(totalQuoteCapital).divCeil(quoteTarget); require( requireQuoteCapital <= getQuoteCapitalBalanceOf(msg.sender), "LP_QUOTE_CAPITAL_BALANCE_NOT_ENOUGH" @@ -137,11 +138,11 @@ contract LiquidityProvider is Storage, Pricing, Settlement { // handle penalty, penalty may exceed amount uint256 penalty = getWithdrawQuotePenalty(amount); - require(penalty <= amount, "COULD_NOT_AFFORD_LIQUIDITY_PENALTY"); + require(penalty < amount, "COULD_NOT_AFFORD_LIQUIDITY_PENALTY"); // settlement _TARGET_QUOTE_TOKEN_AMOUNT_ = _TARGET_QUOTE_TOKEN_AMOUNT_.sub(amount); - _burnQuoteTokenCapital(msg.sender, requireQuoteCapital); + _burnQuoteCapital(msg.sender, requireQuoteCapital); _quoteTokenTransferOut(to, amount.sub(penalty)); _donateQuoteToken(penalty); @@ -152,12 +153,12 @@ contract LiquidityProvider is Storage, Pricing, Settlement { } function withdrawBaseTo(address to, uint256 amount) public preventReentrant returns (uint256) { - uint256 B = _BASE_BALANCE_; - require(amount <= B, "DODO_BASE_TOKEN_BALANCE_NOT_ENOUGH"); - // calculate capital (uint256 baseTarget, ) = _getExpectedTarget(); - uint256 requireBaseCapital = amount.mul(getTotalBaseCapital()).divCeil(baseTarget); + uint256 totalBaseCapital = getTotalBaseCapital(); + require(totalBaseCapital > 0, "NO_BASE_LP"); + + uint256 requireBaseCapital = amount.mul(totalBaseCapital).divCeil(baseTarget); require( requireBaseCapital <= getBaseCapitalBalanceOf(msg.sender), "LP_BASE_CAPITAL_BALANCE_NOT_ENOUGH" @@ -169,7 +170,7 @@ contract LiquidityProvider is Storage, Pricing, Settlement { // settlement _TARGET_BASE_TOKEN_AMOUNT_ = _TARGET_BASE_TOKEN_AMOUNT_.sub(amount); - _burnBaseTokenCapital(msg.sender, requireBaseCapital); + _burnBaseCapital(msg.sender, requireBaseCapital); _baseTokenTransferOut(to, amount.sub(penalty)); _donateBaseToken(penalty); @@ -182,9 +183,7 @@ contract LiquidityProvider is Storage, Pricing, Settlement { // ============ Withdraw all Functions ============ function withdrawAllQuoteTo(address to) public preventReentrant returns (uint256) { - uint256 Q = _QUOTE_BALANCE_; uint256 withdrawAmount = getLpQuoteBalance(msg.sender); - require(withdrawAmount <= Q, "DODO_QUOTE_TOKEN_BALANCE_NOT_ENOUGH"); // handle penalty, penalty may exceed amount uint256 penalty = getWithdrawQuotePenalty(withdrawAmount); @@ -192,7 +191,7 @@ contract LiquidityProvider is Storage, Pricing, Settlement { // settlement _TARGET_QUOTE_TOKEN_AMOUNT_ = _TARGET_QUOTE_TOKEN_AMOUNT_.sub(withdrawAmount); - _burnQuoteTokenCapital(msg.sender, getQuoteCapitalBalanceOf(msg.sender)); + _burnQuoteCapital(msg.sender, getQuoteCapitalBalanceOf(msg.sender)); _quoteTokenTransferOut(to, withdrawAmount.sub(penalty)); _donateQuoteToken(penalty); @@ -203,9 +202,7 @@ contract LiquidityProvider is Storage, Pricing, Settlement { } function withdrawAllBaseTo(address to) public preventReentrant returns (uint256) { - uint256 B = _BASE_BALANCE_; uint256 withdrawAmount = getLpBaseBalance(msg.sender); - require(withdrawAmount <= B, "DODO_BASE_TOKEN_BALANCE_NOT_ENOUGH"); // handle penalty, penalty may exceed amount uint256 penalty = getWithdrawBasePenalty(withdrawAmount); @@ -213,7 +210,7 @@ contract LiquidityProvider is Storage, Pricing, Settlement { // settlement _TARGET_BASE_TOKEN_AMOUNT_ = _TARGET_BASE_TOKEN_AMOUNT_.sub(withdrawAmount); - _burnBaseTokenCapital(msg.sender, getBaseCapitalBalanceOf(msg.sender)); + _burnBaseCapital(msg.sender, getBaseCapitalBalanceOf(msg.sender)); _baseTokenTransferOut(to, withdrawAmount.sub(penalty)); _donateBaseToken(penalty); @@ -225,19 +222,19 @@ contract LiquidityProvider is Storage, Pricing, Settlement { // ============ Helper Functions ============ - function _mintBaseTokenCapital(address user, uint256 amount) internal { + function _mintBaseCapital(address user, uint256 amount) internal { IDODOLpToken(_BASE_CAPITAL_TOKEN_).mint(user, amount); } - function _mintQuoteTokenCapital(address user, uint256 amount) internal { + function _mintQuoteCapital(address user, uint256 amount) internal { IDODOLpToken(_QUOTE_CAPITAL_TOKEN_).mint(user, amount); } - function _burnBaseTokenCapital(address user, uint256 amount) internal { + function _burnBaseCapital(address user, uint256 amount) internal { IDODOLpToken(_BASE_CAPITAL_TOKEN_).burn(user, amount); } - function _burnQuoteTokenCapital(address user, uint256 amount) internal { + function _burnQuoteCapital(address user, uint256 amount) internal { IDODOLpToken(_QUOTE_CAPITAL_TOKEN_).burn(user, amount); } @@ -264,8 +261,8 @@ contract LiquidityProvider is Storage, Pricing, Settlement { } function getWithdrawQuotePenalty(uint256 amount) public view returns (uint256 penalty) { + require(amount <= _QUOTE_BALANCE_, "DODO_QUOTE_TOKEN_BALANCE_NOT_ENOUGH"); if (_R_STATUS_ == Types.RStatus.BELOW_ONE) { - require(amount < _QUOTE_BALANCE_, "DODO_QUOTE_BALANCE_NOT_ENOUGH"); uint256 spareBase = _BASE_BALANCE_.sub(_TARGET_BASE_TOKEN_AMOUNT_); uint256 price = getOraclePrice(); uint256 fairAmount = DecimalMath.mul(spareBase, price); @@ -274,6 +271,7 @@ contract LiquidityProvider is Storage, Pricing, Settlement { _K_, fairAmount ); + // if amount = _QUOTE_BALANCE_, div error uint256 targetQuoteWithWithdraw = DODOMath._SolveQuadraticFunctionForTarget( _QUOTE_BALANCE_.sub(amount), _K_, @@ -286,8 +284,8 @@ contract LiquidityProvider is Storage, Pricing, Settlement { } function getWithdrawBasePenalty(uint256 amount) public view returns (uint256 penalty) { + require(amount <= _BASE_BALANCE_, "DODO_BASE_TOKEN_BALANCE_NOT_ENOUGH"); if (_R_STATUS_ == Types.RStatus.ABOVE_ONE) { - require(amount < _BASE_BALANCE_, "DODO_BASE_BALANCE_NOT_ENOUGH"); uint256 spareQuote = _QUOTE_BALANCE_.sub(_TARGET_QUOTE_TOKEN_AMOUNT_); uint256 price = getOraclePrice(); uint256 fairAmount = DecimalMath.divFloor(spareQuote, price); @@ -296,6 +294,7 @@ contract LiquidityProvider is Storage, Pricing, Settlement { _K_, fairAmount ); + // if amount = _BASE_BALANCE_, div error uint256 targetBaseWithWithdraw = DODOMath._SolveQuadraticFunctionForTarget( _BASE_BALANCE_.sub(amount), _K_, diff --git a/contracts/impl/Trader.sol b/contracts/impl/Trader.sol index 80d018c..8a5f6a6 100644 --- a/contracts/impl/Trader.sol +++ b/contracts/impl/Trader.sol @@ -223,6 +223,7 @@ contract Trader is Storage, Pricing, Settlement { // complex case, R status may change if (buyBaseAmount < backToOneReceiveBase) { // case 3.1: R status do not change + // no need to check payQuote because spare base token must be greater than zero payQuote = _RBelowBuyBaseToken(buyBaseAmount, _QUOTE_BALANCE_, newQuoteTarget); newRStatus = Types.RStatus.BELOW_ONE; } else if (buyBaseAmount == backToOneReceiveBase) { From acbbaeea93dbef8b960e8e6ba1e0166fc52ba108 Mon Sep 17 00:00:00 2001 From: mingda Date: Fri, 26 Jun 2020 13:08:47 +0800 Subject: [PATCH 004/118] fix deposit base permission control --- contracts/impl/LiquidityProvider.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/impl/LiquidityProvider.sol b/contracts/impl/LiquidityProvider.sol index ed110f6..533e7f2 100644 --- a/contracts/impl/LiquidityProvider.sol +++ b/contracts/impl/LiquidityProvider.sol @@ -43,12 +43,12 @@ contract LiquidityProvider is Storage, Pricing, Settlement { // ============ Modifiers ============ modifier depositQuoteAllowed() { - require(_DEPOSIT_QUOTE_ALLOWED_, "DEPOSIT_QUOTE_NOT_ALLOWED"); + require(_DEPOSIT_QUOTE_ALLOWED_, "DEPOSIT_QUOTE_TOKEN_NOT_ALLOWED"); _; } modifier depositBaseAllowed() { - require(_DEPOSIT_BASE_ALLOWED_, "DEPOSIT_BASE_NOT_ALLOWED"); + require(_DEPOSIT_BASE_ALLOWED_, "DEPOSIT_BASE_TOKEN_NOT_ALLOWED"); _; } @@ -103,7 +103,7 @@ contract LiquidityProvider is Storage, Pricing, Settlement { emit DepositQuoteToken(msg.sender, to, amount); } - function depositBaseTo(address to, uint256 amount) public preventReentrant depositQuoteAllowed { + function depositBaseTo(address to, uint256 amount) public preventReentrant depositBaseAllowed { (uint256 baseTarget, ) = _getExpectedTarget(); uint256 totalBaseCapital = getTotalBaseCapital(); uint256 capital = amount; From ccce3f9cd832c267fc9f6a57b93cb76e554af871 Mon Sep 17 00:00:00 2001 From: mingda Date: Fri, 26 Jun 2020 13:08:59 +0800 Subject: [PATCH 005/118] docs for audit --- docs/DODO Smart Contract Instructions.html | 968 +++++++++++++++++++++ docs/PMM Algorithm Specification.html | 686 +++++++++++++++ 2 files changed, 1654 insertions(+) create mode 100644 docs/DODO Smart Contract Instructions.html create mode 100644 docs/PMM Algorithm Specification.html diff --git a/docs/DODO Smart Contract Instructions.html b/docs/DODO Smart Contract Instructions.html new file mode 100644 index 0000000..7aac059 --- /dev/null +++ b/docs/DODO Smart Contract Instructions.html @@ -0,0 +1,968 @@ + + + + + + + +DODO Smart Contract Instructions + + + + + + + + + + + + + +

DODO Smart Contract Instructions

+ +

This is an instructions for users who want to interact with dodo smart contract directly.

+ +

Overview

+ +

Each trading pair is an independent DODO smart contract, and all DODO contracts are registered in DODO ZOO.

+ +

Users interact with each DODO smart contract directly. All external functions are divided into three sub-contracts according to the role of their users: Admin, Trader and LiquidityProvider.

+ +

To simplify users' operations, we developed DODO ETH Proxy, a helper contract that helps user handle with WETH-ETH converting.

+ +

+ +

For Trader

+ +

sellBaseToken(uint256 amount, uint256 minReceiveQuote) returns (uint256 receiveQuote)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
sellBaseTokenDesc
@devSell base token and receive quote token
@param amountThe amount of base token to sell
@param minReceiveQuoteThe minimum amount of quote token required. Transaction will be reverted if the trader receive quote token less than this value.
@returns receiveQuoteThe amount of quote token received
+ +

buyBaseToken(uint256 amount, uint256 maxPayQuote) returns (uint256 payQuote)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
buyBaseTokenDesc
@devBuy base token and pay quote token
@param amountThe amount of base token to buy
@param maxPayQuoteThe maximum amount of quote token needs to pay. Transaction will be reverted if the trader pay quote token greater than this value.
@returns payQuoteThe amount of quote token paid
+ +

For Liquidity Provider

+ +

depositBase(uint256 amount)

+ + + + + + + + + + + + + + + + + + + +
depositBaseDesc
@devDeposit base token to liquidity pool
@param amountThe amount of base token to deposit
+ +

depositQuote(uint256 amount)

+ + + + + + + + + + + + + + + + + + + +
depositQuoteDesc
@devDeposit quote token to liquidity pool
@param amountThe amount of quote token to deposit
+ +

withdrawBase(uint256 amount) returns (uint256 receiveAmount)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
withdrawBaseDesc
@devWithdraw base token from liquidity pool
@param amountThe amount of base token to withdraw
@returns receiveAmountThe amount of base token sender received
@noticeDODO charges penalty fee from liquidity providers who withdraw assets and share the fee with all remaining liquidity providers. Normally the penalty would be 0 or nearly 0.
+ +

withdrawQuote(uint256 amount) returns (uint256 receiveAmount)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
withdrawQuoteDesc
@devWithdraw quote token from liquidity pool
@param amountThe amount of quote token to withdraw
@returns receiveAmountThe amount of quote token sender received
@noticeDODO charges penalty fee from liquidity providers who withdraw assets and share the fee with all remaining liquidity providers. Normally the penalty would be 0 or nearly 0.
+ +

For FrontEnd Developer

+ +

Sendable functions

+ +

withdrawAllBase() returns (uint256 receiveAmount)

+ + + + + + + + + + + + + + + +
withdrawAllBaseDesc
@devWithdraw message sender’s all base token deposited in the pool.
+ +

withdrawAllQuote() returns (uint256 receiveAmount)

+ + + + + + + + + + + + + + + +
withdrawAllQuoteDesc
@devWithdraw message sender’s all quote token deposited in the pool.
+ +

View functions

+ +

_GAS_PRICE_LIMIT_

+ + + + + + + + + + + + + + + +
_GASPRICELIMIT_Desc
@devA public variable. All transactions involving trading should be sent with gas price no greater than this value. Otherwise, DODO will revert the transactions.
+ +

getLpBaseBalance(address lp) returns (uint256 lpBalance)

+ + + + + + + + + + + + + + + +
getLpBaseBalanceDesc
@devGet liquidity provider’s base token balance in the pool
+ +

getLpQuoteBalance(address lp) returns (uint256 lpBalance)

+ + + + + + + + + + + + + + + +
getLpQuoteBalanceDesc
@devGet liquidity provider’s quote token balance in the pool
+ +

getWithdrawQuotePenalty(uint256 amount) returns (uint256 penalty)

+ + + + + + + + + + + + + + + +
getWithdrawQuotePenaltyDesc
@devGet the penalty fee will be charged if some liquidity provider withdraw a certain amount of quote token from pool.
+ +

getWithdrawBasePenalty(uint256 amount) returns (uint256 penalty)

+ + + + + + + + + + + + + + + +
getWithdrawBasePenaltyDesc
@devGet the penalty fee will be charged if some liquidity provider withdraw a certain amount of base token from pool.
+ +

querySellBaseToken(uint256 amount) returns (uint256 receiveQuote)

+ + + + + + + + + + + + + + + +
querySellBaseTokenDesc
@devA “view” version of sellBaseToken. This function can be really useful to query price because it doesn’t cost gas.
+ +

queryBuyBaseToken(uint256 amount) returns (uint256 payQuote)

+ + + + + + + + + + + + + + + +
queryBuyBaseTokenDesc
@devA “view” version of buyBaseToken. This function can be really useful to query price because it doesn’t cost gas.
+ +

DODO Eth Proxy functions

+ +

As DODO only works fine with ERC20 tokens, if you want to use Ether directly on DODO, we provide a proxy smart contract to help you access DODO. Basicly, the proxy contract convert Ether to Wrapped ETH, a kind of ERC20 token, and use it on DODO. The operation is totally transparent to user.

+ +

sellEthTo(address quoteTokenAddress,uint256 ethAmount,uint256 minReceiveTokenAmount) returns (uint256 receiveTokenAmount)

+ + + + + + + + + + + + + + + +
sellEthToDesc
@devSell ETH on WETH-quoteTokenAddress market
+ +

buyEthWith(address quoteTokenAddress,uint256 ethAmount,uint256 maxPayTokenAmount) returns (uint256 payTokenAmount)

+ + + + + + + + + + + + + + + +
buyEthToDesc
@devBuy ETH on WETH-quoteTokenAddress market
+ +

depositEth(uint256 ethAmount, address quoteTokenAddress)

+ + + + + + + + + + + + + + + +
depositEthDesc
@devDeposit ETH to WETH-quoteTokenAddress market
+ +

For Quant

+ +

withdrawBaseTo(address to, uint256 amount) returns (uint256)

+ +

depositBaseTo(address to, uint256 amount)

+ +

withdrawQuoteTo(address to, uint256 amount) returns (uint256)

+ +

depositQuoteTo(address to, uint256 amount)

+ +

withdrawAllBaseTo(address to) returns (uint256)

+ +

withdrawAllQuoteTo(address to) returns (uint256)

+ + + + + + + + + + + + + + + diff --git a/docs/PMM Algorithm Specification.html b/docs/PMM Algorithm Specification.html new file mode 100644 index 0000000..686e2c0 --- /dev/null +++ b/docs/PMM Algorithm Specification.html @@ -0,0 +1,686 @@ + + + + + + + +PMM Algorithm Specification + + + + + + + + + + + + + +

DODO PMM 算法详解

+ +

DODO 是新一代由算法驱动的纯链上流动性提供方案。很多人误以为这是对 AMM(Auto Market Maker)算法的改进,事实上 DODO 提出了全新的算法,其运作机制与 AMM 截然不同,我们将其命名为 PMM(Proactive Market Maker)算法。

+ +

本文将全面对算法进行解析,尤其是其链上实现版本。

+ +

资金池回归模型

+ +

PMM 的资金池由四个参数描述

+ +
    +
  • \(B_0\) BaseToken 回归目标
  • +
  • \(Q_0\) QuoteToken 回归目标
  • +
  • \(B\) BaseToken 余额
  • +
  • \(Q\) QuoteToken 余额
  • +
+ +
+

以ETH-USDT交易对为例,BaseToken指ETH,QuoteToken指USDT

+
+ +

价格曲线由下面的公式给出

+ +

\[P_{margin}=iR\] +\[if \ B<B_0, \ R=1-k+(\frac{B_0}{B})^2k\] +\[if \ Q<Q_0, \ R=1/(1-k+(\frac{Q_0}{Q})^2k)\] +\[else \ R=1\]

+ +

可以发现PMM有三种工作场景:均衡、BaseToken匮乏、QuoteToken匮乏。

+ +
    +
  • 没有用户交易时,资金池处于均衡状态,BaseToken和QuoteToken都处于其回归目标
  • +
  • 当用户卖出BaseToken时,资金池BaseToken余额高于回归目标,而QuoteToken余额小于回归目标。此时PMM算法会尝试卖出多余的BaseToken,以使QuoteToken余额回归均衡状态。
  • +
  • 当用户买入BaseToken时,资金池QuoteToken余额高于回归目标,而BaseToken余额小于回归目标。此时PMM算法会尝试卖出多余的QuoteToken,以使BaseToken余额回归均衡状态。
  • +
+ +

+ +

参数\(R\)在此过程中起到了促进回归的作用,资金池偏离均衡状态越多,\(R\)越偏离1,PMM算法给出的价格便越偏离市场价,吸引套利者帮助资金池回归均衡状态。

+ +

至此我们介绍完毕了PMM算法的运作机制,下一节将进入合约实现环节。

+ +

交易者

+ +

对交易者来说,最重要的就是平均成交价。平均成交价是边际价格\(P_{margin}\)的积分

+ +

单一工作场景下的价格

+ +

BaseToken匮乏场景

+ +

+ +

\[\Delta Q =\int^{B_2}_{B_1}P_{margin}dB= \int^{B_2}_{B_1}(1-k)i+i(\frac{B_0}{B})^2kdB \] +\[= i(B_2-B_1)*(1-k+k\frac{B_0^2}{B_1B_2})\]

+ +

平均成交价为:

+ +

\[P=\frac{\Delta Q}{B_2-B_1}=i*(1-k+k\frac{B_0^2}{B_1B_2})\]

+ +

我们发现,平均成交价只与成交前后系统的状态有关,所以买卖两种操作的价格计算方式是一样的——都是对\(P_{margin}\)进行积分。

+ +

QuoteToken匮乏场景

+ +

为了简化用户理解,我们只提供sellBaseToken和buyBaseToken两个接口,下面来推导quoteToken匮乏场景下,给出想要买卖的baseToken数量,如何计算价格。

+ +

\[\Delta B = \frac{1}{i}(Q_2-Q_1)*(1-k+k\frac{Q_0^2}{Q_1Q_2})\]

+ +

已知\(\Delta B, Q_0, Q_1\),求解\(Q_2\),这是一个二次方程,转化为标准形式后:

+ +

\[(1-k)Q_2^2+(\frac{kQ_0^2}{Q_1}-Q_1+kQ_1-i\Delta B)Q_2-kQ_0^2=0\]

+ +

\[let \ a=1-k, \ b=\frac{kQ_0^2}{Q_1}-Q_1+kQ_1-i\Delta B, \ c=-kQ_0^2\]

+ +

因为\(Q_2>=0\),所以舍掉一个负数根,得到\(Q_2\)的公式为

+ +

\[Q_2=\frac{-b+\sqrt{b^2-4ac}}{2a}\]

+ +

在\(\Delta B>0\)时,\(Q_2>Q_1\); 在\(\Delta B<0\)时,\(Q_2<Q_1\); 在\(\Delta B=0\)时,\(Q_2=Q_1\)

+ +

Oracle价格变化的影响

+ +

当系统不处于均衡态时,Oracle变化将带来盈利或亏损。举例来讲,假设现在系统处于BaseToken匮乏场景,Oracle价格提高,将导致多余的QuoteToken无法买入足够的BaseToken,提供BaseToken的lp出现亏损。同理如果Oracle价格下降,多余的QuoteToken可以买入更多的BaseToken,使BaseToken余额超过回归目标,提供BaseToken的lp有盈余。

+ +

为了计算新Oracle价格下的回归目标,我们进行如下推导:

+ +

\[\Delta Q = i(B_2-B_1)*(1-k+k\frac{B_0^2}{B_1B_2})\]

+ +

回归时,\(B_2=B_0\),整理出关于\(B_0\)的二次方程

+ +

\[\frac{k}{B_1}B_0^2+(1-2k)B_0-[(1-k)B_1+\frac{\Delta Q}{i}] = 0\]

+ +

舍弃掉负数解,得到\(B_0\)的解为

+ +

\[B_0=B_1+B_1*\frac{\sqrt{1+\frac{4k\Delta Q}{B_1 i}}-1}{2k}\]

+ +

这里\(\Delta Q=Q-Q_0\). 可以严格证明,在\(\Delta Q \ge 0\)时,\(B_0\ge B_1\). 这一性质非常重要,因为它保证了BaseToken余额和QuoteToken余额不会同时大于回归目标,或同时小于回归目标。这样一来,PMM只会在文章开头提到的三种状态中转换。

+ +

同理我们直接给出\(Q_0\)的计算公式

+ +

\[Q_0=Q_1+Q_1*\frac{\sqrt{1+\frac{4k\Delta B i}{Q_1}}-1}{2k}\]

+ +

跨工作场景时的价格

+ +

由于PMM给出的价格曲线是分段的,如果一笔交易跨越了工作场景(比如在BaseToken匮乏时用户卖出大量BaseToken,直接进入QuoteToken匮乏场景),就需要分段计算价格,并累计。

+ +

这一累计要求精度很高,但计算机有精度损失,所以处理起来要非常小心。合约里提供了三种工作场景下的买卖函数,总计6个。其组合方式是关键。

+ +

流动性提供商

+ +

流动性提供商又称为lp(liquidity provider)。lp有两种操作,充值&提现。

+ +

在BaseToken匮乏场景下充提BaseToken,或在QuoteToken匮乏场景下充提QuoteToken,都会使得改变价格曲线。这要求我们合理地处理充提操作,以使资金池保持健康和公平。

+ +

充值

+ +

我们以BaseToken匮乏场景为例,研究充值如何影响lp收益。

+ +

根据上文推导出的\(B_0\)计算公式

+ +

\[B_0=B_1+B_1*\frac{\sqrt{1+\frac{4k\Delta Q}{B_1 i}}-1}{2k}\]

+ +

充值\(b\)后,\(B_1\)增加\(b\),而\(B_0\)的增量大于\(b\).就说明充值使得所有提供BaseToken的lp都获得了收益。这一收益的来源是,充值使价格曲线变得平缓,同样数量的\(\Delta Q\)可以购买更多BaseToken。

+ +

在这种情况下,lp一旦充值就会获得收益,我们称之为“充值奖励”,因为充值使得系统更接近均衡状态了。这笔奖励的本质来源是交易者付出的滑点。

+ +

但“充值奖励”并不是无风险套利机会,请继续阅读下一节。

+ +

提现

+ +

与上一节同理,提现\(b\)后,\(B_1\)减少\(b\),而\(B_0\)减少的量多于\(b\)。说明提现使所有BaseToken的lp都蒙受损失。这一损失的来源是,提现使价格曲线变得陡峭,同样数量的\(\Delta Q\)只能购买更少的BaseToken。

+ +

PMM算法规定,这种情况下提现需要缴纳一笔“流动性罚金”。罚金数额等于提币后造成的lp损失,这笔罚金将直接充入资金池,分给所有未撤资的lp。

+ +

回到上一节中的情况,如果lp充值后立刻提现,罚金将大于收益,所以不会有无风险套利的机会。这一设计倾向于未撤资lp,可以最大限度留存资金。

+ +
+

值得注意的是,不论是充值奖励,还是流动性罚金,都只有在系统偏离均衡状态较远,且充提金额很大的时候才显著。 +普通用户往往感知不到这一收益(损失)的存在。当然也欢迎羊毛党,在系统偏离均衡时充值赚取充值奖励,在系统回归平衡时提现来避免流动性罚金

+
+ + + + + + + + + + + + + + + From 8de5d8f1abefaf1984e2c03d2a555a8c010db750 Mon Sep 17 00:00:00 2001 From: mingda Date: Fri, 26 Jun 2020 13:09:07 +0800 Subject: [PATCH 006/118] fix coverage --- .gitignore | 3 ++- coverage.json | 2 +- package.json | 2 +- test/Admin.test.ts | 4 ++-- test/LiquidityProvider.test.ts | 15 +++++++++++++-- test/Trader.test.ts | 2 +- 6 files changed, 20 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 6b61b66..28e453c 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,8 @@ build/ dist/ -docs/ +docs/img +docs/src node_modules/ coverage/ lint/ diff --git a/coverage.json b/coverage.json index e90025d..c1c4a51 100644 --- a/coverage.json +++ b/coverage.json @@ -1 +1 @@ -{"contracts/DODO.sol":{"l":{"37":11,"38":10,"40":10,"41":10,"42":10,"43":10,"44":10,"46":10,"47":10,"48":10,"49":10,"51":10,"52":10,"53":10,"54":10,"56":10,"57":10,"59":10},"path":"/Users/leimingda/Documents/dodo/contracts/DODO.sol","s":{"1":11,"2":10,"3":10,"4":10,"5":10,"6":10,"7":10,"8":10,"9":10,"10":10,"11":10,"12":10,"13":10,"14":10,"15":10,"16":10,"17":10,"18":10},"b":{"1":[10,1]},"f":{"1":11},"fnMap":{"1":{"name":"init","line":36,"loc":{"start":{"line":26,"column":4},"end":{"line":60,"column":4}}}},"statementMap":{"1":{"start":{"line":37,"column":8},"end":{"line":37,"column":58}},"2":{"start":{"line":38,"column":8},"end":{"line":38,"column":27}},"3":{"start":{"line":40,"column":8},"end":{"line":40,"column":32}},"4":{"start":{"line":41,"column":8},"end":{"line":41,"column":32}},"5":{"start":{"line":42,"column":8},"end":{"line":42,"column":31}},"6":{"start":{"line":43,"column":8},"end":{"line":43,"column":33}},"7":{"start":{"line":44,"column":8},"end":{"line":44,"column":24}},"8":{"start":{"line":46,"column":8},"end":{"line":46,"column":36}},"9":{"start":{"line":47,"column":8},"end":{"line":47,"column":37}},"10":{"start":{"line":48,"column":8},"end":{"line":48,"column":29}},"11":{"start":{"line":49,"column":8},"end":{"line":49,"column":40}},"12":{"start":{"line":51,"column":8},"end":{"line":51,"column":32}},"13":{"start":{"line":52,"column":8},"end":{"line":52,"column":32}},"14":{"start":{"line":53,"column":8},"end":{"line":53,"column":14}},"15":{"start":{"line":54,"column":8},"end":{"line":54,"column":37}},"16":{"start":{"line":56,"column":8},"end":{"line":56,"column":56}},"17":{"start":{"line":57,"column":8},"end":{"line":57,"column":57}},"18":{"start":{"line":59,"column":8},"end":{"line":59,"column":29}}},"branchMap":{"1":{"line":37,"type":"if","locations":[{"start":{"line":37,"column":8},"end":{"line":37,"column":8}},{"start":{"line":37,"column":8},"end":{"line":37,"column":8}}]}}},"contracts/DODOEthProxy.sol":{"l":{"52":1,"53":1,"57":0,"61":1,"69":2,"70":1,"71":1,"72":1,"73":1,"74":1,"75":1,"76":1,"77":1,"78":1,"86":1,"87":1,"88":1,"89":1,"90":1,"91":1,"92":1,"93":1,"94":1,"95":1,"103":4,"104":3,"105":3,"106":3,"107":3,"108":3,"118":1,"126":1},"path":"/Users/leimingda/Documents/dodo/contracts/DODOEthProxy.sol","s":{"1":1,"2":1,"3":0,"4":2,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":1,"14":1,"15":1,"16":1,"17":1,"18":1,"19":1,"20":1,"21":1,"22":1,"23":1,"24":4,"25":3,"26":3,"27":3,"28":3,"29":3,"30":1,"31":1},"b":{"1":[0,0],"2":[1,0],"3":[1,1],"4":[1,0],"5":[1,0],"6":[3,1]},"f":{"1":1,"2":0,"3":2,"4":1,"5":4,"6":1,"7":1},"fnMap":{"1":{"name":"constructor","line":51,"loc":{"start":{"line":51,"column":4},"end":{"line":54,"column":4}}},"2":{"name":null,"line":56,"loc":{"start":{"line":56,"column":4},"end":{"line":58,"column":4}}},"3":{"name":"sellEthTo","line":68,"loc":{"start":{"line":64,"column":4},"end":{"line":79,"column":4}}},"4":{"name":"buyEthWith","line":85,"loc":{"start":{"line":81,"column":4},"end":{"line":96,"column":4}}},"5":{"name":"depositEth","line":101,"loc":{"start":{"line":98,"column":4},"end":{"line":109,"column":4}}},"6":{"name":"_transferIn","line":113,"loc":{"start":{"line":113,"column":4},"end":{"line":119,"column":4}}},"7":{"name":"_transferOut","line":121,"loc":{"start":{"line":121,"column":4},"end":{"line":127,"column":4}}}},"statementMap":{"1":{"start":{"line":52,"column":8},"end":{"line":52,"column":27}},"2":{"start":{"line":53,"column":8},"end":{"line":53,"column":20}},"3":{"start":{"line":57,"column":8},"end":{"line":57,"column":60}},"4":{"start":{"line":69,"column":8},"end":{"line":69,"column":62}},"5":{"start":{"line":70,"column":8},"end":{"line":70,"column":78}},"6":{"start":{"line":71,"column":8},"end":{"line":71,"column":69}},"7":{"start":{"line":72,"column":8},"end":{"line":72,"column":81}},"8":{"start":{"line":73,"column":8},"end":{"line":73,"column":48}},"9":{"start":{"line":74,"column":8},"end":{"line":74,"column":45}},"10":{"start":{"line":75,"column":8},"end":{"line":75,"column":66}},"11":{"start":{"line":76,"column":8},"end":{"line":76,"column":70}},"12":{"start":{"line":77,"column":8},"end":{"line":77,"column":87}},"13":{"start":{"line":78,"column":8},"end":{"line":78,"column":33}},"14":{"start":{"line":86,"column":8},"end":{"line":86,"column":78}},"15":{"start":{"line":87,"column":8},"end":{"line":87,"column":64}},"16":{"start":{"line":88,"column":8},"end":{"line":88,"column":67}},"17":{"start":{"line":89,"column":8},"end":{"line":89,"column":65}},"18":{"start":{"line":90,"column":8},"end":{"line":90,"column":62}},"19":{"start":{"line":91,"column":8},"end":{"line":91,"column":61}},"20":{"start":{"line":92,"column":8},"end":{"line":92,"column":40}},"21":{"start":{"line":93,"column":8},"end":{"line":93,"column":37}},"22":{"start":{"line":94,"column":8},"end":{"line":94,"column":82}},"23":{"start":{"line":95,"column":8},"end":{"line":95,"column":29}},"24":{"start":{"line":103,"column":8},"end":{"line":103,"column":62}},"25":{"start":{"line":104,"column":8},"end":{"line":104,"column":78}},"26":{"start":{"line":105,"column":8},"end":{"line":105,"column":48}},"27":{"start":{"line":106,"column":8},"end":{"line":106,"column":45}},"28":{"start":{"line":107,"column":8},"end":{"line":107,"column":55}},"29":{"start":{"line":108,"column":8},"end":{"line":108,"column":70}},"30":{"start":{"line":118,"column":8},"end":{"line":118,"column":73}},"31":{"start":{"line":126,"column":8},"end":{"line":126,"column":52}}},"branchMap":{"1":{"line":57,"type":"if","locations":[{"start":{"line":57,"column":8},"end":{"line":57,"column":8}},{"start":{"line":57,"column":8},"end":{"line":57,"column":8}}]},"2":{"line":61,"type":"if","locations":[{"start":{"line":61,"column":8},"end":{"line":61,"column":8}},{"start":{"line":61,"column":8},"end":{"line":61,"column":8}}]},"3":{"line":69,"type":"if","locations":[{"start":{"line":69,"column":8},"end":{"line":69,"column":8}},{"start":{"line":69,"column":8},"end":{"line":69,"column":8}}]},"4":{"line":72,"type":"if","locations":[{"start":{"line":72,"column":8},"end":{"line":72,"column":8}},{"start":{"line":72,"column":8},"end":{"line":72,"column":8}}]},"5":{"line":88,"type":"if","locations":[{"start":{"line":88,"column":8},"end":{"line":88,"column":8}},{"start":{"line":88,"column":8},"end":{"line":88,"column":8}}]},"6":{"line":103,"type":"if","locations":[{"start":{"line":103,"column":8},"end":{"line":103,"column":8}},{"start":{"line":103,"column":8},"end":{"line":103,"column":8}}]}}},"contracts/DODOZoo.sol":{"l":{"42":12,"43":10,"44":10,"45":10,"56":10,"57":10,"58":10,"59":10,"65":12,"69":10,"71":2,"76":15},"path":"/Users/leimingda/Documents/dodo/contracts/DODOZoo.sol","s":{"1":12,"2":10,"3":10,"4":10,"5":10,"6":10,"7":10,"8":10,"9":12,"10":10,"11":2,"12":15},"b":{"1":[10,2],"2":[10,0],"3":[10,2]},"f":{"1":12,"2":12,"3":15},"fnMap":{"1":{"name":"breedDODO","line":41,"loc":{"start":{"line":31,"column":4},"end":{"line":60,"column":4}}},"2":{"name":"isDODORegistered","line":64,"loc":{"start":{"line":64,"column":4},"end":{"line":73,"column":4}}},"3":{"name":"getDODO","line":75,"loc":{"start":{"line":75,"column":4},"end":{"line":77,"column":4}}}},"statementMap":{"1":{"start":{"line":42,"column":8},"end":{"line":42,"column":78}},"2":{"start":{"line":43,"column":8},"end":{"line":43,"column":66}},"3":{"start":{"line":44,"column":8},"end":{"line":44,"column":49}},"4":{"start":{"line":45,"column":8},"end":{"line":45,"column":1105}},"5":{"start":{"line":56,"column":8},"end":{"line":56,"column":52}},"6":{"start":{"line":57,"column":8},"end":{"line":57,"column":59}},"7":{"start":{"line":58,"column":8},"end":{"line":58,"column":35}},"8":{"start":{"line":59,"column":8},"end":{"line":59,"column":26}},"9":{"start":{"line":65,"column":8},"end":{"line":65,"column":1687}},"10":{"start":{"line":69,"column":12},"end":{"line":69,"column":24}},"11":{"start":{"line":71,"column":12},"end":{"line":71,"column":23}},"12":{"start":{"line":76,"column":8},"end":{"line":76,"column":53}}},"branchMap":{"1":{"line":42,"type":"if","locations":[{"start":{"line":42,"column":8},"end":{"line":42,"column":8}},{"start":{"line":42,"column":8},"end":{"line":42,"column":8}}]},"2":{"line":43,"type":"if","locations":[{"start":{"line":43,"column":8},"end":{"line":43,"column":8}},{"start":{"line":43,"column":8},"end":{"line":43,"column":8}}]},"3":{"line":65,"type":"if","locations":[{"start":{"line":65,"column":8},"end":{"line":65,"column":8}},{"start":{"line":65,"column":8},"end":{"line":65,"column":8}}]}}},"contracts/impl/Admin.sol":{"l":{"28":1,"32":1,"36":1,"40":2,"41":2,"45":2,"46":2,"50":3,"51":3,"55":1,"56":1,"62":1,"66":1,"70":1,"74":1,"78":1,"82":1},"path":"/Users/leimingda/Documents/dodo/contracts/impl/Admin.sol","s":{"1":1,"2":1,"3":1,"4":2,"5":2,"6":2,"7":2,"8":3,"9":3,"10":1,"11":1,"12":1,"13":1,"14":1,"15":1,"16":1,"17":1},"b":{},"f":{"1":1,"2":1,"3":1,"4":2,"5":2,"6":3,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":1},"fnMap":{"1":{"name":"setOracle","line":27,"loc":{"start":{"line":27,"column":4},"end":{"line":29,"column":4}}},"2":{"name":"setSupervisor","line":31,"loc":{"start":{"line":31,"column":4},"end":{"line":33,"column":4}}},"3":{"name":"setMaintainer","line":35,"loc":{"start":{"line":35,"column":4},"end":{"line":37,"column":4}}},"4":{"name":"setLiquidityProviderFeeRate","line":39,"loc":{"start":{"line":39,"column":4},"end":{"line":42,"column":4}}},"5":{"name":"setMaintainerFeeRate","line":44,"loc":{"start":{"line":44,"column":4},"end":{"line":47,"column":4}}},"6":{"name":"setK","line":49,"loc":{"start":{"line":49,"column":4},"end":{"line":52,"column":4}}},"7":{"name":"setGasPriceLimit","line":54,"loc":{"start":{"line":54,"column":4},"end":{"line":57,"column":4}}},"8":{"name":"disableTrading","line":61,"loc":{"start":{"line":61,"column":4},"end":{"line":63,"column":4}}},"9":{"name":"enableTrading","line":65,"loc":{"start":{"line":65,"column":4},"end":{"line":67,"column":4}}},"10":{"name":"disableQuoteDeposit","line":69,"loc":{"start":{"line":69,"column":4},"end":{"line":71,"column":4}}},"11":{"name":"enableQuoteDeposit","line":73,"loc":{"start":{"line":73,"column":4},"end":{"line":75,"column":4}}},"12":{"name":"disableBaseDeposit","line":77,"loc":{"start":{"line":77,"column":4},"end":{"line":79,"column":4}}},"13":{"name":"enableBaseDeposit","line":81,"loc":{"start":{"line":81,"column":4},"end":{"line":83,"column":4}}}},"statementMap":{"1":{"start":{"line":28,"column":8},"end":{"line":28,"column":27}},"2":{"start":{"line":32,"column":8},"end":{"line":32,"column":35}},"3":{"start":{"line":36,"column":8},"end":{"line":36,"column":35}},"4":{"start":{"line":40,"column":8},"end":{"line":40,"column":49}},"5":{"start":{"line":41,"column":8},"end":{"line":41,"column":29}},"6":{"start":{"line":45,"column":8},"end":{"line":45,"column":43}},"7":{"start":{"line":46,"column":8},"end":{"line":46,"column":29}},"8":{"start":{"line":50,"column":8},"end":{"line":50,"column":17}},"9":{"start":{"line":51,"column":8},"end":{"line":51,"column":29}},"10":{"start":{"line":55,"column":8},"end":{"line":55,"column":43}},"11":{"start":{"line":56,"column":8},"end":{"line":56,"column":50}},"12":{"start":{"line":62,"column":8},"end":{"line":62,"column":30}},"13":{"start":{"line":66,"column":8},"end":{"line":66,"column":29}},"14":{"start":{"line":70,"column":8},"end":{"line":70,"column":38}},"15":{"start":{"line":74,"column":8},"end":{"line":74,"column":37}},"16":{"start":{"line":78,"column":8},"end":{"line":78,"column":37}},"17":{"start":{"line":82,"column":8},"end":{"line":82,"column":36}}},"branchMap":{}},"contracts/impl/LiquidityProvider.sol":{"l":{"47":38,"48":37,"52":43,"53":42,"59":8,"63":39,"67":8,"71":37,"75":9,"79":8,"89":37,"90":37,"91":37,"92":37,"93":30,"95":37,"96":7,"99":37,"100":37,"101":37,"103":37,"107":42,"108":42,"109":42,"110":42,"111":34,"113":42,"114":8,"117":42,"118":42,"119":42,"121":42,"127":9,"128":9,"131":8,"132":8,"133":8,"139":7,"140":7,"143":5,"144":5,"145":5,"146":5,"148":5,"149":5,"151":5,"155":9,"156":9,"159":8,"160":8,"161":8,"167":7,"168":7,"171":5,"172":5,"173":5,"174":5,"176":5,"177":5,"179":5,"185":9,"186":9,"187":9,"190":8,"191":8,"194":8,"195":8,"196":8,"197":8,"199":8,"200":8,"202":8,"206":10,"207":10,"208":10,"211":9,"212":9,"215":9,"216":9,"217":9,"218":9,"220":9,"221":9,"223":9,"229":42,"233":37,"237":14,"241":13,"247":37,"248":37,"249":37,"250":1,"252":36,"253":36,"257":34,"258":34,"259":34,"260":1,"262":33,"263":33,"267":20,"268":7,"269":6,"270":6,"271":6,"272":6,"277":6,"282":6,"284":13,"289":22,"290":9,"291":8,"292":8,"293":8,"294":8,"299":8,"304":8,"306":13},"path":"/Users/leimingda/Documents/dodo/contracts/impl/LiquidityProvider.sol","s":{"1":38,"2":43,"3":8,"4":39,"5":8,"6":37,"7":9,"8":8,"9":37,"10":37,"11":37,"12":37,"13":30,"14":37,"15":7,"16":37,"17":37,"18":37,"19":37,"20":42,"21":42,"22":42,"23":42,"24":34,"25":42,"26":8,"27":42,"28":42,"29":42,"30":42,"31":9,"32":9,"33":8,"34":8,"35":8,"36":7,"37":7,"38":5,"39":5,"40":5,"41":5,"42":5,"43":5,"44":5,"45":9,"46":9,"47":8,"48":8,"49":8,"50":7,"51":7,"52":5,"53":5,"54":5,"55":5,"56":5,"57":5,"58":5,"59":9,"60":9,"61":9,"62":8,"63":8,"64":8,"65":8,"66":8,"67":8,"68":8,"69":8,"70":8,"71":10,"72":10,"73":10,"74":9,"75":9,"76":9,"77":9,"78":9,"79":9,"80":9,"81":9,"82":9,"83":42,"84":37,"85":14,"86":13,"87":37,"88":37,"89":37,"90":1,"91":36,"92":36,"93":34,"94":34,"95":34,"96":1,"97":33,"98":33,"99":20,"100":7,"101":6,"102":6,"103":6,"104":6,"105":6,"106":6,"107":13,"108":22,"109":9,"110":8,"111":8,"112":8,"113":8,"114":8,"115":8,"116":13},"b":{"1":[37,1],"2":[42,1],"3":[30,7],"4":[7,30],"5":[34,8],"6":[8,34],"7":[8,1],"8":[7,1],"9":[5,2],"10":[8,1],"11":[7,1],"12":[5,2],"13":[8,1],"14":[8,0],"15":[9,1],"16":[9,0],"17":[1,36],"18":[1,33],"19":[7,13],"20":[6,1],"21":[9,13],"22":[8,1]},"f":{"1":38,"2":43,"3":8,"4":39,"5":8,"6":37,"7":9,"8":8,"9":37,"10":42,"11":9,"12":9,"13":9,"14":10,"15":42,"16":37,"17":14,"18":13,"19":37,"20":34,"21":20,"22":22},"fnMap":{"1":{"name":"depositQuoteAllowed","line":46,"loc":{"start":{"line":46,"column":4},"end":{"line":49,"column":4}}},"2":{"name":"depositBaseAllowed","line":51,"loc":{"start":{"line":51,"column":4},"end":{"line":54,"column":4}}},"3":{"name":"withdrawBase","line":58,"loc":{"start":{"line":58,"column":4},"end":{"line":60,"column":4}}},"4":{"name":"depositBase","line":62,"loc":{"start":{"line":62,"column":4},"end":{"line":64,"column":4}}},"5":{"name":"withdrawQuote","line":66,"loc":{"start":{"line":66,"column":4},"end":{"line":68,"column":4}}},"6":{"name":"depositQuote","line":70,"loc":{"start":{"line":70,"column":4},"end":{"line":72,"column":4}}},"7":{"name":"withdrawAllBase","line":74,"loc":{"start":{"line":74,"column":4},"end":{"line":76,"column":4}}},"8":{"name":"withdrawAllQuote","line":78,"loc":{"start":{"line":78,"column":4},"end":{"line":80,"column":4}}},"9":{"name":"depositQuoteTo","line":87,"loc":{"start":{"line":84,"column":4},"end":{"line":104,"column":4}}},"10":{"name":"depositBaseTo","line":106,"loc":{"start":{"line":106,"column":4},"end":{"line":122,"column":4}}},"11":{"name":"withdrawQuoteTo","line":126,"loc":{"start":{"line":126,"column":4},"end":{"line":152,"column":4}}},"12":{"name":"withdrawBaseTo","line":154,"loc":{"start":{"line":154,"column":4},"end":{"line":180,"column":4}}},"13":{"name":"withdrawAllQuoteTo","line":184,"loc":{"start":{"line":184,"column":4},"end":{"line":203,"column":4}}},"14":{"name":"withdrawAllBaseTo","line":205,"loc":{"start":{"line":205,"column":4},"end":{"line":224,"column":4}}},"15":{"name":"_mintBaseTokenCapital","line":228,"loc":{"start":{"line":228,"column":4},"end":{"line":230,"column":4}}},"16":{"name":"_mintQuoteTokenCapital","line":232,"loc":{"start":{"line":232,"column":4},"end":{"line":234,"column":4}}},"17":{"name":"_burnBaseTokenCapital","line":236,"loc":{"start":{"line":236,"column":4},"end":{"line":238,"column":4}}},"18":{"name":"_burnQuoteTokenCapital","line":240,"loc":{"start":{"line":240,"column":4},"end":{"line":242,"column":4}}},"19":{"name":"getLpBaseBalance","line":246,"loc":{"start":{"line":246,"column":4},"end":{"line":254,"column":4}}},"20":{"name":"getLpQuoteBalance","line":256,"loc":{"start":{"line":256,"column":4},"end":{"line":264,"column":4}}},"21":{"name":"getWithdrawQuotePenalty","line":266,"loc":{"start":{"line":266,"column":4},"end":{"line":286,"column":4}}},"22":{"name":"getWithdrawBasePenalty","line":288,"loc":{"start":{"line":288,"column":4},"end":{"line":308,"column":4}}}},"statementMap":{"1":{"start":{"line":47,"column":8},"end":{"line":47,"column":68}},"2":{"start":{"line":52,"column":8},"end":{"line":52,"column":66}},"3":{"start":{"line":59,"column":8},"end":{"line":59,"column":49}},"4":{"start":{"line":63,"column":8},"end":{"line":63,"column":40}},"5":{"start":{"line":67,"column":8},"end":{"line":67,"column":50}},"6":{"start":{"line":71,"column":8},"end":{"line":71,"column":41}},"7":{"start":{"line":75,"column":8},"end":{"line":75,"column":44}},"8":{"start":{"line":79,"column":8},"end":{"line":79,"column":45}},"9":{"start":{"line":89,"column":8},"end":{"line":89,"column":54}},"10":{"start":{"line":90,"column":8},"end":{"line":90,"column":32}},"11":{"start":{"line":91,"column":8},"end":{"line":91,"column":58}},"12":{"start":{"line":92,"column":8},"end":{"line":92,"column":2660}},"13":{"start":{"line":93,"column":12},"end":{"line":93,"column":44}},"14":{"start":{"line":95,"column":8},"end":{"line":95,"column":2801}},"15":{"start":{"line":96,"column":12},"end":{"line":96,"column":67}},"16":{"start":{"line":99,"column":8},"end":{"line":99,"column":48}},"17":{"start":{"line":100,"column":8},"end":{"line":100,"column":42}},"18":{"start":{"line":101,"column":8},"end":{"line":101,"column":76}},"19":{"start":{"line":103,"column":8},"end":{"line":103,"column":54}},"20":{"start":{"line":107,"column":8},"end":{"line":107,"column":53}},"21":{"start":{"line":108,"column":8},"end":{"line":108,"column":32}},"22":{"start":{"line":109,"column":8},"end":{"line":109,"column":56}},"23":{"start":{"line":110,"column":8},"end":{"line":110,"column":3445}},"24":{"start":{"line":111,"column":12},"end":{"line":111,"column":43}},"25":{"start":{"line":113,"column":8},"end":{"line":113,"column":3583}},"26":{"start":{"line":114,"column":12},"end":{"line":114,"column":65}},"27":{"start":{"line":117,"column":8},"end":{"line":117,"column":47}},"28":{"start":{"line":118,"column":8},"end":{"line":118,"column":41}},"29":{"start":{"line":119,"column":8},"end":{"line":119,"column":74}},"30":{"start":{"line":121,"column":8},"end":{"line":121,"column":53}},"31":{"start":{"line":127,"column":8},"end":{"line":127,"column":35}},"32":{"start":{"line":128,"column":8},"end":{"line":128,"column":66}},"33":{"start":{"line":131,"column":8},"end":{"line":131,"column":54}},"34":{"start":{"line":132,"column":8},"end":{"line":132,"column":93}},"35":{"start":{"line":133,"column":8},"end":{"line":133,"column":4412}},"36":{"start":{"line":139,"column":8},"end":{"line":139,"column":57}},"37":{"start":{"line":140,"column":8},"end":{"line":140,"column":71}},"38":{"start":{"line":143,"column":8},"end":{"line":143,"column":76}},"39":{"start":{"line":144,"column":8},"end":{"line":144,"column":62}},"40":{"start":{"line":145,"column":8},"end":{"line":145,"column":54}},"41":{"start":{"line":146,"column":8},"end":{"line":146,"column":33}},"42":{"start":{"line":148,"column":8},"end":{"line":148,"column":68}},"43":{"start":{"line":149,"column":8},"end":{"line":149,"column":52}},"44":{"start":{"line":151,"column":8},"end":{"line":151,"column":34}},"45":{"start":{"line":155,"column":8},"end":{"line":155,"column":34}},"46":{"start":{"line":156,"column":8},"end":{"line":156,"column":65}},"47":{"start":{"line":159,"column":8},"end":{"line":159,"column":53}},"48":{"start":{"line":160,"column":8},"end":{"line":160,"column":90}},"49":{"start":{"line":161,"column":8},"end":{"line":161,"column":5560}},"50":{"start":{"line":167,"column":8},"end":{"line":167,"column":56}},"51":{"start":{"line":168,"column":8},"end":{"line":168,"column":71}},"52":{"start":{"line":171,"column":8},"end":{"line":171,"column":74}},"53":{"start":{"line":172,"column":8},"end":{"line":172,"column":60}},"54":{"start":{"line":173,"column":8},"end":{"line":173,"column":53}},"55":{"start":{"line":174,"column":8},"end":{"line":174,"column":32}},"56":{"start":{"line":176,"column":8},"end":{"line":176,"column":67}},"57":{"start":{"line":177,"column":8},"end":{"line":177,"column":51}},"58":{"start":{"line":179,"column":8},"end":{"line":179,"column":34}},"59":{"start":{"line":185,"column":8},"end":{"line":185,"column":35}},"60":{"start":{"line":186,"column":8},"end":{"line":186,"column":62}},"61":{"start":{"line":187,"column":8},"end":{"line":187,"column":74}},"62":{"start":{"line":190,"column":8},"end":{"line":190,"column":65}},"63":{"start":{"line":191,"column":8},"end":{"line":191,"column":79}},"64":{"start":{"line":194,"column":8},"end":{"line":194,"column":84}},"65":{"start":{"line":195,"column":8},"end":{"line":195,"column":79}},"66":{"start":{"line":196,"column":8},"end":{"line":196,"column":62}},"67":{"start":{"line":197,"column":8},"end":{"line":197,"column":33}},"68":{"start":{"line":199,"column":8},"end":{"line":199,"column":63}},"69":{"start":{"line":200,"column":8},"end":{"line":200,"column":52}},"70":{"start":{"line":202,"column":8},"end":{"line":202,"column":42}},"71":{"start":{"line":206,"column":8},"end":{"line":206,"column":34}},"72":{"start":{"line":207,"column":8},"end":{"line":207,"column":61}},"73":{"start":{"line":208,"column":8},"end":{"line":208,"column":73}},"74":{"start":{"line":211,"column":8},"end":{"line":211,"column":64}},"75":{"start":{"line":212,"column":8},"end":{"line":212,"column":79}},"76":{"start":{"line":215,"column":8},"end":{"line":215,"column":82}},"77":{"start":{"line":216,"column":8},"end":{"line":216,"column":77}},"78":{"start":{"line":217,"column":8},"end":{"line":217,"column":61}},"79":{"start":{"line":218,"column":8},"end":{"line":218,"column":32}},"80":{"start":{"line":220,"column":8},"end":{"line":220,"column":62}},"81":{"start":{"line":221,"column":8},"end":{"line":221,"column":51}},"82":{"start":{"line":223,"column":8},"end":{"line":223,"column":42}},"83":{"start":{"line":229,"column":8},"end":{"line":229,"column":60}},"84":{"start":{"line":233,"column":8},"end":{"line":233,"column":61}},"85":{"start":{"line":237,"column":8},"end":{"line":237,"column":60}},"86":{"start":{"line":241,"column":8},"end":{"line":241,"column":61}},"87":{"start":{"line":247,"column":8},"end":{"line":247,"column":56}},"88":{"start":{"line":248,"column":8},"end":{"line":248,"column":53}},"89":{"start":{"line":249,"column":8},"end":{"line":249,"column":9114}},"90":{"start":{"line":250,"column":12},"end":{"line":250,"column":20}},"91":{"start":{"line":252,"column":8},"end":{"line":252,"column":84}},"92":{"start":{"line":253,"column":8},"end":{"line":253,"column":24}},"93":{"start":{"line":257,"column":8},"end":{"line":257,"column":58}},"94":{"start":{"line":258,"column":8},"end":{"line":258,"column":54}},"95":{"start":{"line":259,"column":8},"end":{"line":259,"column":9504}},"96":{"start":{"line":260,"column":12},"end":{"line":260,"column":20}},"97":{"start":{"line":262,"column":8},"end":{"line":262,"column":87}},"98":{"start":{"line":263,"column":8},"end":{"line":263,"column":24}},"99":{"start":{"line":267,"column":8},"end":{"line":267,"column":9790}},"100":{"start":{"line":268,"column":12},"end":{"line":268,"column":77}},"101":{"start":{"line":269,"column":12},"end":{"line":269,"column":78}},"102":{"start":{"line":270,"column":12},"end":{"line":270,"column":44}},"103":{"start":{"line":271,"column":12},"end":{"line":271,"column":66}},"104":{"start":{"line":272,"column":12},"end":{"line":272,"column":10126}},"105":{"start":{"line":277,"column":12},"end":{"line":277,"column":10299}},"106":{"start":{"line":282,"column":12},"end":{"line":282,"column":71}},"107":{"start":{"line":284,"column":12},"end":{"line":284,"column":20}},"108":{"start":{"line":289,"column":8},"end":{"line":289,"column":10708}},"109":{"start":{"line":290,"column":12},"end":{"line":290,"column":75}},"110":{"start":{"line":291,"column":12},"end":{"line":291,"column":81}},"111":{"start":{"line":292,"column":12},"end":{"line":292,"column":44}},"112":{"start":{"line":293,"column":12},"end":{"line":293,"column":72}},"113":{"start":{"line":294,"column":12},"end":{"line":294,"column":11051}},"114":{"start":{"line":299,"column":12},"end":{"line":299,"column":11222}},"115":{"start":{"line":304,"column":12},"end":{"line":304,"column":69}},"116":{"start":{"line":306,"column":12},"end":{"line":306,"column":20}}},"branchMap":{"1":{"line":47,"type":"if","locations":[{"start":{"line":47,"column":8},"end":{"line":47,"column":8}},{"start":{"line":47,"column":8},"end":{"line":47,"column":8}}]},"2":{"line":52,"type":"if","locations":[{"start":{"line":52,"column":8},"end":{"line":52,"column":8}},{"start":{"line":52,"column":8},"end":{"line":52,"column":8}}]},"3":{"line":92,"type":"if","locations":[{"start":{"line":92,"column":8},"end":{"line":92,"column":8}},{"start":{"line":92,"column":8},"end":{"line":92,"column":8}}]},"4":{"line":95,"type":"if","locations":[{"start":{"line":95,"column":8},"end":{"line":95,"column":8}},{"start":{"line":95,"column":8},"end":{"line":95,"column":8}}]},"5":{"line":110,"type":"if","locations":[{"start":{"line":110,"column":8},"end":{"line":110,"column":8}},{"start":{"line":110,"column":8},"end":{"line":110,"column":8}}]},"6":{"line":113,"type":"if","locations":[{"start":{"line":113,"column":8},"end":{"line":113,"column":8}},{"start":{"line":113,"column":8},"end":{"line":113,"column":8}}]},"7":{"line":128,"type":"if","locations":[{"start":{"line":128,"column":8},"end":{"line":128,"column":8}},{"start":{"line":128,"column":8},"end":{"line":128,"column":8}}]},"8":{"line":133,"type":"if","locations":[{"start":{"line":133,"column":8},"end":{"line":133,"column":8}},{"start":{"line":133,"column":8},"end":{"line":133,"column":8}}]},"9":{"line":140,"type":"if","locations":[{"start":{"line":140,"column":8},"end":{"line":140,"column":8}},{"start":{"line":140,"column":8},"end":{"line":140,"column":8}}]},"10":{"line":156,"type":"if","locations":[{"start":{"line":156,"column":8},"end":{"line":156,"column":8}},{"start":{"line":156,"column":8},"end":{"line":156,"column":8}}]},"11":{"line":161,"type":"if","locations":[{"start":{"line":161,"column":8},"end":{"line":161,"column":8}},{"start":{"line":161,"column":8},"end":{"line":161,"column":8}}]},"12":{"line":168,"type":"if","locations":[{"start":{"line":168,"column":8},"end":{"line":168,"column":8}},{"start":{"line":168,"column":8},"end":{"line":168,"column":8}}]},"13":{"line":187,"type":"if","locations":[{"start":{"line":187,"column":8},"end":{"line":187,"column":8}},{"start":{"line":187,"column":8},"end":{"line":187,"column":8}}]},"14":{"line":191,"type":"if","locations":[{"start":{"line":191,"column":8},"end":{"line":191,"column":8}},{"start":{"line":191,"column":8},"end":{"line":191,"column":8}}]},"15":{"line":208,"type":"if","locations":[{"start":{"line":208,"column":8},"end":{"line":208,"column":8}},{"start":{"line":208,"column":8},"end":{"line":208,"column":8}}]},"16":{"line":212,"type":"if","locations":[{"start":{"line":212,"column":8},"end":{"line":212,"column":8}},{"start":{"line":212,"column":8},"end":{"line":212,"column":8}}]},"17":{"line":249,"type":"if","locations":[{"start":{"line":249,"column":8},"end":{"line":249,"column":8}},{"start":{"line":249,"column":8},"end":{"line":249,"column":8}}]},"18":{"line":259,"type":"if","locations":[{"start":{"line":259,"column":8},"end":{"line":259,"column":8}},{"start":{"line":259,"column":8},"end":{"line":259,"column":8}}]},"19":{"line":267,"type":"if","locations":[{"start":{"line":267,"column":8},"end":{"line":267,"column":8}},{"start":{"line":267,"column":8},"end":{"line":267,"column":8}}]},"20":{"line":268,"type":"if","locations":[{"start":{"line":268,"column":12},"end":{"line":268,"column":12}},{"start":{"line":268,"column":12},"end":{"line":268,"column":12}}]},"21":{"line":289,"type":"if","locations":[{"start":{"line":289,"column":8},"end":{"line":289,"column":8}},{"start":{"line":289,"column":8},"end":{"line":289,"column":8}}]},"22":{"line":290,"type":"if","locations":[{"start":{"line":290,"column":12},"end":{"line":290,"column":12}},{"start":{"line":290,"column":12},"end":{"line":290,"column":12}}]}}},"contracts/impl/Pricing.sol":{"l":{"34":25,"35":25,"44":25,"52":35,"53":33,"54":33,"55":33,"65":1,"66":1,"73":1,"84":2,"85":2,"92":2,"101":34,"102":34,"103":34,"104":34,"109":34,"119":7,"120":6,"121":6,"132":5,"133":5,"142":51,"143":51,"144":51,"145":51,"150":51,"156":246,"157":246,"158":246,"159":161,"161":34,"162":34,"164":51,"165":51,"174":44,"175":44},"path":"/Users/leimingda/Documents/dodo/contracts/impl/Pricing.sol","s":{"1":25,"2":25,"3":25,"4":35,"5":33,"6":33,"7":33,"8":1,"9":1,"10":1,"11":2,"12":2,"13":2,"14":34,"15":34,"16":34,"17":34,"18":34,"19":7,"20":6,"21":6,"22":5,"23":5,"24":51,"25":51,"26":51,"27":51,"28":51,"29":246,"30":246,"31":246,"32":161,"33":85,"34":34,"35":34,"36":51,"37":51,"38":51,"39":44,"40":44},"b":{"1":[33,2],"2":[6,1],"3":[161,85],"4":[34,51],"5":[51,0]},"f":{"1":25,"2":35,"3":1,"4":2,"5":34,"6":7,"7":5,"8":51,"9":246,"10":44},"fnMap":{"1":{"name":"_ROneSellBaseToken","line":29,"loc":{"start":{"line":29,"column":4},"end":{"line":45,"column":4}}},"2":{"name":"_ROneBuyBaseToken","line":47,"loc":{"start":{"line":47,"column":4},"end":{"line":56,"column":4}}},"3":{"name":"_RBelowSellBaseToken","line":60,"loc":{"start":{"line":60,"column":4},"end":{"line":74,"column":4}}},"4":{"name":"_RBelowBuylBaseToken","line":76,"loc":{"start":{"line":76,"column":4},"end":{"line":93,"column":4}}},"5":{"name":"_RBelowBackToOne","line":95,"loc":{"start":{"line":95,"column":4},"end":{"line":110,"column":4}}},"6":{"name":"_RAboveBuyBaseToken","line":114,"loc":{"start":{"line":114,"column":4},"end":{"line":122,"column":4}}},"7":{"name":"_RAboveSellBaseToken","line":124,"loc":{"start":{"line":124,"column":4},"end":{"line":134,"column":4}}},"8":{"name":"_RAboveBackToOne","line":136,"loc":{"start":{"line":136,"column":4},"end":{"line":151,"column":4}}},"9":{"name":"_getExpectedTarget","line":155,"loc":{"start":{"line":155,"column":4},"end":{"line":167,"column":4}}},"10":{"name":"_RAboveIntegrate","line":169,"loc":{"start":{"line":169,"column":4},"end":{"line":176,"column":4}}}},"statementMap":{"1":{"start":{"line":34,"column":8},"end":{"line":34,"column":36}},"2":{"start":{"line":35,"column":8},"end":{"line":35,"column":783}},"3":{"start":{"line":44,"column":8},"end":{"line":44,"column":45}},"4":{"start":{"line":52,"column":8},"end":{"line":52,"column":84}},"5":{"start":{"line":53,"column":8},"end":{"line":53,"column":54}},"6":{"start":{"line":54,"column":8},"end":{"line":54,"column":89}},"7":{"start":{"line":55,"column":8},"end":{"line":55,"column":28}},"8":{"start":{"line":65,"column":8},"end":{"line":65,"column":36}},"9":{"start":{"line":66,"column":8},"end":{"line":66,"column":1874}},"10":{"start":{"line":73,"column":8},"end":{"line":73,"column":40}},"11":{"start":{"line":84,"column":8},"end":{"line":84,"column":36}},"12":{"start":{"line":85,"column":8},"end":{"line":85,"column":2496}},"13":{"start":{"line":92,"column":8},"end":{"line":92,"column":35}},"14":{"start":{"line":101,"column":8},"end":{"line":101,"column":74}},"15":{"start":{"line":102,"column":8},"end":{"line":102,"column":40}},"16":{"start":{"line":103,"column":8},"end":{"line":103,"column":62}},"17":{"start":{"line":104,"column":8},"end":{"line":104,"column":3168}},"18":{"start":{"line":109,"column":8},"end":{"line":109,"column":63}},"19":{"start":{"line":119,"column":8},"end":{"line":119,"column":74}},"20":{"start":{"line":120,"column":8},"end":{"line":120,"column":44}},"21":{"start":{"line":121,"column":8},"end":{"line":121,"column":66}},"22":{"start":{"line":132,"column":8},"end":{"line":132,"column":44}},"23":{"start":{"line":133,"column":8},"end":{"line":133,"column":66}},"24":{"start":{"line":142,"column":8},"end":{"line":142,"column":77}},"25":{"start":{"line":143,"column":8},"end":{"line":143,"column":40}},"26":{"start":{"line":144,"column":8},"end":{"line":144,"column":68}},"27":{"start":{"line":145,"column":8},"end":{"line":145,"column":4694}},"28":{"start":{"line":150,"column":8},"end":{"line":150,"column":62}},"29":{"start":{"line":156,"column":8},"end":{"line":156,"column":35}},"30":{"start":{"line":157,"column":8},"end":{"line":157,"column":34}},"31":{"start":{"line":158,"column":8},"end":{"line":158,"column":5142}},"32":{"start":{"line":159,"column":12},"end":{"line":159,"column":76}},"33":{"start":{"line":160,"column":15},"end":{"line":160,"column":5274}},"34":{"start":{"line":161,"column":12},"end":{"line":161,"column":82}},"35":{"start":{"line":162,"column":12},"end":{"line":162,"column":66}},"36":{"start":{"line":163,"column":15},"end":{"line":163,"column":5486}},"37":{"start":{"line":164,"column":12},"end":{"line":164,"column":82}},"38":{"start":{"line":165,"column":12},"end":{"line":165,"column":66}},"39":{"start":{"line":174,"column":8},"end":{"line":174,"column":36}},"40":{"start":{"line":175,"column":8},"end":{"line":175,"column":61}}},"branchMap":{"1":{"line":52,"type":"if","locations":[{"start":{"line":52,"column":8},"end":{"line":52,"column":8}},{"start":{"line":52,"column":8},"end":{"line":52,"column":8}}]},"2":{"line":119,"type":"if","locations":[{"start":{"line":119,"column":8},"end":{"line":119,"column":8}},{"start":{"line":119,"column":8},"end":{"line":119,"column":8}}]},"3":{"line":158,"type":"if","locations":[{"start":{"line":158,"column":8},"end":{"line":158,"column":8}},{"start":{"line":158,"column":8},"end":{"line":158,"column":8}}]},"4":{"line":160,"type":"if","locations":[{"start":{"line":160,"column":15},"end":{"line":160,"column":15}},{"start":{"line":160,"column":15},"end":{"line":160,"column":15}}]},"5":{"line":163,"type":"if","locations":[{"start":{"line":163,"column":15},"end":{"line":163,"column":15}},{"start":{"line":163,"column":15},"end":{"line":163,"column":15}}]}}},"contracts/impl/Settlement.sol":{"l":{"40":74,"41":74,"45":80,"46":80,"50":102,"51":102,"55":79,"56":79,"62":57,"63":57,"67":45,"68":45,"72":1,"73":1,"77":1,"78":1,"85":4,"86":4,"87":4,"88":4,"89":4,"90":4,"92":4,"93":1,"95":3,"96":2,"97":2,"98":2,"100":1,"101":1,"102":1,"104":3,"109":6,"110":5,"111":4,"112":4,"116":4,"120":4,"121":4,"122":4,"123":4,"128":4,"129":2,"134":3,"135":2,"140":2},"path":"/Users/leimingda/Documents/dodo/contracts/impl/Settlement.sol","s":{"1":74,"2":74,"3":80,"4":80,"5":102,"6":102,"7":79,"8":79,"9":57,"10":57,"11":45,"12":45,"13":1,"14":1,"15":1,"16":1,"17":4,"18":4,"19":4,"20":4,"21":4,"22":4,"23":4,"24":1,"25":3,"26":2,"27":2,"28":2,"29":1,"30":1,"31":1,"32":3,"33":6,"34":5,"35":4,"36":4,"37":4,"38":4,"39":4,"40":4,"41":4,"42":4,"43":2,"44":3,"45":2,"46":2},"b":{"1":[1,3],"2":[2,1],"3":[5,1],"4":[4,1],"5":[2,2],"6":[1,1],"7":[2,1],"8":[1,1]},"f":{"1":74,"2":80,"3":102,"4":79,"5":57,"6":45,"7":1,"8":1,"9":4,"10":6,"11":4},"fnMap":{"1":{"name":"_baseTokenTransferIn","line":39,"loc":{"start":{"line":39,"column":4},"end":{"line":42,"column":4}}},"2":{"name":"_quoteTokenTransferIn","line":44,"loc":{"start":{"line":44,"column":4},"end":{"line":47,"column":4}}},"3":{"name":"_baseTokenTransferOut","line":49,"loc":{"start":{"line":49,"column":4},"end":{"line":52,"column":4}}},"4":{"name":"_quoteTokenTransferOut","line":54,"loc":{"start":{"line":54,"column":4},"end":{"line":57,"column":4}}},"5":{"name":"_donateBaseToken","line":61,"loc":{"start":{"line":61,"column":4},"end":{"line":64,"column":4}}},"6":{"name":"_donateQuoteToken","line":66,"loc":{"start":{"line":66,"column":4},"end":{"line":69,"column":4}}},"7":{"name":"donateBaseToken","line":71,"loc":{"start":{"line":71,"column":4},"end":{"line":74,"column":4}}},"8":{"name":"donateQuoteToken","line":76,"loc":{"start":{"line":76,"column":4},"end":{"line":79,"column":4}}},"9":{"name":"finalSettlement","line":84,"loc":{"start":{"line":84,"column":4},"end":{"line":105,"column":4}}},"10":{"name":"claim","line":108,"loc":{"start":{"line":108,"column":4},"end":{"line":124,"column":4}}},"11":{"name":"retrieve","line":127,"loc":{"start":{"line":127,"column":4},"end":{"line":141,"column":4}}}},"statementMap":{"1":{"start":{"line":40,"column":8},"end":{"line":40,"column":73}},"2":{"start":{"line":41,"column":8},"end":{"line":41,"column":50}},"3":{"start":{"line":45,"column":8},"end":{"line":45,"column":74}},"4":{"start":{"line":46,"column":8},"end":{"line":46,"column":52}},"5":{"start":{"line":50,"column":8},"end":{"line":50,"column":52}},"6":{"start":{"line":51,"column":8},"end":{"line":51,"column":50}},"7":{"start":{"line":55,"column":8},"end":{"line":55,"column":53}},"8":{"start":{"line":56,"column":8},"end":{"line":56,"column":52}},"9":{"start":{"line":62,"column":8},"end":{"line":62,"column":74}},"10":{"start":{"line":63,"column":8},"end":{"line":63,"column":36}},"11":{"start":{"line":67,"column":8},"end":{"line":67,"column":76}},"12":{"start":{"line":68,"column":8},"end":{"line":68,"column":37}},"13":{"start":{"line":72,"column":8},"end":{"line":72,"column":47}},"14":{"start":{"line":73,"column":8},"end":{"line":73,"column":31}},"15":{"start":{"line":77,"column":8},"end":{"line":77,"column":48}},"16":{"start":{"line":78,"column":8},"end":{"line":78,"column":32}},"17":{"start":{"line":85,"column":8},"end":{"line":85,"column":22}},"18":{"start":{"line":86,"column":8},"end":{"line":86,"column":38}},"19":{"start":{"line":87,"column":8},"end":{"line":87,"column":37}},"20":{"start":{"line":88,"column":8},"end":{"line":88,"column":30}},"21":{"start":{"line":89,"column":8},"end":{"line":89,"column":56}},"22":{"start":{"line":90,"column":8},"end":{"line":90,"column":58}},"23":{"start":{"line":92,"column":8},"end":{"line":92,"column":2792}},"24":{"start":{"line":93,"column":12},"end":{"line":93,"column":18}},"25":{"start":{"line":95,"column":8},"end":{"line":95,"column":2869}},"26":{"start":{"line":96,"column":12},"end":{"line":96,"column":54}},"27":{"start":{"line":97,"column":12},"end":{"line":97,"column":81}},"28":{"start":{"line":98,"column":12},"end":{"line":98,"column":92}},"29":{"start":{"line":100,"column":12},"end":{"line":100,"column":56}},"30":{"start":{"line":101,"column":12},"end":{"line":101,"column":78}},"31":{"start":{"line":102,"column":12},"end":{"line":102,"column":92}},"32":{"start":{"line":104,"column":8},"end":{"line":104,"column":37}},"33":{"start":{"line":109,"column":8},"end":{"line":109,"column":43}},"34":{"start":{"line":110,"column":8},"end":{"line":110,"column":57}},"35":{"start":{"line":111,"column":8},"end":{"line":111,"column":35}},"36":{"start":{"line":112,"column":8},"end":{"line":112,"column":3695}},"37":{"start":{"line":116,"column":8},"end":{"line":116,"column":3843}},"38":{"start":{"line":120,"column":8},"end":{"line":120,"column":52}},"39":{"start":{"line":121,"column":8},"end":{"line":121,"column":54}},"40":{"start":{"line":122,"column":8},"end":{"line":122,"column":30}},"41":{"start":{"line":123,"column":8},"end":{"line":123,"column":14}},"42":{"start":{"line":128,"column":8},"end":{"line":128,"column":4284}},"43":{"start":{"line":129,"column":12},"end":{"line":129,"column":4329}},"44":{"start":{"line":134,"column":8},"end":{"line":134,"column":4507}},"45":{"start":{"line":135,"column":12},"end":{"line":135,"column":4553}},"46":{"start":{"line":140,"column":8},"end":{"line":140,"column":53}}},"branchMap":{"1":{"line":92,"type":"if","locations":[{"start":{"line":92,"column":8},"end":{"line":92,"column":8}},{"start":{"line":92,"column":8},"end":{"line":92,"column":8}}]},"2":{"line":95,"type":"if","locations":[{"start":{"line":95,"column":8},"end":{"line":95,"column":8}},{"start":{"line":95,"column":8},"end":{"line":95,"column":8}}]},"3":{"line":109,"type":"if","locations":[{"start":{"line":109,"column":8},"end":{"line":109,"column":8}},{"start":{"line":109,"column":8},"end":{"line":109,"column":8}}]},"4":{"line":110,"type":"if","locations":[{"start":{"line":110,"column":8},"end":{"line":110,"column":8}},{"start":{"line":110,"column":8},"end":{"line":110,"column":8}}]},"5":{"line":128,"type":"if","locations":[{"start":{"line":128,"column":8},"end":{"line":128,"column":8}},{"start":{"line":128,"column":8},"end":{"line":128,"column":8}}]},"6":{"line":129,"type":"if","locations":[{"start":{"line":129,"column":12},"end":{"line":129,"column":12}},{"start":{"line":129,"column":12},"end":{"line":129,"column":12}}]},"7":{"line":134,"type":"if","locations":[{"start":{"line":134,"column":8},"end":{"line":134,"column":8}},{"start":{"line":134,"column":8},"end":{"line":134,"column":8}}]},"8":{"line":135,"type":"if","locations":[{"start":{"line":135,"column":12},"end":{"line":135,"column":12}},{"start":{"line":135,"column":12},"end":{"line":135,"column":12}}]}}},"contracts/impl/Storage.sol":{"l":{"71":8,"72":4,"76":11,"77":7,"83":17,"84":16,"85":15,"89":171,"93":58,"97":91,"101":57,"105":83},"path":"/Users/leimingda/Documents/dodo/contracts/impl/Storage.sol","s":{"1":8,"2":11,"3":17,"4":16,"5":15,"6":171,"7":58,"8":91,"9":57,"10":83},"b":{"1":[4,4],"2":[7,4],"3":[16,1],"4":[15,1],"5":[13,2]},"f":{"1":8,"2":11,"3":17,"4":171,"5":58,"6":91,"7":57,"8":83},"fnMap":{"1":{"name":"onlySupervisorOrOwner","line":70,"loc":{"start":{"line":70,"column":4},"end":{"line":73,"column":4}}},"2":{"name":"notClosed","line":75,"loc":{"start":{"line":75,"column":4},"end":{"line":78,"column":4}}},"3":{"name":"_checkDODOParameters","line":82,"loc":{"start":{"line":82,"column":4},"end":{"line":86,"column":4}}},"4":{"name":"getOraclePrice","line":88,"loc":{"start":{"line":88,"column":4},"end":{"line":90,"column":4}}},"5":{"name":"getBaseCapitalBalanceOf","line":92,"loc":{"start":{"line":92,"column":4},"end":{"line":94,"column":4}}},"6":{"name":"getTotalBaseCapital","line":96,"loc":{"start":{"line":96,"column":4},"end":{"line":98,"column":4}}},"7":{"name":"getQuoteCapitalBalanceOf","line":100,"loc":{"start":{"line":100,"column":4},"end":{"line":102,"column":4}}},"8":{"name":"getTotalQuoteCapital","line":104,"loc":{"start":{"line":104,"column":4},"end":{"line":106,"column":4}}}},"statementMap":{"1":{"start":{"line":71,"column":8},"end":{"line":71,"column":94}},"2":{"start":{"line":76,"column":8},"end":{"line":76,"column":43}},"3":{"start":{"line":83,"column":8},"end":{"line":83,"column":64}},"4":{"start":{"line":84,"column":8},"end":{"line":84,"column":54}},"5":{"start":{"line":85,"column":8},"end":{"line":85,"column":95}},"6":{"start":{"line":89,"column":8},"end":{"line":89,"column":43}},"7":{"start":{"line":93,"column":8},"end":{"line":93,"column":63}},"8":{"start":{"line":97,"column":8},"end":{"line":97,"column":63}},"9":{"start":{"line":101,"column":8},"end":{"line":101,"column":64}},"10":{"start":{"line":105,"column":8},"end":{"line":105,"column":64}}},"branchMap":{"1":{"line":71,"type":"if","locations":[{"start":{"line":71,"column":8},"end":{"line":71,"column":8}},{"start":{"line":71,"column":8},"end":{"line":71,"column":8}}]},"2":{"line":76,"type":"if","locations":[{"start":{"line":76,"column":8},"end":{"line":76,"column":8}},{"start":{"line":76,"column":8},"end":{"line":76,"column":8}}]},"3":{"line":83,"type":"if","locations":[{"start":{"line":83,"column":8},"end":{"line":83,"column":8}},{"start":{"line":83,"column":8},"end":{"line":83,"column":8}}]},"4":{"line":84,"type":"if","locations":[{"start":{"line":84,"column":8},"end":{"line":84,"column":8}},{"start":{"line":84,"column":8},"end":{"line":84,"column":8}}]},"5":{"line":85,"type":"if","locations":[{"start":{"line":85,"column":8},"end":{"line":85,"column":8}},{"start":{"line":85,"column":8},"end":{"line":85,"column":8}}]}}},"contracts/impl/Trader.sol":{"l":{"39":81,"40":80,"44":80,"45":78,"58":32,"66":32,"69":31,"70":31,"71":31,"74":31,"75":31,"76":31,"78":31,"79":31,"80":31,"82":31,"93":46,"101":43,"104":42,"105":42,"106":42,"109":42,"110":42,"111":42,"113":42,"114":42,"115":42,"117":42,"123":1,"124":1,"128":1,"129":1,"144":33,"146":33,"148":33,"151":21,"152":21,"154":11,"155":11,"158":11,"160":5,"161":5,"162":5,"165":0,"169":2,"170":2,"173":4,"176":4,"181":1,"182":1,"186":33,"187":33,"188":33,"190":33,"205":47,"208":47,"209":47,"210":47,"212":47,"214":32,"215":30,"218":7,"219":6,"221":8,"222":8,"225":8,"227":2,"228":2,"231":3,"232":3,"235":3,"238":3,"242":44},"path":"/Users/leimingda/Documents/dodo/contracts/impl/Trader.sol","s":{"1":81,"2":80,"3":32,"4":32,"5":31,"6":31,"7":31,"8":31,"9":31,"10":31,"11":31,"12":31,"13":31,"14":31,"15":46,"16":43,"17":42,"18":42,"19":42,"20":42,"21":42,"22":42,"23":42,"24":42,"25":42,"26":42,"27":1,"28":1,"29":1,"30":1,"31":33,"32":33,"33":33,"34":21,"35":21,"36":12,"37":11,"38":11,"39":11,"40":5,"41":5,"42":5,"43":0,"44":6,"45":2,"46":2,"47":4,"48":4,"49":1,"50":1,"51":33,"52":33,"53":33,"54":33,"55":47,"56":47,"57":47,"58":47,"59":47,"60":32,"61":30,"62":15,"63":7,"64":6,"65":8,"66":8,"67":8,"68":8,"69":2,"70":2,"71":6,"72":3,"73":3,"74":3,"75":3,"76":44},"b":{"1":[80,1],"2":[78,2],"3":[31,1],"4":[42,1],"5":[21,12],"6":[11,1],"7":[5,6],"8":[0,5],"9":[2,4],"10":[32,15],"11":[7,8],"12":[8,0],"13":[2,6],"14":[3,3]},"f":{"1":81,"2":80,"3":32,"4":46,"5":1,"6":1,"7":33,"8":47},"fnMap":{"1":{"name":"tradeAllowed","line":38,"loc":{"start":{"line":38,"column":4},"end":{"line":41,"column":4}}},"2":{"name":"gasPriceLimit","line":43,"loc":{"start":{"line":43,"column":4},"end":{"line":46,"column":4}}},"3":{"name":"sellBaseToken","line":54,"loc":{"start":{"line":50,"column":4},"end":{"line":83,"column":4}}},"4":{"name":"buyBaseToken","line":89,"loc":{"start":{"line":85,"column":4},"end":{"line":118,"column":4}}},"5":{"name":"querySellBaseToken","line":122,"loc":{"start":{"line":122,"column":4},"end":{"line":125,"column":4}}},"6":{"name":"queryBuyBaseToken","line":127,"loc":{"start":{"line":127,"column":4},"end":{"line":130,"column":4}}},"7":{"name":"_querySellBaseToken","line":132,"loc":{"start":{"line":132,"column":4},"end":{"line":191,"column":4}}},"8":{"name":"_queryBuyBaseToken","line":193,"loc":{"start":{"line":193,"column":4},"end":{"line":243,"column":4}}}},"statementMap":{"1":{"start":{"line":39,"column":8},"end":{"line":39,"column":52}},"2":{"start":{"line":44,"column":8},"end":{"line":44,"column":68}},"3":{"start":{"line":58,"column":8},"end":{"line":58,"column":1427}},"4":{"start":{"line":66,"column":8},"end":{"line":66,"column":79}},"5":{"start":{"line":69,"column":8},"end":{"line":69,"column":47}},"6":{"start":{"line":70,"column":8},"end":{"line":70,"column":55}},"7":{"start":{"line":71,"column":8},"end":{"line":71,"column":55}},"8":{"start":{"line":74,"column":8},"end":{"line":74,"column":51}},"9":{"start":{"line":75,"column":8},"end":{"line":75,"column":49}},"10":{"start":{"line":76,"column":8},"end":{"line":76,"column":30}},"11":{"start":{"line":78,"column":8},"end":{"line":78,"column":36}},"12":{"start":{"line":79,"column":8},"end":{"line":79,"column":60}},"13":{"start":{"line":80,"column":8},"end":{"line":80,"column":45}},"14":{"start":{"line":82,"column":8},"end":{"line":82,"column":27}},"15":{"start":{"line":93,"column":8},"end":{"line":93,"column":2511}},"16":{"start":{"line":101,"column":8},"end":{"line":101,"column":65}},"17":{"start":{"line":104,"column":8},"end":{"line":104,"column":50}},"18":{"start":{"line":105,"column":8},"end":{"line":105,"column":48}},"19":{"start":{"line":106,"column":8},"end":{"line":106,"column":53}},"20":{"start":{"line":109,"column":8},"end":{"line":109,"column":51}},"21":{"start":{"line":110,"column":8},"end":{"line":110,"column":49}},"22":{"start":{"line":111,"column":8},"end":{"line":111,"column":30}},"23":{"start":{"line":113,"column":8},"end":{"line":113,"column":34}},"24":{"start":{"line":114,"column":8},"end":{"line":114,"column":55}},"25":{"start":{"line":115,"column":8},"end":{"line":115,"column":43}},"26":{"start":{"line":117,"column":8},"end":{"line":117,"column":23}},"27":{"start":{"line":123,"column":8},"end":{"line":123,"column":61}},"28":{"start":{"line":124,"column":8},"end":{"line":124,"column":27}},"29":{"start":{"line":128,"column":8},"end":{"line":128,"column":56}},"30":{"start":{"line":129,"column":8},"end":{"line":129,"column":23}},"31":{"start":{"line":144,"column":8},"end":{"line":144,"column":61}},"32":{"start":{"line":146,"column":8},"end":{"line":146,"column":39}},"33":{"start":{"line":148,"column":8},"end":{"line":148,"column":4175}},"34":{"start":{"line":151,"column":12},"end":{"line":151,"column":76}},"35":{"start":{"line":152,"column":12},"end":{"line":152,"column":47}},"36":{"start":{"line":153,"column":15},"end":{"line":153,"column":4418}},"37":{"start":{"line":154,"column":12},"end":{"line":154,"column":72}},"38":{"start":{"line":155,"column":12},"end":{"line":155,"column":79}},"39":{"start":{"line":158,"column":12},"end":{"line":158,"column":4725}},"40":{"start":{"line":160,"column":16},"end":{"line":160,"column":97}},"41":{"start":{"line":161,"column":16},"end":{"line":161,"column":51}},"42":{"start":{"line":162,"column":16},"end":{"line":162,"column":4992}},"43":{"start":{"line":165,"column":20},"end":{"line":165,"column":55}},"44":{"start":{"line":167,"column":19},"end":{"line":167,"column":5394}},"45":{"start":{"line":169,"column":16},"end":{"line":169,"column":51}},"46":{"start":{"line":170,"column":16},"end":{"line":170,"column":45}},"47":{"start":{"line":173,"column":16},"end":{"line":173,"column":5691}},"48":{"start":{"line":176,"column":16},"end":{"line":176,"column":51}},"49":{"start":{"line":181,"column":12},"end":{"line":181,"column":94}},"50":{"start":{"line":182,"column":12},"end":{"line":182,"column":47}},"51":{"start":{"line":186,"column":8},"end":{"line":186,"column":64}},"52":{"start":{"line":187,"column":8},"end":{"line":187,"column":64}},"53":{"start":{"line":188,"column":8},"end":{"line":188,"column":66}},"54":{"start":{"line":190,"column":8},"end":{"line":190,"column":96}},"55":{"start":{"line":205,"column":8},"end":{"line":205,"column":61}},"56":{"start":{"line":208,"column":8},"end":{"line":208,"column":57}},"57":{"start":{"line":209,"column":8},"end":{"line":209,"column":57}},"58":{"start":{"line":210,"column":8},"end":{"line":210,"column":68}},"59":{"start":{"line":212,"column":8},"end":{"line":212,"column":7114}},"60":{"start":{"line":214,"column":12},"end":{"line":214,"column":69}},"61":{"start":{"line":215,"column":12},"end":{"line":215,"column":47}},"62":{"start":{"line":216,"column":15},"end":{"line":216,"column":7317}},"63":{"start":{"line":218,"column":12},"end":{"line":218,"column":87}},"64":{"start":{"line":219,"column":12},"end":{"line":219,"column":47}},"65":{"start":{"line":220,"column":15},"end":{"line":220,"column":7544}},"66":{"start":{"line":221,"column":12},"end":{"line":221,"column":75}},"67":{"start":{"line":222,"column":12},"end":{"line":222,"column":76}},"68":{"start":{"line":225,"column":12},"end":{"line":225,"column":7836}},"69":{"start":{"line":227,"column":16},"end":{"line":227,"column":94}},"70":{"start":{"line":228,"column":16},"end":{"line":228,"column":51}},"71":{"start":{"line":229,"column":19},"end":{"line":229,"column":8102}},"72":{"start":{"line":231,"column":16},"end":{"line":231,"column":43}},"73":{"start":{"line":232,"column":16},"end":{"line":232,"column":45}},"74":{"start":{"line":235,"column":16},"end":{"line":235,"column":8394}},"75":{"start":{"line":238,"column":16},"end":{"line":238,"column":51}},"76":{"start":{"line":242,"column":8},"end":{"line":242,"column":90}}},"branchMap":{"1":{"line":39,"type":"if","locations":[{"start":{"line":39,"column":8},"end":{"line":39,"column":8}},{"start":{"line":39,"column":8},"end":{"line":39,"column":8}}]},"2":{"line":44,"type":"if","locations":[{"start":{"line":44,"column":8},"end":{"line":44,"column":8}},{"start":{"line":44,"column":8},"end":{"line":44,"column":8}}]},"3":{"line":66,"type":"if","locations":[{"start":{"line":66,"column":8},"end":{"line":66,"column":8}},{"start":{"line":66,"column":8},"end":{"line":66,"column":8}}]},"4":{"line":101,"type":"if","locations":[{"start":{"line":101,"column":8},"end":{"line":101,"column":8}},{"start":{"line":101,"column":8},"end":{"line":101,"column":8}}]},"5":{"line":148,"type":"if","locations":[{"start":{"line":148,"column":8},"end":{"line":148,"column":8}},{"start":{"line":148,"column":8},"end":{"line":148,"column":8}}]},"6":{"line":153,"type":"if","locations":[{"start":{"line":153,"column":15},"end":{"line":153,"column":15}},{"start":{"line":153,"column":15},"end":{"line":153,"column":15}}]},"7":{"line":158,"type":"if","locations":[{"start":{"line":158,"column":12},"end":{"line":158,"column":12}},{"start":{"line":158,"column":12},"end":{"line":158,"column":12}}]},"8":{"line":162,"type":"if","locations":[{"start":{"line":162,"column":16},"end":{"line":162,"column":16}},{"start":{"line":162,"column":16},"end":{"line":162,"column":16}}]},"9":{"line":167,"type":"if","locations":[{"start":{"line":167,"column":19},"end":{"line":167,"column":19}},{"start":{"line":167,"column":19},"end":{"line":167,"column":19}}]},"10":{"line":212,"type":"if","locations":[{"start":{"line":212,"column":8},"end":{"line":212,"column":8}},{"start":{"line":212,"column":8},"end":{"line":212,"column":8}}]},"11":{"line":216,"type":"if","locations":[{"start":{"line":216,"column":15},"end":{"line":216,"column":15}},{"start":{"line":216,"column":15},"end":{"line":216,"column":15}}]},"12":{"line":220,"type":"if","locations":[{"start":{"line":220,"column":15},"end":{"line":220,"column":15}},{"start":{"line":220,"column":15},"end":{"line":220,"column":15}}]},"13":{"line":225,"type":"if","locations":[{"start":{"line":225,"column":12},"end":{"line":225,"column":12}},{"start":{"line":225,"column":12},"end":{"line":225,"column":12}}]},"14":{"line":229,"type":"if","locations":[{"start":{"line":229,"column":19},"end":{"line":229,"column":19}},{"start":{"line":229,"column":19},"end":{"line":229,"column":19}}]}}},"contracts/lib/DODOMath.sol":{"l":{"38":44,"39":44,"40":44,"41":44,"42":44,"43":44,"69":28,"70":28,"71":28,"72":28,"73":2,"75":26,"77":28,"78":22,"79":22,"81":6,"82":6,"86":28,"90":28,"93":28,"94":28,"95":22,"97":6,"113":113,"114":113,"115":113,"117":113},"path":"/Users/leimingda/Documents/dodo/contracts/lib/DODOMath.sol","s":{"1":44,"2":44,"3":44,"4":44,"5":44,"6":44,"7":28,"8":28,"9":28,"10":28,"11":2,"12":26,"13":28,"14":22,"15":22,"16":6,"17":6,"18":28,"19":28,"20":28,"21":28,"22":22,"23":6,"24":113,"25":113,"26":113,"27":113},"b":{"1":[2,26],"2":[22,6],"3":[22,6]},"f":{"1":44,"2":28,"3":113},"fnMap":{"1":{"name":"_GeneralIntegrate","line":31,"loc":{"start":{"line":31,"column":4},"end":{"line":44,"column":4}}},"2":{"name":"_SolveQuadraticFunctionForTrade","line":60,"loc":{"start":{"line":60,"column":4},"end":{"line":99,"column":4}}},"3":{"name":"_SolveQuadraticFunctionForTarget","line":107,"loc":{"start":{"line":107,"column":4},"end":{"line":118,"column":4}}}},"statementMap":{"1":{"start":{"line":38,"column":8},"end":{"line":38,"column":34}},"2":{"start":{"line":39,"column":8},"end":{"line":39,"column":54}},"3":{"start":{"line":40,"column":8},"end":{"line":40,"column":50}},"4":{"start":{"line":41,"column":8},"end":{"line":41,"column":50}},"5":{"start":{"line":42,"column":8},"end":{"line":42,"column":73}},"6":{"start":{"line":43,"column":8},"end":{"line":43,"column":79}},"7":{"start":{"line":69,"column":8},"end":{"line":69,"column":63}},"8":{"start":{"line":70,"column":8},"end":{"line":70,"column":63}},"9":{"start":{"line":71,"column":8},"end":{"line":71,"column":29}},"10":{"start":{"line":72,"column":8},"end":{"line":72,"column":2179}},"11":{"start":{"line":73,"column":12},"end":{"line":73,"column":29}},"12":{"start":{"line":75,"column":12},"end":{"line":75,"column":39}},"13":{"start":{"line":77,"column":8},"end":{"line":77,"column":2350}},"14":{"start":{"line":78,"column":12},"end":{"line":78,"column":28}},"15":{"start":{"line":79,"column":12},"end":{"line":79,"column":27}},"16":{"start":{"line":81,"column":12},"end":{"line":81,"column":28}},"17":{"start":{"line":82,"column":12},"end":{"line":82,"column":28}},"18":{"start":{"line":86,"column":8},"end":{"line":86,"column":2555}},"19":{"start":{"line":90,"column":8},"end":{"line":90,"column":51}},"20":{"start":{"line":93,"column":8},"end":{"line":93,"column":59}},"21":{"start":{"line":94,"column":8},"end":{"line":94,"column":2885}},"22":{"start":{"line":95,"column":12},"end":{"line":95,"column":71}},"23":{"start":{"line":97,"column":12},"end":{"line":97,"column":71}},"24":{"start":{"line":113,"column":8},"end":{"line":113,"column":86}},"25":{"start":{"line":114,"column":8},"end":{"line":114,"column":67}},"26":{"start":{"line":115,"column":8},"end":{"line":115,"column":83}},"27":{"start":{"line":117,"column":8},"end":{"line":117,"column":64}}},"branchMap":{"1":{"line":72,"type":"if","locations":[{"start":{"line":72,"column":8},"end":{"line":72,"column":8}},{"start":{"line":72,"column":8},"end":{"line":72,"column":8}}]},"2":{"line":77,"type":"if","locations":[{"start":{"line":77,"column":8},"end":{"line":77,"column":8}},{"start":{"line":77,"column":8},"end":{"line":77,"column":8}}]},"3":{"line":94,"type":"if","locations":[{"start":{"line":94,"column":8},"end":{"line":94,"column":8}},{"start":{"line":94,"column":8},"end":{"line":94,"column":8}}]}}},"contracts/lib/SafeERC20.sol":{"l":{"33":184,"42":155,"65":339,"66":339,"68":339,"71":339},"path":"/Users/leimingda/Documents/dodo/contracts/lib/SafeERC20.sol","s":{"1":184,"2":155,"3":339,"4":339,"5":339,"6":339},"b":{"1":[339,0],"2":[339,0],"3":[339,0]},"f":{"1":184,"2":155,"3":339},"fnMap":{"1":{"name":"safeTransfer","line":28,"loc":{"start":{"line":28,"column":4},"end":{"line":34,"column":4}}},"2":{"name":"safeTransferFrom","line":36,"loc":{"start":{"line":36,"column":4},"end":{"line":46,"column":4}}},"3":{"name":"_callOptionalReturn","line":54,"loc":{"start":{"line":54,"column":4},"end":{"line":73,"column":4}}}},"statementMap":{"1":{"start":{"line":33,"column":8},"end":{"line":33,"column":93}},"2":{"start":{"line":42,"column":8},"end":{"line":42,"column":1162}},"3":{"start":{"line":65,"column":8},"end":{"line":65,"column":75}},"4":{"start":{"line":66,"column":8},"end":{"line":66,"column":59}},"5":{"start":{"line":68,"column":8},"end":{"line":68,"column":2470}},"6":{"start":{"line":71,"column":12},"end":{"line":71,"column":96}}},"branchMap":{"1":{"line":66,"type":"if","locations":[{"start":{"line":66,"column":8},"end":{"line":66,"column":8}},{"start":{"line":66,"column":8},"end":{"line":66,"column":8}}]},"2":{"line":68,"type":"if","locations":[{"start":{"line":68,"column":8},"end":{"line":68,"column":8}},{"start":{"line":68,"column":8},"end":{"line":68,"column":8}}]},"3":{"line":71,"type":"if","locations":[{"start":{"line":71,"column":12},"end":{"line":71,"column":12}},{"start":{"line":71,"column":12},"end":{"line":71,"column":12}}]}}}} \ No newline at end of file +{"contracts/dodo.sol":{"l":{"37":11,"38":10,"40":10,"41":10,"42":10,"43":10,"44":10,"46":10,"47":10,"48":10,"49":10,"51":10,"52":10,"53":10,"54":10,"56":10,"57":10,"59":10},"path":"/Users/leimingda/Documents/dodo/contracts/dodo.sol","s":{"1":11,"2":10,"3":10,"4":10,"5":10,"6":10,"7":10,"8":10,"9":10,"10":10,"11":10,"12":10,"13":10,"14":10,"15":10,"16":10,"17":10,"18":10},"b":{"1":[10,1]},"f":{"1":11},"fnMap":{"1":{"name":"init","line":36,"loc":{"start":{"line":26,"column":4},"end":{"line":60,"column":4}}}},"statementMap":{"1":{"start":{"line":37,"column":8},"end":{"line":37,"column":58}},"2":{"start":{"line":38,"column":8},"end":{"line":38,"column":27}},"3":{"start":{"line":40,"column":8},"end":{"line":40,"column":32}},"4":{"start":{"line":41,"column":8},"end":{"line":41,"column":32}},"5":{"start":{"line":42,"column":8},"end":{"line":42,"column":31}},"6":{"start":{"line":43,"column":8},"end":{"line":43,"column":33}},"7":{"start":{"line":44,"column":8},"end":{"line":44,"column":24}},"8":{"start":{"line":46,"column":8},"end":{"line":46,"column":36}},"9":{"start":{"line":47,"column":8},"end":{"line":47,"column":37}},"10":{"start":{"line":48,"column":8},"end":{"line":48,"column":29}},"11":{"start":{"line":49,"column":8},"end":{"line":49,"column":40}},"12":{"start":{"line":51,"column":8},"end":{"line":51,"column":32}},"13":{"start":{"line":52,"column":8},"end":{"line":52,"column":32}},"14":{"start":{"line":53,"column":8},"end":{"line":53,"column":14}},"15":{"start":{"line":54,"column":8},"end":{"line":54,"column":37}},"16":{"start":{"line":56,"column":8},"end":{"line":56,"column":56}},"17":{"start":{"line":57,"column":8},"end":{"line":57,"column":57}},"18":{"start":{"line":59,"column":8},"end":{"line":59,"column":29}}},"branchMap":{"1":{"line":37,"type":"if","locations":[{"start":{"line":37,"column":8},"end":{"line":37,"column":8}},{"start":{"line":37,"column":8},"end":{"line":37,"column":8}}]}}},"contracts/DODOEthProxy.sol":{"l":{"52":1,"53":1,"57":0,"61":1,"69":2,"70":1,"71":1,"72":1,"73":1,"74":1,"75":1,"76":1,"77":1,"78":1,"86":1,"87":1,"88":1,"89":1,"90":1,"91":1,"92":1,"93":1,"94":1,"95":1,"103":4,"104":3,"105":3,"106":3,"107":3,"108":3,"118":1,"126":1},"path":"/Users/leimingda/Documents/dodo/contracts/DODOEthProxy.sol","s":{"1":1,"2":1,"3":0,"4":2,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":1,"14":1,"15":1,"16":1,"17":1,"18":1,"19":1,"20":1,"21":1,"22":1,"23":1,"24":4,"25":3,"26":3,"27":3,"28":3,"29":3,"30":1,"31":1},"b":{"1":[0,0],"2":[1,0],"3":[1,1],"4":[1,0],"5":[1,0],"6":[3,1]},"f":{"1":1,"2":0,"3":2,"4":1,"5":4,"6":1,"7":1},"fnMap":{"1":{"name":"constructor","line":51,"loc":{"start":{"line":51,"column":4},"end":{"line":54,"column":4}}},"2":{"name":null,"line":56,"loc":{"start":{"line":56,"column":4},"end":{"line":58,"column":4}}},"3":{"name":"sellEthTo","line":68,"loc":{"start":{"line":64,"column":4},"end":{"line":79,"column":4}}},"4":{"name":"buyEthWith","line":85,"loc":{"start":{"line":81,"column":4},"end":{"line":96,"column":4}}},"5":{"name":"depositEth","line":101,"loc":{"start":{"line":98,"column":4},"end":{"line":109,"column":4}}},"6":{"name":"_transferIn","line":113,"loc":{"start":{"line":113,"column":4},"end":{"line":119,"column":4}}},"7":{"name":"_transferOut","line":121,"loc":{"start":{"line":121,"column":4},"end":{"line":127,"column":4}}}},"statementMap":{"1":{"start":{"line":52,"column":8},"end":{"line":52,"column":27}},"2":{"start":{"line":53,"column":8},"end":{"line":53,"column":20}},"3":{"start":{"line":57,"column":8},"end":{"line":57,"column":60}},"4":{"start":{"line":69,"column":8},"end":{"line":69,"column":62}},"5":{"start":{"line":70,"column":8},"end":{"line":70,"column":78}},"6":{"start":{"line":71,"column":8},"end":{"line":71,"column":69}},"7":{"start":{"line":72,"column":8},"end":{"line":72,"column":81}},"8":{"start":{"line":73,"column":8},"end":{"line":73,"column":48}},"9":{"start":{"line":74,"column":8},"end":{"line":74,"column":45}},"10":{"start":{"line":75,"column":8},"end":{"line":75,"column":66}},"11":{"start":{"line":76,"column":8},"end":{"line":76,"column":70}},"12":{"start":{"line":77,"column":8},"end":{"line":77,"column":87}},"13":{"start":{"line":78,"column":8},"end":{"line":78,"column":33}},"14":{"start":{"line":86,"column":8},"end":{"line":86,"column":78}},"15":{"start":{"line":87,"column":8},"end":{"line":87,"column":64}},"16":{"start":{"line":88,"column":8},"end":{"line":88,"column":67}},"17":{"start":{"line":89,"column":8},"end":{"line":89,"column":65}},"18":{"start":{"line":90,"column":8},"end":{"line":90,"column":62}},"19":{"start":{"line":91,"column":8},"end":{"line":91,"column":61}},"20":{"start":{"line":92,"column":8},"end":{"line":92,"column":40}},"21":{"start":{"line":93,"column":8},"end":{"line":93,"column":37}},"22":{"start":{"line":94,"column":8},"end":{"line":94,"column":82}},"23":{"start":{"line":95,"column":8},"end":{"line":95,"column":29}},"24":{"start":{"line":103,"column":8},"end":{"line":103,"column":62}},"25":{"start":{"line":104,"column":8},"end":{"line":104,"column":78}},"26":{"start":{"line":105,"column":8},"end":{"line":105,"column":48}},"27":{"start":{"line":106,"column":8},"end":{"line":106,"column":45}},"28":{"start":{"line":107,"column":8},"end":{"line":107,"column":55}},"29":{"start":{"line":108,"column":8},"end":{"line":108,"column":70}},"30":{"start":{"line":118,"column":8},"end":{"line":118,"column":73}},"31":{"start":{"line":126,"column":8},"end":{"line":126,"column":52}}},"branchMap":{"1":{"line":57,"type":"if","locations":[{"start":{"line":57,"column":8},"end":{"line":57,"column":8}},{"start":{"line":57,"column":8},"end":{"line":57,"column":8}}]},"2":{"line":61,"type":"if","locations":[{"start":{"line":61,"column":8},"end":{"line":61,"column":8}},{"start":{"line":61,"column":8},"end":{"line":61,"column":8}}]},"3":{"line":69,"type":"if","locations":[{"start":{"line":69,"column":8},"end":{"line":69,"column":8}},{"start":{"line":69,"column":8},"end":{"line":69,"column":8}}]},"4":{"line":72,"type":"if","locations":[{"start":{"line":72,"column":8},"end":{"line":72,"column":8}},{"start":{"line":72,"column":8},"end":{"line":72,"column":8}}]},"5":{"line":88,"type":"if","locations":[{"start":{"line":88,"column":8},"end":{"line":88,"column":8}},{"start":{"line":88,"column":8},"end":{"line":88,"column":8}}]},"6":{"line":103,"type":"if","locations":[{"start":{"line":103,"column":8},"end":{"line":103,"column":8}},{"start":{"line":103,"column":8},"end":{"line":103,"column":8}}]}}},"contracts/DODOZoo.sol":{"l":{"42":12,"43":10,"44":10,"45":10,"56":10,"57":10,"58":10,"59":10,"65":12,"69":10,"71":2,"76":15},"path":"/Users/leimingda/Documents/dodo/contracts/DODOZoo.sol","s":{"1":12,"2":10,"3":10,"4":10,"5":10,"6":10,"7":10,"8":10,"9":12,"10":10,"11":2,"12":15},"b":{"1":[10,2],"2":[10,0],"3":[10,2]},"f":{"1":12,"2":12,"3":15},"fnMap":{"1":{"name":"breedDODO","line":41,"loc":{"start":{"line":31,"column":4},"end":{"line":60,"column":4}}},"2":{"name":"isDODORegistered","line":64,"loc":{"start":{"line":64,"column":4},"end":{"line":73,"column":4}}},"3":{"name":"getDODO","line":75,"loc":{"start":{"line":75,"column":4},"end":{"line":77,"column":4}}}},"statementMap":{"1":{"start":{"line":42,"column":8},"end":{"line":42,"column":78}},"2":{"start":{"line":43,"column":8},"end":{"line":43,"column":66}},"3":{"start":{"line":44,"column":8},"end":{"line":44,"column":49}},"4":{"start":{"line":45,"column":8},"end":{"line":45,"column":1105}},"5":{"start":{"line":56,"column":8},"end":{"line":56,"column":52}},"6":{"start":{"line":57,"column":8},"end":{"line":57,"column":59}},"7":{"start":{"line":58,"column":8},"end":{"line":58,"column":35}},"8":{"start":{"line":59,"column":8},"end":{"line":59,"column":26}},"9":{"start":{"line":65,"column":8},"end":{"line":65,"column":1687}},"10":{"start":{"line":69,"column":12},"end":{"line":69,"column":24}},"11":{"start":{"line":71,"column":12},"end":{"line":71,"column":23}},"12":{"start":{"line":76,"column":8},"end":{"line":76,"column":53}}},"branchMap":{"1":{"line":42,"type":"if","locations":[{"start":{"line":42,"column":8},"end":{"line":42,"column":8}},{"start":{"line":42,"column":8},"end":{"line":42,"column":8}}]},"2":{"line":43,"type":"if","locations":[{"start":{"line":43,"column":8},"end":{"line":43,"column":8}},{"start":{"line":43,"column":8},"end":{"line":43,"column":8}}]},"3":{"line":65,"type":"if","locations":[{"start":{"line":65,"column":8},"end":{"line":65,"column":8}},{"start":{"line":65,"column":8},"end":{"line":65,"column":8}}]}}},"contracts/impl/Admin.sol":{"l":{"27":1,"31":1,"35":1,"39":2,"40":2,"44":2,"45":2,"49":3,"50":3,"54":1,"55":1,"61":0,"65":0,"69":0,"73":0,"77":1,"81":0},"path":"/Users/leimingda/Documents/dodo/contracts/impl/Admin.sol","s":{"1":1,"2":1,"3":1,"4":2,"5":2,"6":2,"7":2,"8":3,"9":3,"10":1,"11":1,"12":0,"13":0,"14":0,"15":0,"16":1,"17":0},"b":{},"f":{"1":1,"2":1,"3":1,"4":2,"5":2,"6":3,"7":1,"8":0,"9":0,"10":0,"11":0,"12":1,"13":0},"fnMap":{"1":{"name":"setOracle","line":26,"loc":{"start":{"line":26,"column":4},"end":{"line":28,"column":4}}},"2":{"name":"setSupervisor","line":30,"loc":{"start":{"line":30,"column":4},"end":{"line":32,"column":4}}},"3":{"name":"setMaintainer","line":34,"loc":{"start":{"line":34,"column":4},"end":{"line":36,"column":4}}},"4":{"name":"setLiquidityProviderFeeRate","line":38,"loc":{"start":{"line":38,"column":4},"end":{"line":41,"column":4}}},"5":{"name":"setMaintainerFeeRate","line":43,"loc":{"start":{"line":43,"column":4},"end":{"line":46,"column":4}}},"6":{"name":"setK","line":48,"loc":{"start":{"line":48,"column":4},"end":{"line":51,"column":4}}},"7":{"name":"setGasPriceLimit","line":53,"loc":{"start":{"line":53,"column":4},"end":{"line":56,"column":4}}},"8":{"name":"disableTrading","line":60,"loc":{"start":{"line":60,"column":4},"end":{"line":62,"column":4}}},"9":{"name":"enableTrading","line":64,"loc":{"start":{"line":64,"column":4},"end":{"line":66,"column":4}}},"10":{"name":"disableQuoteDeposit","line":68,"loc":{"start":{"line":68,"column":4},"end":{"line":70,"column":4}}},"11":{"name":"enableQuoteDeposit","line":72,"loc":{"start":{"line":72,"column":4},"end":{"line":74,"column":4}}},"12":{"name":"disableBaseDeposit","line":76,"loc":{"start":{"line":76,"column":4},"end":{"line":78,"column":4}}},"13":{"name":"enableBaseDeposit","line":80,"loc":{"start":{"line":80,"column":4},"end":{"line":82,"column":4}}}},"statementMap":{"1":{"start":{"line":27,"column":8},"end":{"line":27,"column":27}},"2":{"start":{"line":31,"column":8},"end":{"line":31,"column":35}},"3":{"start":{"line":35,"column":8},"end":{"line":35,"column":35}},"4":{"start":{"line":39,"column":8},"end":{"line":39,"column":50}},"5":{"start":{"line":40,"column":8},"end":{"line":40,"column":29}},"6":{"start":{"line":44,"column":8},"end":{"line":44,"column":43}},"7":{"start":{"line":45,"column":8},"end":{"line":45,"column":29}},"8":{"start":{"line":49,"column":8},"end":{"line":49,"column":17}},"9":{"start":{"line":50,"column":8},"end":{"line":50,"column":29}},"10":{"start":{"line":54,"column":8},"end":{"line":54,"column":43}},"11":{"start":{"line":55,"column":8},"end":{"line":55,"column":50}},"12":{"start":{"line":61,"column":8},"end":{"line":61,"column":30}},"13":{"start":{"line":65,"column":8},"end":{"line":65,"column":29}},"14":{"start":{"line":69,"column":8},"end":{"line":69,"column":38}},"15":{"start":{"line":73,"column":8},"end":{"line":73,"column":37}},"16":{"start":{"line":77,"column":8},"end":{"line":77,"column":37}},"17":{"start":{"line":81,"column":8},"end":{"line":81,"column":36}}},"branchMap":{}},"contracts/impl/LiquidityProvider.sol":{"l":{"46":78,"47":78,"51":0,"52":0,"58":9,"62":38,"66":9,"70":35,"74":9,"78":8,"88":36,"89":36,"90":36,"91":36,"93":29,"95":7,"99":36,"100":36,"101":36,"103":36,"107":42,"108":42,"109":42,"110":42,"112":34,"114":8,"118":42,"119":42,"120":42,"122":42,"129":10,"130":10,"131":10,"133":9,"134":9,"140":8,"141":7,"144":5,"145":5,"146":5,"147":5,"149":5,"150":5,"152":5,"157":10,"158":10,"159":10,"161":9,"162":9,"168":8,"169":7,"172":5,"173":5,"174":5,"175":5,"177":5,"178":5,"180":5,"186":9,"189":9,"190":8,"193":8,"194":8,"195":8,"196":8,"198":8,"199":8,"201":8,"205":10,"208":10,"209":9,"212":9,"213":9,"214":9,"215":9,"217":9,"218":9,"220":9,"226":42,"230":36,"234":14,"238":13,"244":37,"245":37,"246":37,"247":1,"249":36,"250":36,"254":34,"255":34,"256":34,"257":1,"259":33,"260":33,"264":22,"265":19,"266":6,"267":6,"268":6,"269":6,"275":6,"280":6,"282":13,"287":24,"288":21,"289":8,"290":8,"291":8,"292":8,"298":8,"303":8,"305":13},"path":"/Users/leimingda/Documents/dodo/contracts/impl/LiquidityProvider.sol","s":{"1":78,"2":0,"3":9,"4":38,"5":9,"6":35,"7":9,"8":8,"9":36,"10":36,"11":36,"12":36,"13":29,"14":7,"15":7,"16":36,"17":36,"18":36,"19":36,"20":42,"21":42,"22":42,"23":42,"24":34,"25":8,"26":8,"27":42,"28":42,"29":42,"30":42,"31":10,"32":10,"33":10,"34":9,"35":9,"36":8,"37":7,"38":5,"39":5,"40":5,"41":5,"42":5,"43":5,"44":5,"45":10,"46":10,"47":10,"48":9,"49":9,"50":8,"51":7,"52":5,"53":5,"54":5,"55":5,"56":5,"57":5,"58":5,"59":9,"60":9,"61":8,"62":8,"63":8,"64":8,"65":8,"66":8,"67":8,"68":8,"69":10,"70":10,"71":9,"72":9,"73":9,"74":9,"75":9,"76":9,"77":9,"78":9,"79":42,"80":36,"81":14,"82":13,"83":37,"84":37,"85":37,"86":1,"87":36,"88":36,"89":34,"90":34,"91":34,"92":1,"93":33,"94":33,"95":22,"96":19,"97":6,"98":6,"99":6,"100":6,"101":6,"102":6,"103":13,"104":24,"105":21,"106":8,"107":8,"108":8,"109":8,"110":8,"111":8,"112":13},"b":{"1":[78,0],"2":[0,0],"3":[29,7],"4":[7,0],"5":[34,8],"6":[8,0],"7":[9,1],"8":[8,1],"9":[5,2],"10":[9,1],"11":[8,1],"12":[5,2],"13":[8,0],"14":[9,0],"15":[1,36],"16":[1,33],"17":[19,3],"18":[6,13],"19":[21,3],"20":[8,13]},"f":{"1":78,"2":0,"3":9,"4":38,"5":9,"6":35,"7":9,"8":8,"9":36,"10":42,"11":10,"12":10,"13":9,"14":10,"15":42,"16":36,"17":14,"18":13,"19":37,"20":34,"21":22,"22":24},"fnMap":{"1":{"name":"depositQuoteAllowed","line":45,"loc":{"start":{"line":45,"column":4},"end":{"line":48,"column":4}}},"2":{"name":"depositBaseAllowed","line":50,"loc":{"start":{"line":50,"column":4},"end":{"line":53,"column":4}}},"3":{"name":"withdrawBase","line":57,"loc":{"start":{"line":57,"column":4},"end":{"line":59,"column":4}}},"4":{"name":"depositBase","line":61,"loc":{"start":{"line":61,"column":4},"end":{"line":63,"column":4}}},"5":{"name":"withdrawQuote","line":65,"loc":{"start":{"line":65,"column":4},"end":{"line":67,"column":4}}},"6":{"name":"depositQuote","line":69,"loc":{"start":{"line":69,"column":4},"end":{"line":71,"column":4}}},"7":{"name":"withdrawAllBase","line":73,"loc":{"start":{"line":73,"column":4},"end":{"line":75,"column":4}}},"8":{"name":"withdrawAllQuote","line":77,"loc":{"start":{"line":77,"column":4},"end":{"line":79,"column":4}}},"9":{"name":"depositQuoteTo","line":86,"loc":{"start":{"line":83,"column":4},"end":{"line":104,"column":4}}},"10":{"name":"depositBaseTo","line":106,"loc":{"start":{"line":106,"column":4},"end":{"line":123,"column":4}}},"11":{"name":"withdrawQuoteTo","line":127,"loc":{"start":{"line":127,"column":4},"end":{"line":153,"column":4}}},"12":{"name":"withdrawBaseTo","line":155,"loc":{"start":{"line":155,"column":4},"end":{"line":181,"column":4}}},"13":{"name":"withdrawAllQuoteTo","line":185,"loc":{"start":{"line":185,"column":4},"end":{"line":202,"column":4}}},"14":{"name":"withdrawAllBaseTo","line":204,"loc":{"start":{"line":204,"column":4},"end":{"line":221,"column":4}}},"15":{"name":"_mintBaseCapital","line":225,"loc":{"start":{"line":225,"column":4},"end":{"line":227,"column":4}}},"16":{"name":"_mintQuoteCapital","line":229,"loc":{"start":{"line":229,"column":4},"end":{"line":231,"column":4}}},"17":{"name":"_burnBaseCapital","line":233,"loc":{"start":{"line":233,"column":4},"end":{"line":235,"column":4}}},"18":{"name":"_burnQuoteCapital","line":237,"loc":{"start":{"line":237,"column":4},"end":{"line":239,"column":4}}},"19":{"name":"getLpBaseBalance","line":243,"loc":{"start":{"line":243,"column":4},"end":{"line":251,"column":4}}},"20":{"name":"getLpQuoteBalance","line":253,"loc":{"start":{"line":253,"column":4},"end":{"line":261,"column":4}}},"21":{"name":"getWithdrawQuotePenalty","line":263,"loc":{"start":{"line":263,"column":4},"end":{"line":284,"column":4}}},"22":{"name":"getWithdrawBasePenalty","line":286,"loc":{"start":{"line":286,"column":4},"end":{"line":307,"column":4}}}},"statementMap":{"1":{"start":{"line":46,"column":8},"end":{"line":46,"column":68}},"2":{"start":{"line":51,"column":8},"end":{"line":51,"column":66}},"3":{"start":{"line":58,"column":8},"end":{"line":58,"column":49}},"4":{"start":{"line":62,"column":8},"end":{"line":62,"column":40}},"5":{"start":{"line":66,"column":8},"end":{"line":66,"column":50}},"6":{"start":{"line":70,"column":8},"end":{"line":70,"column":41}},"7":{"start":{"line":74,"column":8},"end":{"line":74,"column":44}},"8":{"start":{"line":78,"column":8},"end":{"line":78,"column":45}},"9":{"start":{"line":88,"column":8},"end":{"line":88,"column":54}},"10":{"start":{"line":89,"column":8},"end":{"line":89,"column":58}},"11":{"start":{"line":90,"column":8},"end":{"line":90,"column":32}},"12":{"start":{"line":91,"column":8},"end":{"line":91,"column":2659}},"13":{"start":{"line":93,"column":12},"end":{"line":93,"column":44}},"14":{"start":{"line":94,"column":15},"end":{"line":94,"column":2809}},"15":{"start":{"line":95,"column":12},"end":{"line":95,"column":67}},"16":{"start":{"line":99,"column":8},"end":{"line":99,"column":48}},"17":{"start":{"line":100,"column":8},"end":{"line":100,"column":37}},"18":{"start":{"line":101,"column":8},"end":{"line":101,"column":76}},"19":{"start":{"line":103,"column":8},"end":{"line":103,"column":54}},"20":{"start":{"line":107,"column":8},"end":{"line":107,"column":53}},"21":{"start":{"line":108,"column":8},"end":{"line":108,"column":56}},"22":{"start":{"line":109,"column":8},"end":{"line":109,"column":32}},"23":{"start":{"line":110,"column":8},"end":{"line":110,"column":3425}},"24":{"start":{"line":112,"column":12},"end":{"line":112,"column":43}},"25":{"start":{"line":113,"column":15},"end":{"line":113,"column":3572}},"26":{"start":{"line":114,"column":12},"end":{"line":114,"column":65}},"27":{"start":{"line":118,"column":8},"end":{"line":118,"column":47}},"28":{"start":{"line":119,"column":8},"end":{"line":119,"column":36}},"29":{"start":{"line":120,"column":8},"end":{"line":120,"column":74}},"30":{"start":{"line":122,"column":8},"end":{"line":122,"column":53}},"31":{"start":{"line":129,"column":8},"end":{"line":129,"column":54}},"32":{"start":{"line":130,"column":8},"end":{"line":130,"column":58}},"33":{"start":{"line":131,"column":8},"end":{"line":131,"column":52}},"34":{"start":{"line":133,"column":8},"end":{"line":133,"column":88}},"35":{"start":{"line":134,"column":8},"end":{"line":134,"column":4377}},"36":{"start":{"line":140,"column":8},"end":{"line":140,"column":57}},"37":{"start":{"line":141,"column":8},"end":{"line":141,"column":70}},"38":{"start":{"line":144,"column":8},"end":{"line":144,"column":76}},"39":{"start":{"line":145,"column":8},"end":{"line":145,"column":57}},"40":{"start":{"line":146,"column":8},"end":{"line":146,"column":54}},"41":{"start":{"line":147,"column":8},"end":{"line":147,"column":33}},"42":{"start":{"line":149,"column":8},"end":{"line":149,"column":68}},"43":{"start":{"line":150,"column":8},"end":{"line":150,"column":52}},"44":{"start":{"line":152,"column":8},"end":{"line":152,"column":34}},"45":{"start":{"line":157,"column":8},"end":{"line":157,"column":53}},"46":{"start":{"line":158,"column":8},"end":{"line":158,"column":56}},"47":{"start":{"line":159,"column":8},"end":{"line":159,"column":50}},"48":{"start":{"line":161,"column":8},"end":{"line":161,"column":85}},"49":{"start":{"line":162,"column":8},"end":{"line":162,"column":5521}},"50":{"start":{"line":168,"column":8},"end":{"line":168,"column":56}},"51":{"start":{"line":169,"column":8},"end":{"line":169,"column":71}},"52":{"start":{"line":172,"column":8},"end":{"line":172,"column":74}},"53":{"start":{"line":173,"column":8},"end":{"line":173,"column":55}},"54":{"start":{"line":174,"column":8},"end":{"line":174,"column":53}},"55":{"start":{"line":175,"column":8},"end":{"line":175,"column":32}},"56":{"start":{"line":177,"column":8},"end":{"line":177,"column":67}},"57":{"start":{"line":178,"column":8},"end":{"line":178,"column":51}},"58":{"start":{"line":180,"column":8},"end":{"line":180,"column":34}},"59":{"start":{"line":186,"column":8},"end":{"line":186,"column":62}},"60":{"start":{"line":189,"column":8},"end":{"line":189,"column":65}},"61":{"start":{"line":190,"column":8},"end":{"line":190,"column":79}},"62":{"start":{"line":193,"column":8},"end":{"line":193,"column":84}},"63":{"start":{"line":194,"column":8},"end":{"line":194,"column":74}},"64":{"start":{"line":195,"column":8},"end":{"line":195,"column":62}},"65":{"start":{"line":196,"column":8},"end":{"line":196,"column":33}},"66":{"start":{"line":198,"column":8},"end":{"line":198,"column":63}},"67":{"start":{"line":199,"column":8},"end":{"line":199,"column":52}},"68":{"start":{"line":201,"column":8},"end":{"line":201,"column":42}},"69":{"start":{"line":205,"column":8},"end":{"line":205,"column":61}},"70":{"start":{"line":208,"column":8},"end":{"line":208,"column":64}},"71":{"start":{"line":209,"column":8},"end":{"line":209,"column":79}},"72":{"start":{"line":212,"column":8},"end":{"line":212,"column":82}},"73":{"start":{"line":213,"column":8},"end":{"line":213,"column":72}},"74":{"start":{"line":214,"column":8},"end":{"line":214,"column":61}},"75":{"start":{"line":215,"column":8},"end":{"line":215,"column":32}},"76":{"start":{"line":217,"column":8},"end":{"line":217,"column":62}},"77":{"start":{"line":218,"column":8},"end":{"line":218,"column":51}},"78":{"start":{"line":220,"column":8},"end":{"line":220,"column":42}},"79":{"start":{"line":226,"column":8},"end":{"line":226,"column":60}},"80":{"start":{"line":230,"column":8},"end":{"line":230,"column":61}},"81":{"start":{"line":234,"column":8},"end":{"line":234,"column":60}},"82":{"start":{"line":238,"column":8},"end":{"line":238,"column":61}},"83":{"start":{"line":244,"column":8},"end":{"line":244,"column":56}},"84":{"start":{"line":245,"column":8},"end":{"line":245,"column":53}},"85":{"start":{"line":246,"column":8},"end":{"line":246,"column":8814}},"86":{"start":{"line":247,"column":12},"end":{"line":247,"column":20}},"87":{"start":{"line":249,"column":8},"end":{"line":249,"column":84}},"88":{"start":{"line":250,"column":8},"end":{"line":250,"column":24}},"89":{"start":{"line":254,"column":8},"end":{"line":254,"column":58}},"90":{"start":{"line":255,"column":8},"end":{"line":255,"column":54}},"91":{"start":{"line":256,"column":8},"end":{"line":256,"column":9204}},"92":{"start":{"line":257,"column":12},"end":{"line":257,"column":20}},"93":{"start":{"line":259,"column":8},"end":{"line":259,"column":87}},"94":{"start":{"line":260,"column":8},"end":{"line":260,"column":24}},"95":{"start":{"line":264,"column":8},"end":{"line":264,"column":80}},"96":{"start":{"line":265,"column":8},"end":{"line":265,"column":9573}},"97":{"start":{"line":266,"column":12},"end":{"line":266,"column":78}},"98":{"start":{"line":267,"column":12},"end":{"line":267,"column":44}},"99":{"start":{"line":268,"column":12},"end":{"line":268,"column":66}},"100":{"start":{"line":269,"column":12},"end":{"line":269,"column":9829}},"101":{"start":{"line":275,"column":12},"end":{"line":275,"column":10056}},"102":{"start":{"line":280,"column":12},"end":{"line":280,"column":71}},"103":{"start":{"line":282,"column":12},"end":{"line":282,"column":20}},"104":{"start":{"line":287,"column":8},"end":{"line":287,"column":78}},"105":{"start":{"line":288,"column":8},"end":{"line":288,"column":10546}},"106":{"start":{"line":289,"column":12},"end":{"line":289,"column":81}},"107":{"start":{"line":290,"column":12},"end":{"line":290,"column":44}},"108":{"start":{"line":291,"column":12},"end":{"line":291,"column":72}},"109":{"start":{"line":292,"column":12},"end":{"line":292,"column":10811}},"110":{"start":{"line":298,"column":12},"end":{"line":298,"column":11035}},"111":{"start":{"line":303,"column":12},"end":{"line":303,"column":69}},"112":{"start":{"line":305,"column":12},"end":{"line":305,"column":20}}},"branchMap":{"1":{"line":46,"type":"if","locations":[{"start":{"line":46,"column":8},"end":{"line":46,"column":8}},{"start":{"line":46,"column":8},"end":{"line":46,"column":8}}]},"2":{"line":51,"type":"if","locations":[{"start":{"line":51,"column":8},"end":{"line":51,"column":8}},{"start":{"line":51,"column":8},"end":{"line":51,"column":8}}]},"3":{"line":91,"type":"if","locations":[{"start":{"line":91,"column":8},"end":{"line":91,"column":8}},{"start":{"line":91,"column":8},"end":{"line":91,"column":8}}]},"4":{"line":94,"type":"if","locations":[{"start":{"line":94,"column":15},"end":{"line":94,"column":15}},{"start":{"line":94,"column":15},"end":{"line":94,"column":15}}]},"5":{"line":110,"type":"if","locations":[{"start":{"line":110,"column":8},"end":{"line":110,"column":8}},{"start":{"line":110,"column":8},"end":{"line":110,"column":8}}]},"6":{"line":113,"type":"if","locations":[{"start":{"line":113,"column":15},"end":{"line":113,"column":15}},{"start":{"line":113,"column":15},"end":{"line":113,"column":15}}]},"7":{"line":131,"type":"if","locations":[{"start":{"line":131,"column":8},"end":{"line":131,"column":8}},{"start":{"line":131,"column":8},"end":{"line":131,"column":8}}]},"8":{"line":134,"type":"if","locations":[{"start":{"line":134,"column":8},"end":{"line":134,"column":8}},{"start":{"line":134,"column":8},"end":{"line":134,"column":8}}]},"9":{"line":141,"type":"if","locations":[{"start":{"line":141,"column":8},"end":{"line":141,"column":8}},{"start":{"line":141,"column":8},"end":{"line":141,"column":8}}]},"10":{"line":159,"type":"if","locations":[{"start":{"line":159,"column":8},"end":{"line":159,"column":8}},{"start":{"line":159,"column":8},"end":{"line":159,"column":8}}]},"11":{"line":162,"type":"if","locations":[{"start":{"line":162,"column":8},"end":{"line":162,"column":8}},{"start":{"line":162,"column":8},"end":{"line":162,"column":8}}]},"12":{"line":169,"type":"if","locations":[{"start":{"line":169,"column":8},"end":{"line":169,"column":8}},{"start":{"line":169,"column":8},"end":{"line":169,"column":8}}]},"13":{"line":190,"type":"if","locations":[{"start":{"line":190,"column":8},"end":{"line":190,"column":8}},{"start":{"line":190,"column":8},"end":{"line":190,"column":8}}]},"14":{"line":209,"type":"if","locations":[{"start":{"line":209,"column":8},"end":{"line":209,"column":8}},{"start":{"line":209,"column":8},"end":{"line":209,"column":8}}]},"15":{"line":246,"type":"if","locations":[{"start":{"line":246,"column":8},"end":{"line":246,"column":8}},{"start":{"line":246,"column":8},"end":{"line":246,"column":8}}]},"16":{"line":256,"type":"if","locations":[{"start":{"line":256,"column":8},"end":{"line":256,"column":8}},{"start":{"line":256,"column":8},"end":{"line":256,"column":8}}]},"17":{"line":264,"type":"if","locations":[{"start":{"line":264,"column":8},"end":{"line":264,"column":8}},{"start":{"line":264,"column":8},"end":{"line":264,"column":8}}]},"18":{"line":265,"type":"if","locations":[{"start":{"line":265,"column":8},"end":{"line":265,"column":8}},{"start":{"line":265,"column":8},"end":{"line":265,"column":8}}]},"19":{"line":287,"type":"if","locations":[{"start":{"line":287,"column":8},"end":{"line":287,"column":8}},{"start":{"line":287,"column":8},"end":{"line":287,"column":8}}]},"20":{"line":288,"type":"if","locations":[{"start":{"line":288,"column":8},"end":{"line":288,"column":8}},{"start":{"line":288,"column":8},"end":{"line":288,"column":8}}]}}},"contracts/impl/Pricing.sol":{"l":{"33":25,"34":25,"43":25,"51":34,"52":32,"53":32,"54":32,"64":1,"65":1,"72":1,"83":2,"84":2,"91":2,"100":35,"101":35,"102":35,"103":35,"108":35,"118":7,"119":6,"120":6,"131":5,"132":5,"141":52,"142":52,"143":52,"144":52,"149":52,"155":248,"156":248,"157":248,"158":161,"160":35,"161":35,"163":52,"164":52,"173":43,"174":43},"path":"/Users/leimingda/Documents/dodo/contracts/impl/Pricing.sol","s":{"1":25,"2":25,"3":25,"4":34,"5":32,"6":32,"7":32,"8":1,"9":1,"10":1,"11":2,"12":2,"13":2,"14":35,"15":35,"16":35,"17":35,"18":35,"19":7,"20":6,"21":6,"22":5,"23":5,"24":52,"25":52,"26":52,"27":52,"28":52,"29":248,"30":248,"31":248,"32":161,"33":87,"34":35,"35":35,"36":52,"37":52,"38":52,"39":43,"40":43},"b":{"1":[32,2],"2":[6,1],"3":[161,87],"4":[35,52],"5":[52,0]},"f":{"1":25,"2":34,"3":1,"4":2,"5":35,"6":7,"7":5,"8":52,"9":248,"10":43},"fnMap":{"1":{"name":"_ROneSellBaseToken","line":28,"loc":{"start":{"line":28,"column":4},"end":{"line":44,"column":4}}},"2":{"name":"_ROneBuyBaseToken","line":46,"loc":{"start":{"line":46,"column":4},"end":{"line":55,"column":4}}},"3":{"name":"_RBelowSellBaseToken","line":59,"loc":{"start":{"line":59,"column":4},"end":{"line":73,"column":4}}},"4":{"name":"_RBelowBuyBaseToken","line":75,"loc":{"start":{"line":75,"column":4},"end":{"line":92,"column":4}}},"5":{"name":"_RBelowBackToOne","line":94,"loc":{"start":{"line":94,"column":4},"end":{"line":109,"column":4}}},"6":{"name":"_RAboveBuyBaseToken","line":113,"loc":{"start":{"line":113,"column":4},"end":{"line":121,"column":4}}},"7":{"name":"_RAboveSellBaseToken","line":123,"loc":{"start":{"line":123,"column":4},"end":{"line":133,"column":4}}},"8":{"name":"_RAboveBackToOne","line":135,"loc":{"start":{"line":135,"column":4},"end":{"line":150,"column":4}}},"9":{"name":"_getExpectedTarget","line":154,"loc":{"start":{"line":154,"column":4},"end":{"line":166,"column":4}}},"10":{"name":"_RAboveIntegrate","line":168,"loc":{"start":{"line":168,"column":4},"end":{"line":175,"column":4}}}},"statementMap":{"1":{"start":{"line":33,"column":8},"end":{"line":33,"column":36}},"2":{"start":{"line":34,"column":8},"end":{"line":34,"column":768}},"3":{"start":{"line":43,"column":8},"end":{"line":43,"column":45}},"4":{"start":{"line":51,"column":8},"end":{"line":51,"column":84}},"5":{"start":{"line":52,"column":8},"end":{"line":52,"column":54}},"6":{"start":{"line":53,"column":8},"end":{"line":53,"column":89}},"7":{"start":{"line":54,"column":8},"end":{"line":54,"column":28}},"8":{"start":{"line":64,"column":8},"end":{"line":64,"column":36}},"9":{"start":{"line":65,"column":8},"end":{"line":65,"column":1886}},"10":{"start":{"line":72,"column":8},"end":{"line":72,"column":35}},"11":{"start":{"line":83,"column":8},"end":{"line":83,"column":36}},"12":{"start":{"line":84,"column":8},"end":{"line":84,"column":2502}},"13":{"start":{"line":91,"column":8},"end":{"line":91,"column":35}},"14":{"start":{"line":100,"column":8},"end":{"line":100,"column":74}},"15":{"start":{"line":101,"column":8},"end":{"line":101,"column":40}},"16":{"start":{"line":102,"column":8},"end":{"line":102,"column":62}},"17":{"start":{"line":103,"column":8},"end":{"line":103,"column":3174}},"18":{"start":{"line":108,"column":8},"end":{"line":108,"column":63}},"19":{"start":{"line":118,"column":8},"end":{"line":118,"column":74}},"20":{"start":{"line":119,"column":8},"end":{"line":119,"column":44}},"21":{"start":{"line":120,"column":8},"end":{"line":120,"column":66}},"22":{"start":{"line":131,"column":8},"end":{"line":131,"column":44}},"23":{"start":{"line":132,"column":8},"end":{"line":132,"column":66}},"24":{"start":{"line":141,"column":8},"end":{"line":141,"column":77}},"25":{"start":{"line":142,"column":8},"end":{"line":142,"column":40}},"26":{"start":{"line":143,"column":8},"end":{"line":143,"column":68}},"27":{"start":{"line":144,"column":8},"end":{"line":144,"column":4700}},"28":{"start":{"line":149,"column":8},"end":{"line":149,"column":62}},"29":{"start":{"line":155,"column":8},"end":{"line":155,"column":35}},"30":{"start":{"line":156,"column":8},"end":{"line":156,"column":34}},"31":{"start":{"line":157,"column":8},"end":{"line":157,"column":5148}},"32":{"start":{"line":158,"column":12},"end":{"line":158,"column":76}},"33":{"start":{"line":159,"column":15},"end":{"line":159,"column":5280}},"34":{"start":{"line":160,"column":12},"end":{"line":160,"column":82}},"35":{"start":{"line":161,"column":12},"end":{"line":161,"column":66}},"36":{"start":{"line":162,"column":15},"end":{"line":162,"column":5492}},"37":{"start":{"line":163,"column":12},"end":{"line":163,"column":82}},"38":{"start":{"line":164,"column":12},"end":{"line":164,"column":66}},"39":{"start":{"line":173,"column":8},"end":{"line":173,"column":36}},"40":{"start":{"line":174,"column":8},"end":{"line":174,"column":61}}},"branchMap":{"1":{"line":51,"type":"if","locations":[{"start":{"line":51,"column":8},"end":{"line":51,"column":8}},{"start":{"line":51,"column":8},"end":{"line":51,"column":8}}]},"2":{"line":118,"type":"if","locations":[{"start":{"line":118,"column":8},"end":{"line":118,"column":8}},{"start":{"line":118,"column":8},"end":{"line":118,"column":8}}]},"3":{"line":157,"type":"if","locations":[{"start":{"line":157,"column":8},"end":{"line":157,"column":8}},{"start":{"line":157,"column":8},"end":{"line":157,"column":8}}]},"4":{"line":159,"type":"if","locations":[{"start":{"line":159,"column":15},"end":{"line":159,"column":15}},{"start":{"line":159,"column":15},"end":{"line":159,"column":15}}]},"5":{"line":162,"type":"if","locations":[{"start":{"line":162,"column":15},"end":{"line":162,"column":15}},{"start":{"line":162,"column":15},"end":{"line":162,"column":15}}]}}},"contracts/impl/Settlement.sol":{"l":{"39":74,"40":74,"44":78,"45":78,"49":100,"50":100,"54":79,"55":79,"61":56,"62":56,"66":45,"67":45,"71":1,"72":1,"76":1,"77":1,"84":4,"85":4,"86":4,"87":4,"88":4,"89":4,"91":4,"92":2,"93":2,"95":2,"98":4,"99":1,"100":1,"102":3,"105":4,"110":6,"111":5,"112":4,"113":4,"117":4,"121":4,"122":4,"123":4,"124":4,"129":4,"130":2,"135":3,"136":2,"141":2},"path":"/Users/leimingda/Documents/dodo/contracts/impl/Settlement.sol","s":{"1":74,"2":74,"3":78,"4":78,"5":100,"6":100,"7":79,"8":79,"9":56,"10":56,"11":45,"12":45,"13":1,"14":1,"15":1,"16":1,"17":4,"18":4,"19":4,"20":4,"21":4,"22":4,"23":4,"24":2,"25":2,"26":2,"27":4,"28":1,"29":1,"30":3,"31":4,"32":6,"33":5,"34":4,"35":4,"36":4,"37":4,"38":4,"39":4,"40":4,"41":4,"42":2,"43":3,"44":2,"45":2},"b":{"1":[2,2],"2":[1,3],"3":[5,1],"4":[4,1],"5":[2,2],"6":[1,1],"7":[2,1],"8":[1,1]},"f":{"1":74,"2":78,"3":100,"4":79,"5":56,"6":45,"7":1,"8":1,"9":4,"10":6,"11":4},"fnMap":{"1":{"name":"_baseTokenTransferIn","line":38,"loc":{"start":{"line":38,"column":4},"end":{"line":41,"column":4}}},"2":{"name":"_quoteTokenTransferIn","line":43,"loc":{"start":{"line":43,"column":4},"end":{"line":46,"column":4}}},"3":{"name":"_baseTokenTransferOut","line":48,"loc":{"start":{"line":48,"column":4},"end":{"line":51,"column":4}}},"4":{"name":"_quoteTokenTransferOut","line":53,"loc":{"start":{"line":53,"column":4},"end":{"line":56,"column":4}}},"5":{"name":"_donateBaseToken","line":60,"loc":{"start":{"line":60,"column":4},"end":{"line":63,"column":4}}},"6":{"name":"_donateQuoteToken","line":65,"loc":{"start":{"line":65,"column":4},"end":{"line":68,"column":4}}},"7":{"name":"donateBaseToken","line":70,"loc":{"start":{"line":70,"column":4},"end":{"line":73,"column":4}}},"8":{"name":"donateQuoteToken","line":75,"loc":{"start":{"line":75,"column":4},"end":{"line":78,"column":4}}},"9":{"name":"finalSettlement","line":83,"loc":{"start":{"line":83,"column":4},"end":{"line":106,"column":4}}},"10":{"name":"claim","line":109,"loc":{"start":{"line":109,"column":4},"end":{"line":125,"column":4}}},"11":{"name":"retrieve","line":128,"loc":{"start":{"line":128,"column":4},"end":{"line":142,"column":4}}}},"statementMap":{"1":{"start":{"line":39,"column":8},"end":{"line":39,"column":73}},"2":{"start":{"line":40,"column":8},"end":{"line":40,"column":50}},"3":{"start":{"line":44,"column":8},"end":{"line":44,"column":74}},"4":{"start":{"line":45,"column":8},"end":{"line":45,"column":52}},"5":{"start":{"line":49,"column":8},"end":{"line":49,"column":52}},"6":{"start":{"line":50,"column":8},"end":{"line":50,"column":50}},"7":{"start":{"line":54,"column":8},"end":{"line":54,"column":53}},"8":{"start":{"line":55,"column":8},"end":{"line":55,"column":52}},"9":{"start":{"line":61,"column":8},"end":{"line":61,"column":74}},"10":{"start":{"line":62,"column":8},"end":{"line":62,"column":36}},"11":{"start":{"line":66,"column":8},"end":{"line":66,"column":76}},"12":{"start":{"line":67,"column":8},"end":{"line":67,"column":37}},"13":{"start":{"line":71,"column":8},"end":{"line":71,"column":47}},"14":{"start":{"line":72,"column":8},"end":{"line":72,"column":31}},"15":{"start":{"line":76,"column":8},"end":{"line":76,"column":48}},"16":{"start":{"line":77,"column":8},"end":{"line":77,"column":32}},"17":{"start":{"line":84,"column":8},"end":{"line":84,"column":22}},"18":{"start":{"line":85,"column":8},"end":{"line":85,"column":38}},"19":{"start":{"line":86,"column":8},"end":{"line":86,"column":37}},"20":{"start":{"line":87,"column":8},"end":{"line":87,"column":30}},"21":{"start":{"line":88,"column":8},"end":{"line":88,"column":56}},"22":{"start":{"line":89,"column":8},"end":{"line":89,"column":58}},"23":{"start":{"line":91,"column":8},"end":{"line":91,"column":2850}},"24":{"start":{"line":92,"column":12},"end":{"line":92,"column":81}},"25":{"start":{"line":93,"column":12},"end":{"line":93,"column":92}},"26":{"start":{"line":95,"column":12},"end":{"line":95,"column":56}},"27":{"start":{"line":98,"column":8},"end":{"line":98,"column":3176}},"28":{"start":{"line":99,"column":12},"end":{"line":99,"column":78}},"29":{"start":{"line":100,"column":12},"end":{"line":100,"column":92}},"30":{"start":{"line":102,"column":12},"end":{"line":102,"column":54}},"31":{"start":{"line":105,"column":8},"end":{"line":105,"column":37}},"32":{"start":{"line":110,"column":8},"end":{"line":110,"column":46}},"33":{"start":{"line":111,"column":8},"end":{"line":111,"column":57}},"34":{"start":{"line":112,"column":8},"end":{"line":112,"column":35}},"35":{"start":{"line":113,"column":8},"end":{"line":113,"column":3792}},"36":{"start":{"line":117,"column":8},"end":{"line":117,"column":3940}},"37":{"start":{"line":121,"column":8},"end":{"line":121,"column":52}},"38":{"start":{"line":122,"column":8},"end":{"line":122,"column":54}},"39":{"start":{"line":123,"column":8},"end":{"line":123,"column":55}},"40":{"start":{"line":124,"column":8},"end":{"line":124,"column":14}},"41":{"start":{"line":129,"column":8},"end":{"line":129,"column":4406}},"42":{"start":{"line":130,"column":12},"end":{"line":130,"column":4451}},"43":{"start":{"line":135,"column":8},"end":{"line":135,"column":4629}},"44":{"start":{"line":136,"column":12},"end":{"line":136,"column":4675}},"45":{"start":{"line":141,"column":8},"end":{"line":141,"column":53}}},"branchMap":{"1":{"line":91,"type":"if","locations":[{"start":{"line":91,"column":8},"end":{"line":91,"column":8}},{"start":{"line":91,"column":8},"end":{"line":91,"column":8}}]},"2":{"line":98,"type":"if","locations":[{"start":{"line":98,"column":8},"end":{"line":98,"column":8}},{"start":{"line":98,"column":8},"end":{"line":98,"column":8}}]},"3":{"line":110,"type":"if","locations":[{"start":{"line":110,"column":8},"end":{"line":110,"column":8}},{"start":{"line":110,"column":8},"end":{"line":110,"column":8}}]},"4":{"line":111,"type":"if","locations":[{"start":{"line":111,"column":8},"end":{"line":111,"column":8}},{"start":{"line":111,"column":8},"end":{"line":111,"column":8}}]},"5":{"line":129,"type":"if","locations":[{"start":{"line":129,"column":8},"end":{"line":129,"column":8}},{"start":{"line":129,"column":8},"end":{"line":129,"column":8}}]},"6":{"line":130,"type":"if","locations":[{"start":{"line":130,"column":12},"end":{"line":130,"column":12}},{"start":{"line":130,"column":12},"end":{"line":130,"column":12}}]},"7":{"line":135,"type":"if","locations":[{"start":{"line":135,"column":8},"end":{"line":135,"column":8}},{"start":{"line":135,"column":8},"end":{"line":135,"column":8}}]},"8":{"line":136,"type":"if","locations":[{"start":{"line":136,"column":12},"end":{"line":136,"column":12}},{"start":{"line":136,"column":12},"end":{"line":136,"column":12}}]}}},"contracts/impl/Storage.sol":{"l":{"70":6,"71":2,"75":8,"76":4,"82":17,"83":16,"84":15,"88":172,"92":59,"96":93,"100":58,"104":84},"path":"/Users/leimingda/Documents/dodo/contracts/impl/Storage.sol","s":{"1":6,"2":8,"3":17,"4":16,"5":15,"6":172,"7":59,"8":93,"9":58,"10":84},"b":{"1":[2,4],"2":[4,4],"3":[16,1],"4":[15,1],"5":[13,2]},"f":{"1":6,"2":8,"3":17,"4":172,"5":59,"6":93,"7":58,"8":84},"fnMap":{"1":{"name":"onlySupervisorOrOwner","line":69,"loc":{"start":{"line":69,"column":4},"end":{"line":72,"column":4}}},"2":{"name":"notClosed","line":74,"loc":{"start":{"line":74,"column":4},"end":{"line":77,"column":4}}},"3":{"name":"_checkDODOParameters","line":81,"loc":{"start":{"line":81,"column":4},"end":{"line":85,"column":4}}},"4":{"name":"getOraclePrice","line":87,"loc":{"start":{"line":87,"column":4},"end":{"line":89,"column":4}}},"5":{"name":"getBaseCapitalBalanceOf","line":91,"loc":{"start":{"line":91,"column":4},"end":{"line":93,"column":4}}},"6":{"name":"getTotalBaseCapital","line":95,"loc":{"start":{"line":95,"column":4},"end":{"line":97,"column":4}}},"7":{"name":"getQuoteCapitalBalanceOf","line":99,"loc":{"start":{"line":99,"column":4},"end":{"line":101,"column":4}}},"8":{"name":"getTotalQuoteCapital","line":103,"loc":{"start":{"line":103,"column":4},"end":{"line":105,"column":4}}}},"statementMap":{"1":{"start":{"line":70,"column":8},"end":{"line":70,"column":94}},"2":{"start":{"line":75,"column":8},"end":{"line":75,"column":43}},"3":{"start":{"line":82,"column":8},"end":{"line":82,"column":64}},"4":{"start":{"line":83,"column":8},"end":{"line":83,"column":54}},"5":{"start":{"line":84,"column":8},"end":{"line":84,"column":95}},"6":{"start":{"line":88,"column":8},"end":{"line":88,"column":43}},"7":{"start":{"line":92,"column":8},"end":{"line":92,"column":63}},"8":{"start":{"line":96,"column":8},"end":{"line":96,"column":63}},"9":{"start":{"line":100,"column":8},"end":{"line":100,"column":64}},"10":{"start":{"line":104,"column":8},"end":{"line":104,"column":64}}},"branchMap":{"1":{"line":70,"type":"if","locations":[{"start":{"line":70,"column":8},"end":{"line":70,"column":8}},{"start":{"line":70,"column":8},"end":{"line":70,"column":8}}]},"2":{"line":75,"type":"if","locations":[{"start":{"line":75,"column":8},"end":{"line":75,"column":8}},{"start":{"line":75,"column":8},"end":{"line":75,"column":8}}]},"3":{"line":82,"type":"if","locations":[{"start":{"line":82,"column":8},"end":{"line":82,"column":8}},{"start":{"line":82,"column":8},"end":{"line":82,"column":8}}]},"4":{"line":83,"type":"if","locations":[{"start":{"line":83,"column":8},"end":{"line":83,"column":8}},{"start":{"line":83,"column":8},"end":{"line":83,"column":8}}]},"5":{"line":84,"type":"if","locations":[{"start":{"line":84,"column":8},"end":{"line":84,"column":8}},{"start":{"line":84,"column":8},"end":{"line":84,"column":8}}]}}},"contracts/impl/Trader.sol":{"l":{"38":79,"39":79,"43":79,"44":77,"57":32,"65":32,"68":31,"69":31,"70":31,"73":31,"74":31,"75":31,"77":31,"78":31,"79":31,"81":31,"92":45,"100":42,"103":41,"104":41,"105":41,"108":41,"109":41,"110":41,"112":41,"113":41,"114":41,"116":41,"122":1,"123":1,"127":1,"128":1,"143":33,"145":33,"147":33,"150":21,"151":21,"153":11,"154":11,"157":11,"159":5,"160":5,"161":5,"164":0,"168":2,"169":2,"172":4,"175":4,"180":1,"181":1,"185":33,"186":33,"187":33,"189":33,"204":46,"207":46,"208":46,"209":46,"211":46,"213":31,"214":29,"217":7,"218":6,"220":8,"221":8,"224":8,"227":2,"228":2,"231":3,"232":3,"235":3,"238":3,"242":43},"path":"/Users/leimingda/Documents/dodo/contracts/impl/Trader.sol","s":{"1":79,"2":79,"3":32,"4":32,"5":31,"6":31,"7":31,"8":31,"9":31,"10":31,"11":31,"12":31,"13":31,"14":31,"15":45,"16":42,"17":41,"18":41,"19":41,"20":41,"21":41,"22":41,"23":41,"24":41,"25":41,"26":41,"27":1,"28":1,"29":1,"30":1,"31":33,"32":33,"33":33,"34":21,"35":21,"36":12,"37":11,"38":11,"39":11,"40":5,"41":5,"42":5,"43":0,"44":6,"45":2,"46":2,"47":4,"48":4,"49":1,"50":1,"51":33,"52":33,"53":33,"54":33,"55":46,"56":46,"57":46,"58":46,"59":46,"60":31,"61":29,"62":15,"63":7,"64":6,"65":8,"66":8,"67":8,"68":8,"69":2,"70":2,"71":6,"72":3,"73":3,"74":3,"75":3,"76":43},"b":{"1":[79,0],"2":[77,2],"3":[31,1],"4":[41,1],"5":[21,12],"6":[11,1],"7":[5,6],"8":[0,5],"9":[2,4],"10":[31,15],"11":[7,8],"12":[8,0],"13":[2,6],"14":[3,3]},"f":{"1":79,"2":79,"3":32,"4":45,"5":1,"6":1,"7":33,"8":46},"fnMap":{"1":{"name":"tradeAllowed","line":37,"loc":{"start":{"line":37,"column":4},"end":{"line":40,"column":4}}},"2":{"name":"gasPriceLimit","line":42,"loc":{"start":{"line":42,"column":4},"end":{"line":45,"column":4}}},"3":{"name":"sellBaseToken","line":53,"loc":{"start":{"line":49,"column":4},"end":{"line":82,"column":4}}},"4":{"name":"buyBaseToken","line":88,"loc":{"start":{"line":84,"column":4},"end":{"line":117,"column":4}}},"5":{"name":"querySellBaseToken","line":121,"loc":{"start":{"line":121,"column":4},"end":{"line":124,"column":4}}},"6":{"name":"queryBuyBaseToken","line":126,"loc":{"start":{"line":126,"column":4},"end":{"line":129,"column":4}}},"7":{"name":"_querySellBaseToken","line":131,"loc":{"start":{"line":131,"column":4},"end":{"line":190,"column":4}}},"8":{"name":"_queryBuyBaseToken","line":192,"loc":{"start":{"line":192,"column":4},"end":{"line":243,"column":4}}}},"statementMap":{"1":{"start":{"line":38,"column":8},"end":{"line":38,"column":52}},"2":{"start":{"line":43,"column":8},"end":{"line":43,"column":68}},"3":{"start":{"line":57,"column":8},"end":{"line":57,"column":1426}},"4":{"start":{"line":65,"column":8},"end":{"line":65,"column":79}},"5":{"start":{"line":68,"column":8},"end":{"line":68,"column":47}},"6":{"start":{"line":69,"column":8},"end":{"line":69,"column":55}},"7":{"start":{"line":70,"column":8},"end":{"line":70,"column":55}},"8":{"start":{"line":73,"column":8},"end":{"line":73,"column":51}},"9":{"start":{"line":74,"column":8},"end":{"line":74,"column":49}},"10":{"start":{"line":75,"column":8},"end":{"line":75,"column":30}},"11":{"start":{"line":77,"column":8},"end":{"line":77,"column":36}},"12":{"start":{"line":78,"column":8},"end":{"line":78,"column":60}},"13":{"start":{"line":79,"column":8},"end":{"line":79,"column":45}},"14":{"start":{"line":81,"column":8},"end":{"line":81,"column":27}},"15":{"start":{"line":92,"column":8},"end":{"line":92,"column":2510}},"16":{"start":{"line":100,"column":8},"end":{"line":100,"column":65}},"17":{"start":{"line":103,"column":8},"end":{"line":103,"column":50}},"18":{"start":{"line":104,"column":8},"end":{"line":104,"column":48}},"19":{"start":{"line":105,"column":8},"end":{"line":105,"column":53}},"20":{"start":{"line":108,"column":8},"end":{"line":108,"column":51}},"21":{"start":{"line":109,"column":8},"end":{"line":109,"column":49}},"22":{"start":{"line":110,"column":8},"end":{"line":110,"column":30}},"23":{"start":{"line":112,"column":8},"end":{"line":112,"column":34}},"24":{"start":{"line":113,"column":8},"end":{"line":113,"column":55}},"25":{"start":{"line":114,"column":8},"end":{"line":114,"column":43}},"26":{"start":{"line":116,"column":8},"end":{"line":116,"column":23}},"27":{"start":{"line":122,"column":8},"end":{"line":122,"column":61}},"28":{"start":{"line":123,"column":8},"end":{"line":123,"column":27}},"29":{"start":{"line":127,"column":8},"end":{"line":127,"column":56}},"30":{"start":{"line":128,"column":8},"end":{"line":128,"column":23}},"31":{"start":{"line":143,"column":8},"end":{"line":143,"column":61}},"32":{"start":{"line":145,"column":8},"end":{"line":145,"column":39}},"33":{"start":{"line":147,"column":8},"end":{"line":147,"column":4174}},"34":{"start":{"line":150,"column":12},"end":{"line":150,"column":76}},"35":{"start":{"line":151,"column":12},"end":{"line":151,"column":47}},"36":{"start":{"line":152,"column":15},"end":{"line":152,"column":4417}},"37":{"start":{"line":153,"column":12},"end":{"line":153,"column":72}},"38":{"start":{"line":154,"column":12},"end":{"line":154,"column":79}},"39":{"start":{"line":157,"column":12},"end":{"line":157,"column":4724}},"40":{"start":{"line":159,"column":16},"end":{"line":159,"column":97}},"41":{"start":{"line":160,"column":16},"end":{"line":160,"column":51}},"42":{"start":{"line":161,"column":16},"end":{"line":161,"column":4991}},"43":{"start":{"line":164,"column":20},"end":{"line":164,"column":55}},"44":{"start":{"line":166,"column":19},"end":{"line":166,"column":5393}},"45":{"start":{"line":168,"column":16},"end":{"line":168,"column":51}},"46":{"start":{"line":169,"column":16},"end":{"line":169,"column":45}},"47":{"start":{"line":172,"column":16},"end":{"line":172,"column":5690}},"48":{"start":{"line":175,"column":16},"end":{"line":175,"column":51}},"49":{"start":{"line":180,"column":12},"end":{"line":180,"column":95}},"50":{"start":{"line":181,"column":12},"end":{"line":181,"column":47}},"51":{"start":{"line":185,"column":8},"end":{"line":185,"column":64}},"52":{"start":{"line":186,"column":8},"end":{"line":186,"column":64}},"53":{"start":{"line":187,"column":8},"end":{"line":187,"column":66}},"54":{"start":{"line":189,"column":8},"end":{"line":189,"column":96}},"55":{"start":{"line":204,"column":8},"end":{"line":204,"column":61}},"56":{"start":{"line":207,"column":8},"end":{"line":207,"column":57}},"57":{"start":{"line":208,"column":8},"end":{"line":208,"column":57}},"58":{"start":{"line":209,"column":8},"end":{"line":209,"column":68}},"59":{"start":{"line":211,"column":8},"end":{"line":211,"column":7114}},"60":{"start":{"line":213,"column":12},"end":{"line":213,"column":69}},"61":{"start":{"line":214,"column":12},"end":{"line":214,"column":47}},"62":{"start":{"line":215,"column":15},"end":{"line":215,"column":7317}},"63":{"start":{"line":217,"column":12},"end":{"line":217,"column":87}},"64":{"start":{"line":218,"column":12},"end":{"line":218,"column":47}},"65":{"start":{"line":219,"column":15},"end":{"line":219,"column":7544}},"66":{"start":{"line":220,"column":12},"end":{"line":220,"column":75}},"67":{"start":{"line":221,"column":12},"end":{"line":221,"column":76}},"68":{"start":{"line":224,"column":12},"end":{"line":224,"column":7836}},"69":{"start":{"line":227,"column":16},"end":{"line":227,"column":93}},"70":{"start":{"line":228,"column":16},"end":{"line":228,"column":51}},"71":{"start":{"line":229,"column":19},"end":{"line":229,"column":8197}},"72":{"start":{"line":231,"column":16},"end":{"line":231,"column":43}},"73":{"start":{"line":232,"column":16},"end":{"line":232,"column":45}},"74":{"start":{"line":235,"column":16},"end":{"line":235,"column":8489}},"75":{"start":{"line":238,"column":16},"end":{"line":238,"column":51}},"76":{"start":{"line":242,"column":8},"end":{"line":242,"column":90}}},"branchMap":{"1":{"line":38,"type":"if","locations":[{"start":{"line":38,"column":8},"end":{"line":38,"column":8}},{"start":{"line":38,"column":8},"end":{"line":38,"column":8}}]},"2":{"line":43,"type":"if","locations":[{"start":{"line":43,"column":8},"end":{"line":43,"column":8}},{"start":{"line":43,"column":8},"end":{"line":43,"column":8}}]},"3":{"line":65,"type":"if","locations":[{"start":{"line":65,"column":8},"end":{"line":65,"column":8}},{"start":{"line":65,"column":8},"end":{"line":65,"column":8}}]},"4":{"line":100,"type":"if","locations":[{"start":{"line":100,"column":8},"end":{"line":100,"column":8}},{"start":{"line":100,"column":8},"end":{"line":100,"column":8}}]},"5":{"line":147,"type":"if","locations":[{"start":{"line":147,"column":8},"end":{"line":147,"column":8}},{"start":{"line":147,"column":8},"end":{"line":147,"column":8}}]},"6":{"line":152,"type":"if","locations":[{"start":{"line":152,"column":15},"end":{"line":152,"column":15}},{"start":{"line":152,"column":15},"end":{"line":152,"column":15}}]},"7":{"line":157,"type":"if","locations":[{"start":{"line":157,"column":12},"end":{"line":157,"column":12}},{"start":{"line":157,"column":12},"end":{"line":157,"column":12}}]},"8":{"line":161,"type":"if","locations":[{"start":{"line":161,"column":16},"end":{"line":161,"column":16}},{"start":{"line":161,"column":16},"end":{"line":161,"column":16}}]},"9":{"line":166,"type":"if","locations":[{"start":{"line":166,"column":19},"end":{"line":166,"column":19}},{"start":{"line":166,"column":19},"end":{"line":166,"column":19}}]},"10":{"line":211,"type":"if","locations":[{"start":{"line":211,"column":8},"end":{"line":211,"column":8}},{"start":{"line":211,"column":8},"end":{"line":211,"column":8}}]},"11":{"line":215,"type":"if","locations":[{"start":{"line":215,"column":15},"end":{"line":215,"column":15}},{"start":{"line":215,"column":15},"end":{"line":215,"column":15}}]},"12":{"line":219,"type":"if","locations":[{"start":{"line":219,"column":15},"end":{"line":219,"column":15}},{"start":{"line":219,"column":15},"end":{"line":219,"column":15}}]},"13":{"line":224,"type":"if","locations":[{"start":{"line":224,"column":12},"end":{"line":224,"column":12}},{"start":{"line":224,"column":12},"end":{"line":224,"column":12}}]},"14":{"line":229,"type":"if","locations":[{"start":{"line":229,"column":19},"end":{"line":229,"column":19}},{"start":{"line":229,"column":19},"end":{"line":229,"column":19}}]}}},"contracts/lib/DODOMath.sol":{"l":{"37":43,"38":43,"39":43,"40":43,"41":43,"67":28,"68":28,"69":28,"70":28,"71":2,"73":26,"75":28,"76":22,"77":22,"79":6,"80":6,"84":28,"88":28,"91":28,"92":28,"93":22,"95":6,"111":115,"112":115,"113":115,"115":115},"path":"/Users/leimingda/Documents/dodo/contracts/lib/DODOMath.sol","s":{"1":43,"2":43,"3":43,"4":43,"5":43,"6":28,"7":28,"8":28,"9":28,"10":2,"11":26,"12":28,"13":22,"14":22,"15":6,"16":6,"17":28,"18":28,"19":28,"20":28,"21":22,"22":6,"23":115,"24":115,"25":115,"26":115},"b":{"1":[2,26],"2":[22,6],"3":[22,6]},"f":{"1":43,"2":28,"3":115},"fnMap":{"1":{"name":"_GeneralIntegrate","line":30,"loc":{"start":{"line":30,"column":4},"end":{"line":42,"column":4}}},"2":{"name":"_SolveQuadraticFunctionForTrade","line":58,"loc":{"start":{"line":58,"column":4},"end":{"line":97,"column":4}}},"3":{"name":"_SolveQuadraticFunctionForTarget","line":105,"loc":{"start":{"line":105,"column":4},"end":{"line":116,"column":4}}}},"statementMap":{"1":{"start":{"line":37,"column":8},"end":{"line":37,"column":59}},"2":{"start":{"line":38,"column":8},"end":{"line":38,"column":50}},"3":{"start":{"line":39,"column":8},"end":{"line":39,"column":50}},"4":{"start":{"line":40,"column":8},"end":{"line":40,"column":73}},"5":{"start":{"line":41,"column":8},"end":{"line":41,"column":79}},"6":{"start":{"line":67,"column":8},"end":{"line":67,"column":63}},"7":{"start":{"line":68,"column":8},"end":{"line":68,"column":63}},"8":{"start":{"line":69,"column":8},"end":{"line":69,"column":29}},"9":{"start":{"line":70,"column":8},"end":{"line":70,"column":2147}},"10":{"start":{"line":71,"column":12},"end":{"line":71,"column":29}},"11":{"start":{"line":73,"column":12},"end":{"line":73,"column":39}},"12":{"start":{"line":75,"column":8},"end":{"line":75,"column":2318}},"13":{"start":{"line":76,"column":12},"end":{"line":76,"column":28}},"14":{"start":{"line":77,"column":12},"end":{"line":77,"column":27}},"15":{"start":{"line":79,"column":12},"end":{"line":79,"column":28}},"16":{"start":{"line":80,"column":12},"end":{"line":80,"column":28}},"17":{"start":{"line":84,"column":8},"end":{"line":84,"column":2523}},"18":{"start":{"line":88,"column":8},"end":{"line":88,"column":51}},"19":{"start":{"line":91,"column":8},"end":{"line":91,"column":59}},"20":{"start":{"line":92,"column":8},"end":{"line":92,"column":2853}},"21":{"start":{"line":93,"column":12},"end":{"line":93,"column":71}},"22":{"start":{"line":95,"column":12},"end":{"line":95,"column":71}},"23":{"start":{"line":111,"column":8},"end":{"line":111,"column":86}},"24":{"start":{"line":112,"column":8},"end":{"line":112,"column":67}},"25":{"start":{"line":113,"column":8},"end":{"line":113,"column":83}},"26":{"start":{"line":115,"column":8},"end":{"line":115,"column":64}}},"branchMap":{"1":{"line":70,"type":"if","locations":[{"start":{"line":70,"column":8},"end":{"line":70,"column":8}},{"start":{"line":70,"column":8},"end":{"line":70,"column":8}}]},"2":{"line":75,"type":"if","locations":[{"start":{"line":75,"column":8},"end":{"line":75,"column":8}},{"start":{"line":75,"column":8},"end":{"line":75,"column":8}}]},"3":{"line":92,"type":"if","locations":[{"start":{"line":92,"column":8},"end":{"line":92,"column":8}},{"start":{"line":92,"column":8},"end":{"line":92,"column":8}}]}}},"contracts/lib/SafeERC20.sol":{"l":{"33":182,"42":153,"65":335,"66":335,"68":335,"71":335},"path":"/Users/leimingda/Documents/dodo/contracts/lib/SafeERC20.sol","s":{"1":182,"2":153,"3":335,"4":335,"5":335,"6":335},"b":{"1":[335,0],"2":[335,0],"3":[335,0]},"f":{"1":182,"2":153,"3":335},"fnMap":{"1":{"name":"safeTransfer","line":28,"loc":{"start":{"line":28,"column":4},"end":{"line":34,"column":4}}},"2":{"name":"safeTransferFrom","line":36,"loc":{"start":{"line":36,"column":4},"end":{"line":46,"column":4}}},"3":{"name":"_callOptionalReturn","line":54,"loc":{"start":{"line":54,"column":4},"end":{"line":73,"column":4}}}},"statementMap":{"1":{"start":{"line":33,"column":8},"end":{"line":33,"column":93}},"2":{"start":{"line":42,"column":8},"end":{"line":42,"column":1162}},"3":{"start":{"line":65,"column":8},"end":{"line":65,"column":75}},"4":{"start":{"line":66,"column":8},"end":{"line":66,"column":59}},"5":{"start":{"line":68,"column":8},"end":{"line":68,"column":2470}},"6":{"start":{"line":71,"column":12},"end":{"line":71,"column":96}}},"branchMap":{"1":{"line":66,"type":"if","locations":[{"start":{"line":66,"column":8},"end":{"line":66,"column":8}},{"start":{"line":66,"column":8},"end":{"line":66,"column":8}}]},"2":{"line":68,"type":"if","locations":[{"start":{"line":68,"column":8},"end":{"line":68,"column":8}},{"start":{"line":68,"column":8},"end":{"line":68,"column":8}}]},"3":{"line":71,"type":"if","locations":[{"start":{"line":71,"column":12},"end":{"line":71,"column":12}},{"start":{"line":71,"column":12},"end":{"line":71,"column":12}}]}}}} \ No newline at end of file diff --git a/package.json b/package.json index 123c39c..f1e1b3d 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "scripts": { "prettier": "prettier --write **/*.sol", "migrate": "truffle migrate", - "compile": "truffle compile", + "compile": "rm -r build && truffle compile", "coverage": "NETWORK_ID=1002 RPC_NODE_URI=http://127.0.0.1:6545 COVERAGE=true truffle run coverage", "test": "truffle compile && truffle test", "test_only": "truffle test", diff --git a/test/Admin.test.ts b/test/Admin.test.ts index f559996..44080e5 100644 --- a/test/Admin.test.ts +++ b/test/Admin.test.ts @@ -89,7 +89,7 @@ describe("Admin", () => { await ctx.DODO.methods.disableBaseDeposit().send(ctx.sendParam(ctx.Supervisor)) await assert.rejects( ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)), - /DEPOSIT_BASE_NOT_ALLOWED/ + /DEPOSIT_BASE_TOKEN_NOT_ALLOWED/ ) await ctx.DODO.methods.enableBaseDeposit().send(ctx.sendParam(ctx.Deployer)) @@ -99,7 +99,7 @@ describe("Admin", () => { await ctx.DODO.methods.disableQuoteDeposit().send(ctx.sendParam(ctx.Supervisor)) await assert.rejects( ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)), - /DEPOSIT_QUOTE_NOT_ALLOWED/ + /DEPOSIT_QUOTE_TOKEN_NOT_ALLOWED/ ) await ctx.DODO.methods.enableQuoteDeposit().send(ctx.sendParam(ctx.Deployer)) diff --git a/test/LiquidityProvider.test.ts b/test/LiquidityProvider.test.ts index c672875..658c318 100644 --- a/test/LiquidityProvider.test.ts +++ b/test/LiquidityProvider.test.ts @@ -386,7 +386,7 @@ describe("LiquidityProvider", () => { await assert.rejects( ctx.DODO.methods.getWithdrawBasePenalty(decimalStr("10")).call(), - /DODO_BASE_BALANCE_NOT_ENOUGH/ + /DODO_BASE_TOKEN_BALANCE_NOT_ENOUGH/ ) }) @@ -401,7 +401,7 @@ describe("LiquidityProvider", () => { await assert.rejects( ctx.DODO.methods.getWithdrawQuotePenalty(decimalStr("1000")).call(), - /DODO_QUOTE_BALANCE_NOT_ENOUGH/ + /DODO_QUOTE_TOKEN_BALANCE_NOT_ENOUGH/ ) }) @@ -441,6 +441,17 @@ describe("LiquidityProvider", () => { /LP_QUOTE_CAPITAL_BALANCE_NOT_ENOUGH/ ) }) + + it("withdraw when there is no lp", async () => { + await assert.rejects( + ctx.DODO.methods.withdrawBase(decimalStr("1")).send(ctx.sendParam(lp1)), + /NO_BASE_LP/ + ) + await assert.rejects( + ctx.DODO.methods.withdrawQuote(decimalStr("1")).send(ctx.sendParam(lp1)), + /NO_QUOTE_LP/ + ) + }) }) }) \ No newline at end of file diff --git a/test/Trader.test.ts b/test/Trader.test.ts index 68a1b70..1fbbd59 100644 --- a/test/Trader.test.ts +++ b/test/Trader.test.ts @@ -60,7 +60,7 @@ describe("Trader", () => { assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "1101418160497943759027") }) - it.only("buy when R is ABOVE ONE", async () => { + it("buy when R is ABOVE ONE", async () => { await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110")).send(ctx.sendParam(trader)) await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("130")).send(ctx.sendParam(trader)) // trader balances From ee88b6c35833cb5198141a59bed42c9d6ac94d92 Mon Sep 17 00:00:00 2001 From: mingda Date: Fri, 26 Jun 2020 17:05:22 +0800 Subject: [PATCH 007/118] simplify migrate script --- .env | 2 +- migrations/2_deploy.js | 22 +- package.json | 1 + yarn.lock | 1217 ++++++++++++++++++++++++++++++++++++++-- 4 files changed, 1190 insertions(+), 52 deletions(-) diff --git a/.env b/.env index c237685..0dab5f0 100644 --- a/.env +++ b/.env @@ -1,4 +1,4 @@ RPC_NODE_URI=http://127.0.0.1:8545 RESET_SNAPSHOT_ID=0x2 NETWORK_ID=5777 -GAS_PRICE=1 +GAS_PRICE=1 \ No newline at end of file diff --git a/migrations/2_deploy.js b/migrations/2_deploy.js index 943d7be..39dc335 100644 --- a/migrations/2_deploy.js +++ b/migrations/2_deploy.js @@ -1,27 +1,11 @@ -const DecimalMath = artifacts.require("DecimalMath"); -const SafeERC20 = artifacts.require("SafeERC20"); -const DODOMath = artifacts.require("DODOMath"); -const DODO = artifacts.require("DODO"); const DODOZoo = artifacts.require("DODOZoo"); module.exports = async (deployer, network) => { - const deployDODO = async () => { - await deployer.deploy(DecimalMath); - await deployer.deploy(SafeERC20); - await deployer.deploy(DODOMath); - - await deployer.link(SafeERC20, DODO); - await deployer.link(DecimalMath, DODO); - await deployer.link(DODOMath, DODO); - - await deployer.deploy(DODO); + const deployDODOZoo = async () => { await deployer.deploy(DODOZoo); }; - if (network == "production") { - } else if (network == "kovan") { - } else { - // for development & test - await deployDODO(); + if (network == "development") { + await deployDODOZoo(); } }; diff --git a/package.json b/package.json index f1e1b3d..ff6f3e9 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "web3-eth-contract": "^1.2.8" }, "devDependencies": { + "@truffle/hdwallet-provider": "^1.0.36", "ganache-cli": "^6.9.1", "prettier": "^2.0.5", "prettier-plugin-solidity": "^1.0.0-alpha.52", diff --git a/yarn.lock b/yarn.lock index f554761..1739e46 100644 --- a/yarn.lock +++ b/yarn.lock @@ -31,6 +31,16 @@ dependencies: "@babel/types" "^7.10.1" +"@babel/helper-module-imports@^7.10.3": + version "7.10.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.3.tgz#766fa1d57608e53e5676f23ae498ec7a95e1b11a" + dependencies: + "@babel/types" "^7.10.3" + +"@babel/helper-plugin-utils@^7.10.3": + version "7.10.3" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.3.tgz#aac45cccf8bc1873b99a85f34bceef3beb5d3244" + "@babel/helper-split-export-declaration@^7.10.1": version "7.10.1" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.1.tgz#c6f4be1cbc15e3a868e4c64a17d5d31d754da35f" @@ -41,6 +51,10 @@ version "7.10.1" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.1.tgz#5770b0c1a826c4f53f5ede5e153163e0318e94b5" +"@babel/helper-validator-identifier@^7.10.3": + version "7.10.3" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.3.tgz#60d9847f98c4cea1b279e005fdb7c28be5412d15" + "@babel/highlight@^7.10.1": version "7.10.1" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.1.tgz#841d098ba613ba1a427a2b383d79e35552c38ae0" @@ -53,6 +67,21 @@ version "7.10.2" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.10.2.tgz#871807f10442b92ff97e4783b9b54f6a0ca812d0" +"@babel/plugin-transform-runtime@^7.5.5": + version "7.10.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.10.3.tgz#3b287b06acc534a7cb6e6c71d6b1d88b1922dd6c" + dependencies: + "@babel/helper-module-imports" "^7.10.3" + "@babel/helper-plugin-utils" "^7.10.3" + resolve "^1.8.1" + semver "^5.5.1" + +"@babel/runtime@^7.5.5": + version "7.10.3" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.3.tgz#670d002655a7c366540c67f6fd3342cd09500364" + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@^7.10.1": version "7.10.1" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.1.tgz#e167154a94cb5f14b28dc58f5356d2162f539811" @@ -83,6 +112,14 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" +"@babel/types@^7.10.3": + version "7.10.3" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.10.3.tgz#6535e3b79fea86a6b09e012ea8528f935099de8e" + dependencies: + "@babel/helper-validator-identifier" "^7.10.3" + lodash "^4.17.13" + to-fast-properties "^2.0.0" + "@ethersproject/abi@5.0.0-beta.153": version "5.0.0-beta.153" resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.0.0-beta.153.tgz#43a37172b33794e4562999f6e2d555b7599a8eee" @@ -206,6 +243,21 @@ version "0.0.7" resolved "https://registry.yarnpkg.com/@truffle/error/-/error-0.0.7.tgz#e9db39885575647ef08bf624b0c13fe46d41a209" +"@truffle/hdwallet-provider@^1.0.36": + version "1.0.36" + resolved "https://registry.yarnpkg.com/@truffle/hdwallet-provider/-/hdwallet-provider-1.0.36.tgz#d8f2abec2004a3174c0c62f5d5e01a792c894fdc" + dependencies: + "@trufflesuite/web3-provider-engine" "14.0.6" + any-promise "^1.3.0" + bindings "^1.5.0" + bip39 "^2.4.2" + ethereum-protocol "^1.0.1" + ethereumjs-tx "^1.0.0" + ethereumjs-util "^6.1.0" + ethereumjs-wallet "^0.6.3" + source-map-support "^0.5.19" + web3 "1.2.1" + "@truffle/interface-adapter@^0.3.0": version "0.3.3" resolved "https://registry.yarnpkg.com/@truffle/interface-adapter/-/interface-adapter-0.3.3.tgz#61305378cf81776769ef36c60d394e568ac4a2ee" @@ -223,6 +275,33 @@ "@truffle/interface-adapter" "^0.3.0" web3 "1.2.1" +"@trufflesuite/web3-provider-engine@14.0.6": + version "14.0.6" + resolved "https://registry.yarnpkg.com/@trufflesuite/web3-provider-engine/-/web3-provider-engine-14.0.6.tgz#024d192cde9534a778e5d2436be1caf3c553a2e0" + dependencies: + async "^2.5.0" + backoff "^2.5.0" + clone "^2.0.0" + cross-fetch "^2.1.0" + eth-block-tracker "^4.2.0" + eth-json-rpc-filters "^4.0.2" + eth-json-rpc-infura "^3.1.0" + eth-json-rpc-middleware "^4.1.1" + eth-sig-util "^1.4.2" + ethereumjs-block "^1.2.2" + ethereumjs-tx "^1.2.0" + ethereumjs-util "^5.1.5" + ethereumjs-vm "^2.3.4" + json-rpc-error "^2.0.0" + json-stable-stringify "^1.0.1" + promise-to-callback "^1.0.0" + readable-stream "^2.2.9" + request "^2.85.0" + semaphore "^1.0.3" + ws "^5.1.1" + xhr "^2.2.0" + xtend "^4.0.1" + "@types/bn.js@^4.11.3", "@types/bn.js@^4.11.4": version "4.11.6" resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c" @@ -294,6 +373,18 @@ abbrev@1.0.x: version "1.0.9" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" +abstract-leveldown@~2.6.0: + version "2.6.3" + resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-2.6.3.tgz#1c5e8c6a5ef965ae8c35dfb3a8770c476b82c4b8" + dependencies: + xtend "~4.0.0" + +abstract-leveldown@~2.7.1: + version "2.7.2" + resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-2.7.2.tgz#87a44d7ebebc341d59665204834c8b7e0932cc93" + dependencies: + xtend "~4.0.0" + accepts@~1.3.7: version "1.3.7" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" @@ -309,6 +400,10 @@ aes-js@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" +aes-js@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.1.2.tgz#db9aabde85d5caabbfc0d4f2a4446960f627146a" + ajv@^6.5.5: version "6.12.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.2.tgz#c629c5eced17baf314437918d2da88c99d5958cd" @@ -457,14 +552,26 @@ async-each@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" +async-eventemitter@^0.2.2: + version "0.2.4" + resolved "https://registry.yarnpkg.com/async-eventemitter/-/async-eventemitter-0.2.4.tgz#f5e7c8ca7d3e46aab9ec40a292baf686a0bafaca" + dependencies: + async "^2.4.0" + async-limiter@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" -async@1.x: +async@1.x, async@^1.4.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" +async@^2.0.1, async@^2.1.2, async@^2.4.0, async@^2.5.0: + version "2.6.3" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" + dependencies: + lodash "^4.17.14" + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -479,6 +586,10 @@ available-typed-arrays@^1.0.0, available-typed-arrays@^1.0.2: dependencies: array-filter "^1.0.0" +await-semaphore@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/await-semaphore/-/await-semaphore-0.1.3.tgz#2b88018cc8c28e06167ae1cdff02504f1f9688d3" + aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" @@ -516,7 +627,7 @@ babel-code-frame@^6.26.0: esutils "^2.0.2" js-tokens "^3.0.2" -babel-core@^6.26.0: +babel-core@^6.0.14, babel-core@^6.26.0: version "6.26.3" resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" dependencies: @@ -564,6 +675,100 @@ babel-generator@^6.26.0: source-map "^0.5.7" trim-right "^1.0.1" +babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" + dependencies: + babel-helper-explode-assignable-expression "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-call-delegate@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-define-map@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-explode-assignable-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-function-name@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" + dependencies: + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-get-function-arity@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-hoist-variables@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-optimise-call-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-regex@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" + dependencies: + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-remap-async-to-generator@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-replace-supers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" + dependencies: + babel-helper-optimise-call-expression "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + babel-helpers@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" @@ -577,6 +782,221 @@ babel-messages@^6.23.0: dependencies: babel-runtime "^6.22.0" +babel-plugin-check-es2015-constants@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-syntax-async-functions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" + +babel-plugin-syntax-exponentiation-operator@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" + +babel-plugin-syntax-trailing-function-commas@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" + +babel-plugin-transform-async-to-generator@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" + dependencies: + babel-helper-remap-async-to-generator "^6.24.1" + babel-plugin-syntax-async-functions "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-arrow-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoping@^6.23.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" + dependencies: + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-plugin-transform-es2015-classes@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" + dependencies: + babel-helper-define-map "^6.24.1" + babel-helper-function-name "^6.24.1" + babel-helper-optimise-call-expression "^6.24.1" + babel-helper-replace-supers "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-computed-properties@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-destructuring@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-duplicate-keys@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-for-of@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-function-name@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" + dependencies: + babel-plugin-transform-es2015-modules-commonjs "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: + version "6.26.2" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz#58a793863a9e7ca870bdc5a881117ffac27db6f3" + dependencies: + babel-plugin-transform-strict-mode "^6.24.1" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-types "^6.26.0" + +babel-plugin-transform-es2015-modules-systemjs@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-modules-umd@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" + dependencies: + babel-plugin-transform-es2015-modules-amd "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-object-super@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" + dependencies: + babel-helper-replace-supers "^6.24.1" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-parameters@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" + dependencies: + babel-helper-call-delegate "^6.24.1" + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-shorthand-properties@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-spread@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-sticky-regex@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-template-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-typeof-symbol@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-unicode-regex@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + regexpu-core "^2.0.0" + +babel-plugin-transform-exponentiation-operator@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" + dependencies: + babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" + babel-plugin-syntax-exponentiation-operator "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-regenerator@^6.22.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" + dependencies: + regenerator-transform "^0.10.0" + +babel-plugin-transform-strict-mode@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + babel-polyfill@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" @@ -585,6 +1005,41 @@ babel-polyfill@^6.26.0: core-js "^2.5.0" regenerator-runtime "^0.10.5" +babel-preset-env@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.7.0.tgz#dea79fa4ebeb883cd35dab07e260c1c9c04df77a" + dependencies: + babel-plugin-check-es2015-constants "^6.22.0" + babel-plugin-syntax-trailing-function-commas "^6.22.0" + babel-plugin-transform-async-to-generator "^6.22.0" + babel-plugin-transform-es2015-arrow-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoping "^6.23.0" + babel-plugin-transform-es2015-classes "^6.23.0" + babel-plugin-transform-es2015-computed-properties "^6.22.0" + babel-plugin-transform-es2015-destructuring "^6.23.0" + babel-plugin-transform-es2015-duplicate-keys "^6.22.0" + babel-plugin-transform-es2015-for-of "^6.23.0" + babel-plugin-transform-es2015-function-name "^6.22.0" + babel-plugin-transform-es2015-literals "^6.22.0" + babel-plugin-transform-es2015-modules-amd "^6.22.0" + babel-plugin-transform-es2015-modules-commonjs "^6.23.0" + babel-plugin-transform-es2015-modules-systemjs "^6.23.0" + babel-plugin-transform-es2015-modules-umd "^6.23.0" + babel-plugin-transform-es2015-object-super "^6.22.0" + babel-plugin-transform-es2015-parameters "^6.23.0" + babel-plugin-transform-es2015-shorthand-properties "^6.22.0" + babel-plugin-transform-es2015-spread "^6.22.0" + babel-plugin-transform-es2015-sticky-regex "^6.22.0" + babel-plugin-transform-es2015-template-literals "^6.22.0" + babel-plugin-transform-es2015-typeof-symbol "^6.23.0" + babel-plugin-transform-es2015-unicode-regex "^6.22.0" + babel-plugin-transform-exponentiation-operator "^6.22.0" + babel-plugin-transform-regenerator "^6.22.0" + browserslist "^3.2.6" + invariant "^2.2.2" + semver "^5.3.0" + babel-register@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" @@ -597,7 +1052,7 @@ babel-register@^6.26.0: mkdirp "^0.5.1" source-map-support "^0.4.15" -babel-runtime@^6.22.0, babel-runtime@^6.26.0: +babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" dependencies: @@ -614,7 +1069,7 @@ babel-template@^6.24.1, babel-template@^6.26.0: babylon "^6.18.0" lodash "^4.17.4" -babel-traverse@^6.26.0: +babel-traverse@^6.24.1, babel-traverse@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" dependencies: @@ -628,7 +1083,7 @@ babel-traverse@^6.26.0: invariant "^2.2.2" lodash "^4.17.4" -babel-types@^6.26.0: +babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" dependencies: @@ -637,15 +1092,28 @@ babel-types@^6.26.0: lodash "^4.17.4" to-fast-properties "^1.0.3" +babelify@^7.3.0: + version "7.3.0" + resolved "https://registry.yarnpkg.com/babelify/-/babelify-7.3.0.tgz#aa56aede7067fd7bd549666ee16dc285087e88e5" + dependencies: + babel-core "^6.0.14" + object-assign "^4.0.0" + babylon@^6.18.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" +backoff@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/backoff/-/backoff-2.5.0.tgz#f616eda9d3e4b66b8ca7fca79f695722c5f8e26f" + dependencies: + precond "0.2" + balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" -base-x@^3.0.8: +base-x@^3.0.2, base-x@^3.0.8: version "3.0.8" resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.8.tgz#1e1106c2537f0162e8b52474a557ebb09000018d" dependencies: @@ -691,6 +1159,16 @@ bindings@^1.2.1, bindings@^1.3.1, bindings@^1.5.0: dependencies: file-uri-to-path "1.0.0" +bip39@^2.4.2: + version "2.6.0" + resolved "https://registry.yarnpkg.com/bip39/-/bip39-2.6.0.tgz#9e3a720b42ec8b3fbe4038f1e445317b6a99321c" + dependencies: + create-hash "^1.1.0" + pbkdf2 "^3.0.9" + randombytes "^2.0.1" + safe-buffer "^5.0.1" + unorm "^1.3.3" + bip66@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/bip66/-/bip66-1.1.5.tgz#01fa8748785ca70955d5011217d1b3139969ca22" @@ -832,6 +1310,31 @@ browserify-sign@^4.0.0: readable-stream "^3.6.0" safe-buffer "^5.2.0" +browserslist@^3.2.6: + version "3.2.8" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-3.2.8.tgz#b0005361d6471f0f5952797a76fc985f1f978fc6" + dependencies: + caniuse-lite "^1.0.30000844" + electron-to-chromium "^1.3.47" + +bs58@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" + dependencies: + base-x "^3.0.2" + +bs58check@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc" + dependencies: + bs58 "^4.0.0" + create-hash "^1.1.0" + safe-buffer "^5.1.2" + +btoa@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/btoa/-/btoa-1.2.1.tgz#01a9909f8b2c93f6bf680ba26131eb30f7fa3d73" + buffer-alloc-unsafe@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" @@ -904,6 +1407,10 @@ camelcase@^5.0.0: version "5.3.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" +caniuse-lite@^1.0.30000844: + version "1.0.30001088" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001088.tgz#23a6b9e192106107458528858f2c0e0dba0d9073" + caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" @@ -945,6 +1452,12 @@ check-error@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" +checkpoint-store@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/checkpoint-store/-/checkpoint-store-1.1.0.tgz#04e4cb516b91433893581e6d4601a78e9552ea06" + dependencies: + functional-red-black-tree "^1.0.1" + chokidar@3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.0.tgz#12c0714668c55800f659e262d4962a97faf554a6" @@ -1022,6 +1535,10 @@ clone-response@^1.0.2: dependencies: mimic-response "^1.0.0" +clone@^2.0.0, clone@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + collection-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" @@ -1063,6 +1580,15 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" +concat-stream@^1.5.1: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + content-disposition@0.5.3: version "0.5.3" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" @@ -1146,6 +1672,13 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: safe-buffer "^5.0.1" sha.js "^2.4.8" +cross-fetch@^2.1.0, cross-fetch@^2.1.1: + version "2.2.3" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-2.2.3.tgz#e8a0b3c54598136e037f8650f8e823ccdfac198e" + dependencies: + node-fetch "2.1.2" + whatwg-fetch "2.0.4" + cross-spawn@^6.0.0: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" @@ -1275,6 +1808,17 @@ deep-eql@^3.0.1: dependencies: type-detect "^4.0.0" +deep-equal@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" + dependencies: + is-arguments "^1.0.4" + is-date-object "^1.0.1" + is-regex "^1.0.4" + object-is "^1.0.1" + object-keys "^1.1.1" + regexp.prototype.flags "^1.2.0" + deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" @@ -1283,6 +1827,12 @@ defer-to-connect@^1.0.1: version "1.1.3" resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" +deferred-leveldown@~1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-1.2.2.tgz#3acd2e0b75d1669924bc0a4b642851131173e1eb" + dependencies: + abstract-leveldown "~2.6.0" + define-properties@^1.1.2, define-properties@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -1308,6 +1858,10 @@ define-property@^2.0.2: is-descriptor "^1.0.2" isobject "^3.0.1" +defined@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -1380,6 +1934,12 @@ dotenv@^8.0.0: version "8.2.0" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" +dotignore@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/dotignore/-/dotignore-0.1.2.tgz#f942f2200d28c3a76fbdd6f0ee9f3257c8a2e905" + dependencies: + minimatch "^3.0.4" + drbg.js@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/drbg.js/-/drbg.js-1.0.1.tgz#3e36b6c42b37043823cdbc332d58f31e2445480b" @@ -1403,6 +1963,10 @@ ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" +electron-to-chromium@^1.3.47: + version "1.3.483" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.483.tgz#9269e7cfc1c8e72709824da171cbe47ca5e3ca9e" + elliptic@6.3.3: version "6.3.3" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.3.3.tgz#5482d9646d54bcb89fd7d994fc9e2e9568876e3f" @@ -1440,12 +2004,24 @@ encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" +encoding@^0.1.11: + version "0.1.12" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + dependencies: + iconv-lite "~0.4.13" + end-of-stream@^1.0.0, end-of-stream@^1.1.0: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" dependencies: once "^1.4.0" +errno@~0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" + dependencies: + prr "~1.0.1" + es-abstract@^1.17.0-next.1, es-abstract@^1.17.4, es-abstract@^1.17.5: version "1.17.5" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.5.tgz#d8c9d1d66c8981fb9200e2251d799eee92774ae9" @@ -1554,6 +2130,17 @@ etag@~1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" +eth-block-tracker@^4.2.0: + version "4.4.3" + resolved "https://registry.yarnpkg.com/eth-block-tracker/-/eth-block-tracker-4.4.3.tgz#766a0a0eb4a52c867a28328e9ae21353812cf626" + dependencies: + "@babel/plugin-transform-runtime" "^7.5.5" + "@babel/runtime" "^7.5.5" + eth-query "^2.1.0" + json-rpc-random-id "^1.0.1" + pify "^3.0.0" + safe-event-emitter "^1.0.1" + eth-ens-namehash@2.0.8: version "2.0.8" resolved "https://registry.yarnpkg.com/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz#229ac46eca86d52e0c991e7cb2aef83ff0f68bcf" @@ -1561,6 +2148,75 @@ eth-ens-namehash@2.0.8: idna-uts46-hx "^2.3.1" js-sha3 "^0.5.7" +eth-json-rpc-errors@^1.0.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/eth-json-rpc-errors/-/eth-json-rpc-errors-1.1.1.tgz#148377ef55155585981c21ff574a8937f9d6991f" + dependencies: + fast-safe-stringify "^2.0.6" + +eth-json-rpc-errors@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/eth-json-rpc-errors/-/eth-json-rpc-errors-2.0.2.tgz#c1965de0301fe941c058e928bebaba2e1285e3c4" + dependencies: + fast-safe-stringify "^2.0.6" + +eth-json-rpc-filters@^4.0.2: + version "4.1.1" + resolved "https://registry.yarnpkg.com/eth-json-rpc-filters/-/eth-json-rpc-filters-4.1.1.tgz#15277c66790236d85f798f4d7dc6bab99a798cd2" + dependencies: + await-semaphore "^0.1.3" + eth-json-rpc-middleware "^4.1.4" + eth-query "^2.1.2" + json-rpc-engine "^5.1.3" + lodash.flatmap "^4.5.0" + safe-event-emitter "^1.0.1" + +eth-json-rpc-infura@^3.1.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/eth-json-rpc-infura/-/eth-json-rpc-infura-3.2.1.tgz#26702a821067862b72d979c016fd611502c6057f" + dependencies: + cross-fetch "^2.1.1" + eth-json-rpc-middleware "^1.5.0" + json-rpc-engine "^3.4.0" + json-rpc-error "^2.0.0" + +eth-json-rpc-middleware@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/eth-json-rpc-middleware/-/eth-json-rpc-middleware-1.6.0.tgz#5c9d4c28f745ccb01630f0300ba945f4bef9593f" + dependencies: + async "^2.5.0" + eth-query "^2.1.2" + eth-tx-summary "^3.1.2" + ethereumjs-block "^1.6.0" + ethereumjs-tx "^1.3.3" + ethereumjs-util "^5.1.2" + ethereumjs-vm "^2.1.0" + fetch-ponyfill "^4.0.0" + json-rpc-engine "^3.6.0" + json-rpc-error "^2.0.0" + json-stable-stringify "^1.0.1" + promise-to-callback "^1.0.0" + tape "^4.6.3" + +eth-json-rpc-middleware@^4.1.1, eth-json-rpc-middleware@^4.1.4: + version "4.4.1" + resolved "https://registry.yarnpkg.com/eth-json-rpc-middleware/-/eth-json-rpc-middleware-4.4.1.tgz#07d3dd0724c24a8d31e4a172ee96271da71b4228" + dependencies: + btoa "^1.2.1" + clone "^2.1.1" + eth-json-rpc-errors "^1.0.1" + eth-query "^2.1.2" + eth-sig-util "^1.4.2" + ethereumjs-block "^1.6.0" + ethereumjs-tx "^1.3.7" + ethereumjs-util "^5.1.2" + ethereumjs-vm "^2.6.0" + fetch-ponyfill "^4.0.0" + json-rpc-engine "^5.1.3" + json-stable-stringify "^1.0.1" + pify "^3.0.0" + safe-event-emitter "^1.0.1" + eth-lib@0.2.7: version "0.2.7" resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.2.7.tgz#2f93f17b1e23aec3759cd4a3fe20c1286a3fc1ca" @@ -1588,16 +2244,99 @@ eth-lib@^0.2.8: elliptic "^6.4.0" xhr-request-promise "^0.1.2" +eth-query@^2.0.2, eth-query@^2.1.0, eth-query@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/eth-query/-/eth-query-2.1.2.tgz#d6741d9000106b51510c72db92d6365456a6da5e" + dependencies: + json-rpc-random-id "^1.0.0" + xtend "^4.0.1" + +eth-sig-util@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/eth-sig-util/-/eth-sig-util-1.4.2.tgz#8d958202c7edbaae839707fba6f09ff327606210" + dependencies: + ethereumjs-abi "git+https://github.com/ethereumjs/ethereumjs-abi.git" + ethereumjs-util "^5.1.1" + +eth-tx-summary@^3.1.2: + version "3.2.4" + resolved "https://registry.yarnpkg.com/eth-tx-summary/-/eth-tx-summary-3.2.4.tgz#e10eb95eb57cdfe549bf29f97f1e4f1db679035c" + dependencies: + async "^2.1.2" + clone "^2.0.0" + concat-stream "^1.5.1" + end-of-stream "^1.1.0" + eth-query "^2.0.2" + ethereumjs-block "^1.4.1" + ethereumjs-tx "^1.1.1" + ethereumjs-util "^5.0.1" + ethereumjs-vm "^2.6.0" + through2 "^2.0.3" + ethereum-bloom-filters@^1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.7.tgz#b7b80735e385dbb7f944ce6b4533e24511306060" dependencies: js-sha3 "^0.8.0" -ethereumjs-common@^1.3.2, ethereumjs-common@^1.5.0: +ethereum-common@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/ethereum-common/-/ethereum-common-0.2.0.tgz#13bf966131cce1eeade62a1b434249bb4cb120ca" + +ethereum-common@^0.0.18: + version "0.0.18" + resolved "https://registry.yarnpkg.com/ethereum-common/-/ethereum-common-0.0.18.tgz#2fdc3576f232903358976eb39da783213ff9523f" + +ethereum-protocol@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ethereum-protocol/-/ethereum-protocol-1.0.1.tgz#b7d68142f4105e0ae7b5e178cf42f8d4dc4b93cf" + +"ethereumjs-abi@git+https://github.com/ethereumjs/ethereumjs-abi.git": + version "0.6.8" + resolved "git+https://github.com/ethereumjs/ethereumjs-abi.git#1cfbb13862f90f0b391d8a699544d5fe4dfb8c7b" + dependencies: + bn.js "^4.11.8" + ethereumjs-util "^6.0.0" + +ethereumjs-account@^2.0.3: + version "2.0.5" + resolved "https://registry.yarnpkg.com/ethereumjs-account/-/ethereumjs-account-2.0.5.tgz#eeafc62de544cb07b0ee44b10f572c9c49e00a84" + dependencies: + ethereumjs-util "^5.0.0" + rlp "^2.0.0" + safe-buffer "^5.1.1" + +ethereumjs-block@^1.2.2, ethereumjs-block@^1.4.1, ethereumjs-block@^1.6.0: + version "1.7.1" + resolved "https://registry.yarnpkg.com/ethereumjs-block/-/ethereumjs-block-1.7.1.tgz#78b88e6cc56de29a6b4884ee75379b6860333c3f" + dependencies: + async "^2.0.1" + ethereum-common "0.2.0" + ethereumjs-tx "^1.2.2" + ethereumjs-util "^5.0.0" + merkle-patricia-tree "^2.1.2" + +ethereumjs-block@~2.2.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/ethereumjs-block/-/ethereumjs-block-2.2.2.tgz#c7654be7e22df489fda206139ecd63e2e9c04965" + dependencies: + async "^2.0.1" + ethereumjs-common "^1.5.0" + ethereumjs-tx "^2.1.1" + ethereumjs-util "^5.0.0" + merkle-patricia-tree "^2.1.2" + +ethereumjs-common@^1.1.0, ethereumjs-common@^1.3.2, ethereumjs-common@^1.5.0: version "1.5.1" resolved "https://registry.yarnpkg.com/ethereumjs-common/-/ethereumjs-common-1.5.1.tgz#4e75042473a64daec0ed9fe84323dd9576aa5dba" +ethereumjs-tx@^1.0.0, ethereumjs-tx@^1.1.1, ethereumjs-tx@^1.2.0, ethereumjs-tx@^1.2.2, ethereumjs-tx@^1.3.3, ethereumjs-tx@^1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/ethereumjs-tx/-/ethereumjs-tx-1.3.7.tgz#88323a2d875b10549b8347e09f4862b546f3d89a" + dependencies: + ethereum-common "^0.0.18" + ethereumjs-util "^5.0.0" + ethereumjs-tx@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/ethereumjs-tx/-/ethereumjs-tx-2.1.2.tgz#5dfe7688bf177b45c9a23f86cf9104d47ea35fed" @@ -1617,7 +2356,19 @@ ethereumjs-util@6.1.0: safe-buffer "^5.1.1" secp256k1 "^3.0.1" -ethereumjs-util@^6.0.0: +ethereumjs-util@^5.0.0, ethereumjs-util@^5.0.1, ethereumjs-util@^5.1.1, ethereumjs-util@^5.1.2, ethereumjs-util@^5.1.5: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz#3e0c0d1741471acf1036052d048623dee54ad642" + dependencies: + bn.js "^4.11.0" + create-hash "^1.1.2" + ethjs-util "^0.1.3" + keccak "^1.0.2" + rlp "^2.0.0" + safe-buffer "^5.1.1" + secp256k1 "^3.0.1" + +ethereumjs-util@^6.0.0, ethereumjs-util@^6.1.0: version "6.2.0" resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-6.2.0.tgz#23ec79b2488a7d041242f01e25f24e5ad0357960" dependencies: @@ -1641,6 +2392,36 @@ ethereumjs-util@^7.0.2: rlp "^2.2.4" secp256k1 "^4.0.1" +ethereumjs-vm@^2.1.0, ethereumjs-vm@^2.3.4, ethereumjs-vm@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/ethereumjs-vm/-/ethereumjs-vm-2.6.0.tgz#76243ed8de031b408793ac33907fb3407fe400c6" + dependencies: + async "^2.1.2" + async-eventemitter "^0.2.2" + ethereumjs-account "^2.0.3" + ethereumjs-block "~2.2.0" + ethereumjs-common "^1.1.0" + ethereumjs-util "^6.0.0" + fake-merkle-patricia-tree "^1.0.1" + functional-red-black-tree "^1.0.1" + merkle-patricia-tree "^2.3.2" + rustbn.js "~0.2.0" + safe-buffer "^5.1.1" + +ethereumjs-wallet@^0.6.3: + version "0.6.4" + resolved "https://registry.yarnpkg.com/ethereumjs-wallet/-/ethereumjs-wallet-0.6.4.tgz#67dd013dd839e69a8eb9a8f78cacfc9bff307167" + dependencies: + aes-js "^3.1.1" + bs58check "^2.1.2" + ethereumjs-util "^6.0.0" + hdkey "^1.1.1" + randombytes "^2.0.6" + safe-buffer "^5.1.2" + scryptsy "^1.2.1" + utf8 "^3.0.0" + uuid "^3.3.2" + ethers@4.0.0-beta.3: version "4.0.0-beta.3" resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.0-beta.3.tgz#15bef14e57e94ecbeb7f9b39dd0a4bd435bc9066" @@ -1677,7 +2458,7 @@ ethjs-unit@0.1.6: bn.js "4.11.6" number-to-bn "1.7.0" -ethjs-util@0.1.6: +ethjs-util@0.1.6, ethjs-util@^0.1.3: version "0.1.6" resolved "https://registry.yarnpkg.com/ethjs-util/-/ethjs-util-0.1.6.tgz#f308b62f185f9fe6237132fb2a9818866a5cd536" dependencies: @@ -1692,6 +2473,10 @@ eventemitter3@^4.0.0: version "4.0.4" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.4.tgz#b5463ace635a083d018bdc7c917b4c5f10a85384" +events@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.1.0.tgz#84279af1b34cb75aa88bf5ff291f6d0bd9b31a59" + evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" @@ -1827,6 +2612,12 @@ extsprintf@^1.2.0: version "1.4.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" +fake-merkle-patricia-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fake-merkle-patricia-tree/-/fake-merkle-patricia-tree-1.0.1.tgz#4b8c3acfb520afadf9860b1f14cd8ce3402cddd3" + dependencies: + checkpoint-store "^1.1.0" + fast-deep-equal@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4" @@ -1850,6 +2641,10 @@ fast-levenshtein@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" +fast-safe-stringify@^2.0.6: + version "2.0.7" + resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz#124aa885899261f68aedb42a7c080de9da608743" + fastq@^1.6.0: version "1.8.0" resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.8.0.tgz#550e1f9f59bbc65fe185cb6a9b4d95357107f481" @@ -1862,6 +2657,12 @@ fd-slicer@~1.1.0: dependencies: pend "~1.2.0" +fetch-ponyfill@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/fetch-ponyfill/-/fetch-ponyfill-4.1.0.tgz#ae3ce5f732c645eab87e4ae8793414709b239893" + dependencies: + node-fetch "~1.7.1" + file-type@^3.8.0: version "3.9.0" resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9" @@ -1931,6 +2732,12 @@ flat@^4.1.0: dependencies: is-buffer "~2.0.3" +for-each@~0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + dependencies: + is-callable "^1.1.3" + for-in@^1.0.1, for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -2016,10 +2823,14 @@ fsevents@~2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" -function-bind@^1.1.1: +function-bind@^1.1.1, function-bind@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + ganache-cli@6.9.0: version "6.9.0" resolved "https://registry.yarnpkg.com/ganache-cli/-/ganache-cli-6.9.0.tgz#94d7e26964dff80b7382a33829ec75e15709a948" @@ -2124,7 +2935,7 @@ glob@^5.0.15: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.0, glob@^7.1.2, glob@^7.1.3: +glob@^7.0.0, glob@^7.1.2, glob@^7.1.3, glob@~7.1.6: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" dependencies: @@ -2301,7 +3112,7 @@ has-values@^1.0.0: is-number "^3.0.0" kind-of "^4.0.0" -has@^1.0.3: +has@^1.0.3, has@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" dependencies: @@ -2329,6 +3140,14 @@ hash.js@^1.0.0, hash.js@^1.0.3: inherits "^2.0.3" minimalistic-assert "^1.0.1" +hdkey@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/hdkey/-/hdkey-1.1.2.tgz#c60f9cf6f90fbf24a8a52ea06893f36a0108cd3e" + dependencies: + bs58check "^2.1.2" + safe-buffer "^5.1.1" + secp256k1 "^3.0.1" + he@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" @@ -2384,7 +3203,7 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" -iconv-lite@0.4.24: +iconv-lite@0.4.24, iconv-lite@~0.4.13: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" dependencies: @@ -2404,6 +3223,10 @@ ignore@^5.1.1: version "5.1.8" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" +immediate@^3.2.3: + version "3.3.0" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.3.0.tgz#1aef225517836bcdf7f2a2de2600c79ff0269266" + inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -2411,7 +3234,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3, inherits@~2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" @@ -2477,7 +3300,7 @@ is-buffer@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.4.tgz#3e572f23c8411a5cfd9557c849e3665e0b290623" -is-callable@^1.1.4, is-callable@^1.1.5: +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.1.5: version "1.2.0" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.0.tgz#83336560b54a38e35e3a2df7afd0454d691468bb" @@ -2545,6 +3368,10 @@ is-finite@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3" +is-fn@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fn/-/is-fn-1.0.0.tgz#9543d5de7bcf5b08a22ec8a20bae6e286d510d8c" + is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" @@ -2629,17 +3456,23 @@ is-primitive@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" -is-regex@^1.0.5: +is-regex@^1.0.4, is-regex@^1.0.5: version "1.1.0" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.0.tgz#ece38e389e490df0dc21caea2bd596f987f767ff" dependencies: has-symbols "^1.0.1" +is-regex@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae" + dependencies: + has "^1.0.3" + is-retry-allowed@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" -is-stream@^1.0.0, is-stream@^1.1.0: +is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" @@ -2666,6 +3499,10 @@ is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + isarray@1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -2737,10 +3574,44 @@ jsesc@^2.5.1: version "2.5.2" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + json-buffer@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" +json-rpc-engine@^3.4.0, json-rpc-engine@^3.6.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/json-rpc-engine/-/json-rpc-engine-3.8.0.tgz#9d4ff447241792e1d0a232f6ef927302bb0c62a9" + dependencies: + async "^2.0.1" + babel-preset-env "^1.7.0" + babelify "^7.3.0" + json-rpc-error "^2.0.0" + promise-to-callback "^1.0.0" + safe-event-emitter "^1.0.1" + +json-rpc-engine@^5.1.3: + version "5.1.8" + resolved "https://registry.yarnpkg.com/json-rpc-engine/-/json-rpc-engine-5.1.8.tgz#5ba0147ce571899bbaa7133ffbc05317c34a3c7f" + dependencies: + async "^2.0.1" + eth-json-rpc-errors "^2.0.1" + promise-to-callback "^1.0.0" + safe-event-emitter "^1.0.1" + +json-rpc-error@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/json-rpc-error/-/json-rpc-error-2.0.0.tgz#a7af9c202838b5e905c7250e547f1aff77258a02" + dependencies: + inherits "^2.0.1" + +json-rpc-random-id@^1.0.0, json-rpc-random-id@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-rpc-random-id/-/json-rpc-random-id-1.0.1.tgz#ba49d96aded1444dbb8da3d203748acbbcdec8c8" + json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" @@ -2749,6 +3620,12 @@ json-schema@0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" +json-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + dependencies: + jsonify "~0.0.0" + json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" @@ -2763,6 +3640,10 @@ jsonfile@^4.0.0: optionalDependencies: graceful-fs "^4.1.6" +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + jsonschema@^1.2.4: version "1.2.6" resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.2.6.tgz#52b0a8e9dc06bbae7295249d03e4b9faee8a0c0b" @@ -2833,6 +3714,50 @@ lcid@^2.0.0: dependencies: invert-kv "^2.0.0" +level-codec@~7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/level-codec/-/level-codec-7.0.1.tgz#341f22f907ce0f16763f24bddd681e395a0fb8a7" + +level-errors@^1.0.3: + version "1.1.2" + resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-1.1.2.tgz#4399c2f3d3ab87d0625f7e3676e2d807deff404d" + dependencies: + errno "~0.1.1" + +level-errors@~1.0.3: + version "1.0.5" + resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-1.0.5.tgz#83dbfb12f0b8a2516bdc9a31c4876038e227b859" + dependencies: + errno "~0.1.1" + +level-iterator-stream@~1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/level-iterator-stream/-/level-iterator-stream-1.3.1.tgz#e43b78b1a8143e6fa97a4f485eb8ea530352f2ed" + dependencies: + inherits "^2.0.1" + level-errors "^1.0.3" + readable-stream "^1.0.33" + xtend "^4.0.0" + +level-ws@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/level-ws/-/level-ws-0.0.0.tgz#372e512177924a00424b0b43aef2bb42496d228b" + dependencies: + readable-stream "~1.0.15" + xtend "~2.1.1" + +levelup@^1.2.1: + version "1.3.9" + resolved "https://registry.yarnpkg.com/levelup/-/levelup-1.3.9.tgz#2dbcae845b2bb2b6bea84df334c475533bbd82ab" + dependencies: + deferred-leveldown "~1.2.1" + level-codec "~7.0.0" + level-errors "~1.0.3" + level-iterator-stream "~1.3.0" + prr "~1.0.1" + semver "~5.4.1" + xtend "~4.0.0" + levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" @@ -2847,11 +3772,15 @@ locate-path@^3.0.0: p-locate "^3.0.0" path-exists "^3.0.0" +lodash.flatmap@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.flatmap/-/lodash.flatmap-4.5.0.tgz#ef8cbf408f6e48268663345305c6acc0b778702e" + lodash.toarray@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.toarray/-/lodash.toarray-4.4.0.tgz#24c4bfcd6b2fba38bfd0594db1179d8e9b656561" -lodash@^4.17.13, lodash@^4.17.15, lodash@^4.17.4: +lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" @@ -2875,6 +3804,10 @@ lowercase-keys@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" +ltgt@~2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5" + make-dir@^1.0.0: version "1.3.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" @@ -2925,6 +3858,17 @@ mem@^4.0.0: mimic-fn "^2.0.0" p-is-promise "^2.0.0" +memdown@^1.0.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/memdown/-/memdown-1.4.1.tgz#b4e4e192174664ffbae41361aa500f3119efe215" + dependencies: + abstract-leveldown "~2.7.1" + functional-red-black-tree "^1.0.1" + immediate "^3.2.3" + inherits "~2.0.1" + ltgt "~2.2.0" + safe-buffer "~5.1.1" + merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" @@ -2933,6 +3877,19 @@ merge2@^1.2.3, merge2@^1.3.0: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" +merkle-patricia-tree@^2.1.2, merkle-patricia-tree@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/merkle-patricia-tree/-/merkle-patricia-tree-2.3.2.tgz#982ca1b5a0fde00eed2f6aeed1f9152860b8208a" + dependencies: + async "^1.4.2" + ethereumjs-util "^5.0.0" + level-ws "0.0.0" + levelup "^1.2.1" + memdown "^1.0.0" + readable-stream "^2.0.0" + rlp "^2.0.0" + semaphore ">=1.0.1" + methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" @@ -3029,7 +3986,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: dependencies: brace-expansion "^1.1.7" -minimist@^1.2.5: +minimist@^1.2.5, minimist@~1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" @@ -3206,6 +4163,17 @@ node-environment-flags@1.0.6: object.getownpropertydescriptors "^2.0.3" semver "^5.7.0" +node-fetch@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.1.2.tgz#ab884e8e7e57e38a944753cec706f788d1768bb5" + +node-fetch@~1.7.1: + version "1.7.3" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" + dependencies: + encoding "^0.1.11" + is-stream "^1.0.1" + node-gyp-build@^4.2.0: version "4.2.2" resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.2.2.tgz#3f44b65adaafd42fb6c3d81afd630e45c847eb66" @@ -3247,7 +4215,7 @@ oauth-sign@~0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" -object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: +object-assign@^4, object-assign@^4.0.0, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -3259,7 +4227,7 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" -object-inspect@^1.7.0: +object-inspect@^1.7.0, object-inspect@~1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" @@ -3274,6 +4242,10 @@ object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" +object-keys@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336" + object-visit@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" @@ -3478,6 +4450,16 @@ pbkdf2@^3.0.3: safe-buffer "^5.0.1" sha.js "^2.4.8" +pbkdf2@^3.0.9: + version "3.1.1" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.1.tgz#cb8724b0fada984596856d1a6ebafd3584654b94" + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + pend@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" @@ -3516,6 +4498,10 @@ posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" +precond@0.2: + version "0.2.3" + resolved "https://registry.yarnpkg.com/precond/-/precond-0.2.3.tgz#aa9591bcaa24923f1e0f4849d240f47efc1075ac" + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" @@ -3549,7 +4535,7 @@ prettier@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.0.5.tgz#d6d56282455243f2f92cc1716692c08aa31522d4" -private@^0.1.8: +private@^0.1.6, private@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" @@ -3561,6 +4547,13 @@ process@~0.5.1: version "0.5.2" resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" +promise-to-callback@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/promise-to-callback/-/promise-to-callback-1.0.0.tgz#5d2a749010bfb67d963598fcd3960746a68feef7" + dependencies: + is-fn "^1.0.0" + set-immediate-shim "^1.0.1" + proxy-addr@~2.0.5: version "2.0.6" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" @@ -3568,6 +4561,10 @@ proxy-addr@~2.0.5: forwarded "~0.1.2" ipaddr.js "1.9.1" +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + psl@^1.1.28: version "1.8.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" @@ -3622,7 +4619,7 @@ randomatic@^3.0.0: kind-of "^6.0.0" math-random "^1.0.1" -randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.0.6, randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" dependencies: @@ -3652,7 +4649,16 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" -readable-stream@^2.0.2, readable-stream@^2.3.0, readable-stream@^2.3.5: +readable-stream@^1.0.33: + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.0, readable-stream@^2.3.5, readable-stream@~2.3.6: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" dependencies: @@ -3672,6 +4678,15 @@ readable-stream@^3.6.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" +readable-stream@~1.0.15: + version "1.0.34" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + readdirp@^2.0.0: version "2.2.1" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" @@ -3698,6 +4713,10 @@ recursive-readdir@^2.2.2: dependencies: minimatch "3.0.4" +regenerate@^1.2.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.1.tgz#cad92ad8e6b591773485fbe05a485caf4f457e6f" + regenerator-runtime@^0.10.5: version "0.10.5" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" @@ -3706,6 +4725,18 @@ regenerator-runtime@^0.11.0: version "0.11.1" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" +regenerator-runtime@^0.13.4: + version "0.13.5" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697" + +regenerator-transform@^0.10.0: + version "0.10.1" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" + dependencies: + babel-runtime "^6.18.0" + babel-types "^6.19.0" + private "^0.1.6" + regex-cache@^0.4.2: version "0.4.4" resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" @@ -3719,6 +4750,31 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" +regexp.prototype.flags@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz#7aba89b3c13a64509dabcf3ca8d9fbb9bdf5cb75" + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + +regexpu-core@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + +regjsgen@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + +regjsparser@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + dependencies: + jsesc "~0.5.0" + remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" @@ -3737,7 +4793,7 @@ repeating@^2.0.0: dependencies: is-finite "^1.0.0" -request@^2.79.0: +request@^2.79.0, request@^2.85.0: version "2.88.2" resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" dependencies: @@ -3778,7 +4834,7 @@ resolve@1.1.x: version "1.1.7" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" -resolve@^1.1.6, resolve@^1.12.0: +resolve@^1.1.6, resolve@^1.12.0, resolve@^1.8.1, resolve@~1.17.0: version "1.17.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" dependencies: @@ -3790,6 +4846,12 @@ responselike@^1.0.2: dependencies: lowercase-keys "^1.0.0" +resumer@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/resumer/-/resumer-0.0.0.tgz#f1e8f461e4064ba39e82af3cdc2a8c893d076759" + dependencies: + through "~2.3.4" + ret@~0.1.10: version "0.1.15" resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" @@ -3815,6 +4877,10 @@ run-parallel@^1.1.9: version "1.1.9" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" +rustbn.js@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/rustbn.js/-/rustbn.js-0.2.0.tgz#8082cb886e707155fd1cb6f23bd591ab8d55d0ca" + safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -3823,6 +4889,12 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" +safe-event-emitter@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/safe-event-emitter/-/safe-event-emitter-1.0.1.tgz#5b692ef22329ed8f69fdce607e50ca734f6f20af" + dependencies: + events "^3.0.0" + safe-regex@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" @@ -3871,6 +4943,12 @@ scryptsy@2.1.0, scryptsy@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/scryptsy/-/scryptsy-2.1.0.tgz#8d1e8d0c025b58fdd25b6fa9a0dc905ee8faa790" +scryptsy@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/scryptsy/-/scryptsy-1.2.1.tgz#a3225fa4b2524f802700761e2855bdf3b2d92163" + dependencies: + pbkdf2 "^3.0.3" + secp256k1@^3.0.1: version "3.8.0" resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-3.8.0.tgz#28f59f4b01dbee9575f56a47034b7d2e3b3b352d" @@ -3898,11 +4976,15 @@ seek-bzip@^1.0.5: dependencies: commander "~2.8.1" +semaphore@>=1.0.1, semaphore@^1.0.3: + version "1.1.0" + resolved "https://registry.yarnpkg.com/semaphore/-/semaphore-1.1.0.tgz#aaad8b86b20fe8e9b32b16dc2ee682a8cd26a8aa" + semver@6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.2.0.tgz#4d813d9590aaf8a9192693d6c85b9344de5901db" -semver@^5.5.0, semver@^5.7.0: +semver@^5.3.0, semver@^5.5.0, semver@^5.5.1, semver@^5.7.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" @@ -3914,6 +4996,10 @@ semver@^7.3.2: version "7.3.2" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" +semver@~5.4.1: + version "5.4.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" + send@0.17.1: version "0.17.1" resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" @@ -3955,6 +5041,10 @@ set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" +set-immediate-shim@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + set-value@^2.0.0, set-value@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" @@ -4098,7 +5188,7 @@ source-map-support@^0.4.15: dependencies: source-map "^0.5.6" -source-map-support@^0.5.17: +source-map-support@^0.5.17, source-map-support@^0.5.19: version "0.5.19" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" dependencies: @@ -4185,6 +5275,14 @@ string-width@^4.2.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.0" +string.prototype.trim@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.1.tgz#141233dff32c82bfad80684d7e5f0869ee0fb782" + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + function-bind "^1.1.1" + string.prototype.trimend@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913" @@ -4221,6 +5319,10 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -4326,6 +5428,26 @@ swarm-js@^0.1.40: tar "^4.0.2" xhr-request "^1.0.1" +tape@^4.6.3: + version "4.13.3" + resolved "https://registry.yarnpkg.com/tape/-/tape-4.13.3.tgz#51b3d91c83668c7a45b1a594b607dee0a0b46278" + dependencies: + deep-equal "~1.1.1" + defined "~1.0.0" + dotignore "~0.1.2" + for-each "~0.3.3" + function-bind "~1.1.1" + glob "~7.1.6" + has "~1.0.3" + inherits "~2.0.4" + is-regex "~1.0.5" + minimist "~1.2.5" + object-inspect "~1.7.0" + resolve "~1.17.0" + resumer "~0.0.0" + string.prototype.trim "~1.2.1" + through "~2.3.8" + tar-stream@^1.5.2: version "1.6.2" resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" @@ -4350,7 +5472,14 @@ tar@^4.0.2: safe-buffer "^5.1.2" yallist "^3.0.3" -through@^2.3.8: +through2@^2.0.3: + version "2.0.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + +through@^2.3.8, through@~2.3.4, through@~2.3.8: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" @@ -4477,6 +5606,10 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + typescript@^3.9.5: version "3.9.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.5.tgz#586f0dba300cde8be52dd1ac4f7e1009c1b13f36" @@ -4515,6 +5648,10 @@ universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" +unorm@^1.3.3: + version "1.6.0" + resolved "https://registry.yarnpkg.com/unorm/-/unorm-1.6.0.tgz#029b289661fba714f1a9af439eb51d9b16c205af" + unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" @@ -4564,7 +5701,7 @@ user-home@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" -utf8@3.0.0: +utf8@3.0.0, utf8@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1" @@ -5501,6 +6638,10 @@ websocket@^1.0.28: typedarray-to-buffer "^3.1.5" yaeti "^0.0.6" +whatwg-fetch@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f" + which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" @@ -5556,6 +6697,12 @@ ws@^3.0.0: safe-buffer "~5.1.0" ultron "~1.1.0" +ws@^5.1.1: + version "5.2.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f" + dependencies: + async-limiter "~1.0.0" + xhr-request-promise@^0.1.2: version "0.1.3" resolved "https://registry.yarnpkg.com/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz#2d5f4b16d8c6c893be97f1a62b0ed4cf3ca5f96c" @@ -5580,7 +6727,7 @@ xhr2-cookies@1.1.0: dependencies: cookiejar "^2.1.1" -xhr@^2.0.4, xhr@^2.3.3: +xhr@^2.0.4, xhr@^2.2.0, xhr@^2.3.3: version "2.5.0" resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.5.0.tgz#bed8d1676d5ca36108667692b74b316c496e49dd" dependencies: @@ -5593,10 +6740,16 @@ xmlhttprequest@1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc" -xtend@^4.0.0: +xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.0, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" +xtend@~2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.1.2.tgz#6efecc2a4dad8e6962c4901b337ce7ba87b5d28b" + dependencies: + object-keys "~0.4.0" + y18n@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" From 44d1f28606dea517c86bdb8512f7732139876ba5 Mon Sep 17 00:00:00 2001 From: mingda Date: Sat, 27 Jun 2020 18:01:18 +0800 Subject: [PATCH 008/118] contract interaction scripts --- .gitignore | 1 + test/utils/Contracts.ts | 10 +++++----- tsconfig.json | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 28e453c..38880f7 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ docs/src node_modules/ coverage/ lint/ +script/ # VIM *.swo diff --git a/test/utils/Contracts.ts b/test/utils/Contracts.ts index 7901049..31a936c 100644 --- a/test/utils/Contracts.ts +++ b/test/utils/Contracts.ts @@ -35,7 +35,7 @@ interface ContractJson { byteCode: string; } -function _getContractJSON(contractName: string): ContractJson { +export function getContractJSON(contractName: string): ContractJson { switch (contractName) { case DODO_CONTRACT_NAME: return { @@ -85,22 +85,22 @@ function _getContractJSON(contractName: string): ContractJson { } export function getContractWithAddress(contractName: string, address: string) { - var Json = _getContractJSON(contractName) + var Json = getContractJSON(contractName) var web3 = getDefaultWeb3() return new web3.eth.Contract(Json.abi, address) } export function getDepolyedContract(contractName: string): Contract { - var Json = _getContractJSON(contractName) + var Json = getContractJSON(contractName) var networkId = process.env.NETWORK_ID - var deployedAddress = _getContractJSON(contractName).networks[networkId].address + var deployedAddress = getContractJSON(contractName).networks[networkId].address var web3 = getDefaultWeb3() return new web3.eth.Contract(Json.abi, deployedAddress) } export async function newContract(contractName: string, args: any[] = []): Promise { var web3 = getDefaultWeb3() - var Json = _getContractJSON(contractName) + var Json = getContractJSON(contractName) var contract = new web3.eth.Contract(Json.abi) var adminAccount = (await web3.eth.getAccounts())[0] let parameter = { diff --git a/tsconfig.json b/tsconfig.json index 5ecfa5e..3e1de7f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,7 +15,7 @@ "typeRoots": ["node_modules/@types"], "types": ["node", "mocha", "chai"] }, - "include": ["src", "test"], + "include": ["src", "test", "script"], "exclude": ["scripts/**/*", "build/**/*", "migrations/**/*"], "compileOnSave": true } From 11eb3d710326480ce8e7c849ae69b0e910e6f3ad Mon Sep 17 00:00:00 2001 From: mingda Date: Wed, 8 Jul 2020 17:04:48 +0800 Subject: [PATCH 009/118] [audit]#1 add decimals and name to lptoken --- contracts/dodo.sol | 17 ++++++++++++++--- contracts/helper/TestERC20.sol | 9 ++++++++- contracts/impl/DODOLpToken.sol | 8 ++++++++ contracts/intf/IERC20.sol | 5 ++++- 4 files changed, 34 insertions(+), 5 deletions(-) diff --git a/contracts/dodo.sol b/contracts/dodo.sol index f62d664..08a60c2 100644 --- a/contracts/dodo.sol +++ b/contracts/dodo.sol @@ -9,13 +9,13 @@ pragma solidity 0.6.9; pragma experimental ABIEncoderV2; import {Types} from "./lib/Types.sol"; +import {IERC20} from "./intf/IERC20.sol"; import {Storage} from "./impl/Storage.sol"; import {Trader} from "./impl/Trader.sol"; import {LiquidityProvider} from "./impl/LiquidityProvider.sol"; import {Admin} from "./impl/Admin.sol"; import {DODOLpToken} from "./impl/DODOLpToken.sol"; - /** * @title DODO * @author DODO Breeder @@ -53,8 +53,19 @@ contract DODO is Admin, Trader, LiquidityProvider { _K_ = k; _R_STATUS_ = Types.RStatus.ONE; - _BASE_CAPITAL_TOKEN_ = address(new DODOLpToken()); - _QUOTE_CAPITAL_TOKEN_ = address(new DODOLpToken()); + string memory lpTokenSuffix = "_DODO_LP_TOKEN_"; + + string memory baseName = string( + abi.encodePacked(IERC20(_BASE_TOKEN_).name(), lpTokenSuffix) + ); + uint8 baseDecimals = IERC20(_BASE_TOKEN_).decimals(); + _BASE_CAPITAL_TOKEN_ = address(new DODOLpToken(baseName, baseDecimals)); + + string memory quoteName = string( + abi.encodePacked(IERC20(_QUOTE_TOKEN_).name(), lpTokenSuffix) + ); + uint8 quoteDecimals = IERC20(_QUOTE_TOKEN_).decimals(); + _QUOTE_CAPITAL_TOKEN_ = address(new DODOLpToken(quoteName, quoteDecimals)); _checkDODOParameters(); } diff --git a/contracts/helper/TestERC20.sol b/contracts/helper/TestERC20.sol index 85acc3b..5d02d72 100644 --- a/contracts/helper/TestERC20.sol +++ b/contracts/helper/TestERC20.sol @@ -9,16 +9,23 @@ pragma solidity 0.6.9; import {SafeMath} from "../lib/SafeMath.sol"; - contract TestERC20 { using SafeMath for uint256; + string public name; + uint8 public decimals; + mapping(address => uint256) balances; mapping(address => mapping(address => uint256)) internal allowed; event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); + constructor(string memory _name, uint8 _decimals) public { + name = _name; + decimals = _decimals; + } + function transfer(address to, uint256 amount) public returns (bool) { require(to != address(0), "TO_ADDRESS_IS_EMPTY"); require(amount <= balances[msg.sender], "BALANCE_NOT_ENOUGH"); diff --git a/contracts/impl/DODOLpToken.sol b/contracts/impl/DODOLpToken.sol index 6268b4f..34f2bb8 100644 --- a/contracts/impl/DODOLpToken.sol +++ b/contracts/impl/DODOLpToken.sol @@ -20,6 +20,9 @@ import {Ownable} from "../lib/Ownable.sol"; contract DODOLpToken is Ownable { using SafeMath for uint256; + string public name; + uint8 public decimals; + uint256 public totalSupply; mapping(address => uint256) internal balances; mapping(address => mapping(address => uint256)) internal allowed; @@ -36,6 +39,11 @@ contract DODOLpToken is Ownable { // ============ Functions ============ + constructor(string memory _name, uint8 _decimals) public { + name = _name; + decimals = _decimals; + } + /** * @dev transfer token for a specified address * @param to The address to transfer to. diff --git a/contracts/intf/IERC20.sol b/contracts/intf/IERC20.sol index e24f1ec..2f1810b 100644 --- a/contracts/intf/IERC20.sol +++ b/contracts/intf/IERC20.sol @@ -4,7 +4,6 @@ pragma solidity 0.6.9; pragma experimental ABIEncoderV2; - /** * @dev Interface of the ERC20 standard as defined in the EIP. */ @@ -14,6 +13,10 @@ interface IERC20 { */ function totalSupply() external view returns (uint256); + function decimals() external view returns (uint8); + + function name() external view returns (string memory); + /** * @dev Returns the amount of tokens owned by `account`. */ From 5d7cabcc16918f2f0d6bbe90a42fdf4fc6b4510e Mon Sep 17 00:00:00 2001 From: mingda Date: Wed, 8 Jul 2020 17:12:00 +0800 Subject: [PATCH 010/118] [audit]#2 make getExpectedTarget public --- contracts/impl/LiquidityProvider.sol | 12 ++++++------ contracts/impl/Pricing.sol | 2 +- contracts/impl/Trader.sol | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/contracts/impl/LiquidityProvider.sol b/contracts/impl/LiquidityProvider.sol index 533e7f2..2e10523 100644 --- a/contracts/impl/LiquidityProvider.sol +++ b/contracts/impl/LiquidityProvider.sol @@ -85,7 +85,7 @@ contract LiquidityProvider is Storage, Pricing, Settlement { preventReentrant depositQuoteAllowed { - (, uint256 quoteTarget) = _getExpectedTarget(); + (, uint256 quoteTarget) = getExpectedTarget(); uint256 totalQuoteCapital = getTotalQuoteCapital(); uint256 capital = amount; if (totalQuoteCapital == 0) { @@ -104,7 +104,7 @@ contract LiquidityProvider is Storage, Pricing, Settlement { } function depositBaseTo(address to, uint256 amount) public preventReentrant depositBaseAllowed { - (uint256 baseTarget, ) = _getExpectedTarget(); + (uint256 baseTarget, ) = getExpectedTarget(); uint256 totalBaseCapital = getTotalBaseCapital(); uint256 capital = amount; if (totalBaseCapital == 0) { @@ -126,7 +126,7 @@ contract LiquidityProvider is Storage, Pricing, Settlement { function withdrawQuoteTo(address to, uint256 amount) public preventReentrant returns (uint256) { // calculate capital - (, uint256 quoteTarget) = _getExpectedTarget(); + (, uint256 quoteTarget) = getExpectedTarget(); uint256 totalQuoteCapital = getTotalQuoteCapital(); require(totalQuoteCapital > 0, "NO_QUOTE_LP"); @@ -154,7 +154,7 @@ contract LiquidityProvider is Storage, Pricing, Settlement { function withdrawBaseTo(address to, uint256 amount) public preventReentrant returns (uint256) { // calculate capital - (uint256 baseTarget, ) = _getExpectedTarget(); + (uint256 baseTarget, ) = getExpectedTarget(); uint256 totalBaseCapital = getTotalBaseCapital(); require(totalBaseCapital > 0, "NO_BASE_LP"); @@ -242,7 +242,7 @@ contract LiquidityProvider is Storage, Pricing, Settlement { function getLpBaseBalance(address lp) public view returns (uint256 lpBalance) { uint256 totalBaseCapital = getTotalBaseCapital(); - (uint256 baseTarget, ) = _getExpectedTarget(); + (uint256 baseTarget, ) = getExpectedTarget(); if (totalBaseCapital == 0) { return 0; } @@ -252,7 +252,7 @@ contract LiquidityProvider is Storage, Pricing, Settlement { function getLpQuoteBalance(address lp) public view returns (uint256 lpBalance) { uint256 totalQuoteCapital = getTotalQuoteCapital(); - (, uint256 quoteTarget) = _getExpectedTarget(); + (, uint256 quoteTarget) = getExpectedTarget(); if (totalQuoteCapital == 0) { return 0; } diff --git a/contracts/impl/Pricing.sol b/contracts/impl/Pricing.sol index d959941..4e81e95 100644 --- a/contracts/impl/Pricing.sol +++ b/contracts/impl/Pricing.sol @@ -151,7 +151,7 @@ contract Pricing is Storage { // ============ Helper functions ============ - function _getExpectedTarget() internal view returns (uint256 baseTarget, uint256 quoteTarget) { + function getExpectedTarget() public view returns (uint256 baseTarget, uint256 quoteTarget) { uint256 Q = _QUOTE_BALANCE_; uint256 B = _BASE_BALANCE_; if (_R_STATUS_ == Types.RStatus.ONE) { diff --git a/contracts/impl/Trader.sol b/contracts/impl/Trader.sol index 8a5f6a6..19d9673 100644 --- a/contracts/impl/Trader.sol +++ b/contracts/impl/Trader.sol @@ -140,7 +140,7 @@ contract Trader is Storage, Pricing, Settlement { uint256 newBaseTarget ) { - (newBaseTarget, newQuoteTarget) = _getExpectedTarget(); + (newBaseTarget, newQuoteTarget) = getExpectedTarget(); uint256 sellBaseAmount = amount; @@ -201,7 +201,7 @@ contract Trader is Storage, Pricing, Settlement { uint256 newBaseTarget ) { - (newBaseTarget, newQuoteTarget) = _getExpectedTarget(); + (newBaseTarget, newQuoteTarget) = getExpectedTarget(); // charge fee from user receive amount lpFeeBase = DecimalMath.mul(amount, _LP_FEE_RATE_); From 5254dc1d6b23b05b2ea16f11dcc6a691bd8acb21 Mon Sep 17 00:00:00 2001 From: mingda Date: Wed, 8 Jul 2020 17:17:10 +0800 Subject: [PATCH 011/118] [audit]#3 simplify getExpectedTarget --- contracts/impl/Pricing.sol | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/contracts/impl/Pricing.sol b/contracts/impl/Pricing.sol index 4e81e95..eaeda9b 100644 --- a/contracts/impl/Pricing.sol +++ b/contracts/impl/Pricing.sol @@ -91,11 +91,7 @@ contract Pricing is Storage { return Q2.sub(quoteBalance); } - function _RBelowBackToOne() - internal - view - returns (uint256 payQuoteToken, uint256 receiveBaseToken) - { + function _RBelowBackToOne() internal view returns (uint256 payQuoteToken) { // important: carefully design the system to make sure spareBase always greater than or equal to 0 uint256 spareBase = _BASE_BALANCE_.sub(_TARGET_BASE_TOKEN_AMOUNT_); uint256 price = getOraclePrice(); @@ -105,7 +101,7 @@ contract Pricing is Storage { _K_, fairAmount ); - return (newTargetQuote.sub(_QUOTE_BALANCE_), spareBase); + return newTargetQuote.sub(_QUOTE_BALANCE_); } // ============ R > 1 cases ============ @@ -132,11 +128,7 @@ contract Pricing is Storage { return _RAboveIntegrate(targetBaseAmount, B1, baseBalance); } - function _RAboveBackToOne() - internal - view - returns (uint256 payBaseToken, uint256 receiveQuoteToken) - { + function _RAboveBackToOne() internal view returns (uint256 payBaseToken) { // important: carefully design the system to make sure spareBase always greater than or equal to 0 uint256 spareQuote = _QUOTE_BALANCE_.sub(_TARGET_QUOTE_TOKEN_AMOUNT_); uint256 price = getOraclePrice(); @@ -146,7 +138,7 @@ contract Pricing is Storage { _K_, fairAmount ); - return (newTargetBase.sub(_BASE_BALANCE_), spareQuote); + return newTargetBase.sub(_BASE_BALANCE_); } // ============ Helper functions ============ @@ -157,11 +149,11 @@ contract Pricing is Storage { if (_R_STATUS_ == Types.RStatus.ONE) { return (_TARGET_BASE_TOKEN_AMOUNT_, _TARGET_QUOTE_TOKEN_AMOUNT_); } else if (_R_STATUS_ == Types.RStatus.BELOW_ONE) { - (uint256 payQuoteToken, uint256 receiveBaseToken) = _RBelowBackToOne(); - return (B.sub(receiveBaseToken), Q.add(payQuoteToken)); + uint256 payQuoteToken = _RBelowBackToOne(); + return (_TARGET_BASE_TOKEN_AMOUNT_, Q.add(payQuoteToken)); } else if (_R_STATUS_ == Types.RStatus.ABOVE_ONE) { - (uint256 payBaseToken, uint256 receiveQuoteToken) = _RAboveBackToOne(); - return (B.add(payBaseToken), Q.sub(receiveQuoteToken)); + uint256 payBaseToken = _RAboveBackToOne(); + return (B.add(payBaseToken), _TARGET_QUOTE_TOKEN_AMOUNT_); } } From 8babc610282b5e533b229e3e9385713de5ec9911 Mon Sep 17 00:00:00 2001 From: mingda Date: Wed, 8 Jul 2020 17:52:20 +0800 Subject: [PATCH 012/118] [audit]#4 add transfer event to dodo lptoken burn --- contracts/impl/DODOLpToken.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/impl/DODOLpToken.sol b/contracts/impl/DODOLpToken.sol index 34f2bb8..9347be9 100644 --- a/contracts/impl/DODOLpToken.sol +++ b/contracts/impl/DODOLpToken.sol @@ -122,5 +122,6 @@ contract DODOLpToken is Ownable { balances[user] = balances[user].sub(value); totalSupply = totalSupply.sub(value); emit Burn(user, value); + emit Transfer(user, address(0), value); } } From 9f974667a739b6a7ff42c6c51d143786c1352e31 Mon Sep 17 00:00:00 2001 From: mingda Date: Wed, 8 Jul 2020 17:53:01 +0800 Subject: [PATCH 013/118] [audit]#5 add claim ownership to ownable contract --- contracts/intf/IDODO.sol | 3 ++- contracts/lib/Ownable.sol | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/contracts/intf/IDODO.sol b/contracts/intf/IDODO.sol index 5a21c29..c27119a 100644 --- a/contracts/intf/IDODO.sol +++ b/contracts/intf/IDODO.sol @@ -8,7 +8,6 @@ pragma solidity 0.6.9; pragma experimental ABIEncoderV2; - interface IDODO { function init( address supervisor, @@ -24,6 +23,8 @@ interface IDODO { function transferOwnership(address newOwner) external; + function claimOwnership() external; + function sellBaseToken(uint256 amount, uint256 minReceiveQuote) external returns (uint256); function buyBaseToken(uint256 amount, uint256 maxPayQuote) external returns (uint256); diff --git a/contracts/lib/Ownable.sol b/contracts/lib/Ownable.sol index da32aa8..68dcacf 100644 --- a/contracts/lib/Ownable.sol +++ b/contracts/lib/Ownable.sol @@ -16,9 +16,12 @@ pragma experimental ABIEncoderV2; */ contract Ownable { address public _OWNER_; + address public _NEW_OWNER_; // ============ Events ============ + event OwnershipTransferPrepared(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); // ============ Modifiers ============ @@ -37,7 +40,14 @@ contract Ownable { function transferOwnership(address newOwner) external onlyOwner { require(newOwner != address(0), "INVALID_OWNER"); - emit OwnershipTransferred(_OWNER_, newOwner); - _OWNER_ = newOwner; + emit OwnershipTransferPrepared(_OWNER_, newOwner); + _NEW_OWNER_ = newOwner; + } + + function claimOwnership() external { + require(msg.sender == _NEW_OWNER_, "INVALID_CLAIM"); + emit OwnershipTransferred(_OWNER_, _NEW_OWNER_); + _OWNER_ = _NEW_OWNER_; + _NEW_OWNER_ = address(0); } } From 2fd47f3d401175a4f100813399f84e05ee6db6e9 Mon Sep 17 00:00:00 2001 From: mingda Date: Wed, 8 Jul 2020 17:54:47 +0800 Subject: [PATCH 014/118] [audit]#6 add baseToken and quoteToken address to dodo birth event --- contracts/DODOZoo.sol | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/contracts/DODOZoo.sol b/contracts/DODOZoo.sol index 1025a21..d42ce99 100644 --- a/contracts/DODOZoo.sol +++ b/contracts/DODOZoo.sol @@ -12,7 +12,6 @@ import {Ownable} from "./lib/Ownable.sol"; import {IDODO} from "./intf/IDODO.sol"; import {DODO} from "./DODO.sol"; - /** * @title DODOZoo * @author DODO Breeder @@ -24,7 +23,7 @@ contract DODOZoo is Ownable { // ============ Events ============ - event DODOBirth(address newBorn); + event DODOBirth(address newBorn, address baseToken, address quoteToken); // ============ Breed DODO Function ============ @@ -55,7 +54,7 @@ contract DODOZoo is Ownable { ); IDODO(newBornDODO).transferOwnership(_OWNER_); _DODO_REGISTER_[baseToken][quoteToken] = newBornDODO; - emit DODOBirth(newBornDODO); + emit DODOBirth(newBornDODO, baseToken, quoteToken); return newBornDODO; } From 3f077bfb498d7275e05c9d287aeb4c5478a45bb4 Mon Sep 17 00:00:00 2001 From: mingda Date: Wed, 8 Jul 2020 17:57:13 +0800 Subject: [PATCH 015/118] [audit]#7 check dodo exist in dodoETHProxy --- contracts/DODOEthProxy.sol | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contracts/DODOEthProxy.sol b/contracts/DODOEthProxy.sol index 5961f14..bd64db3 100644 --- a/contracts/DODOEthProxy.sol +++ b/contracts/DODOEthProxy.sol @@ -15,7 +15,6 @@ import {IDODOZoo} from "./intf/IDODOZoo.sol"; import {IERC20} from "./intf/IERC20.sol"; import {IWETH} from "./intf/IWETH.sol"; - /** * @title DODO Eth Proxy * @author DODO Breeder @@ -68,6 +67,7 @@ contract DODOEthProxy is ReentrancyGuard { ) external payable preventReentrant returns (uint256 receiveTokenAmount) { require(msg.value == ethAmount, "ETH_AMOUNT_NOT_MATCH"); address DODO = IDODOZoo(_DODO_ZOO_).getDODO(_WETH_, quoteTokenAddress); + require(DODO != address(0), "DODO_NOT_EXIST"); receiveTokenAmount = IDODO(DODO).querySellBaseToken(ethAmount); require(receiveTokenAmount >= minReceiveTokenAmount, "RECEIVE_NOT_ENOUGH"); IWETH(_WETH_).deposit{value: ethAmount}(); @@ -84,6 +84,7 @@ contract DODOEthProxy is ReentrancyGuard { uint256 maxPayTokenAmount ) external preventReentrant returns (uint256 payTokenAmount) { address DODO = IDODOZoo(_DODO_ZOO_).getDODO(_WETH_, quoteTokenAddress); + require(DODO != address(0), "DODO_NOT_EXIST"); payTokenAmount = IDODO(DODO).queryBuyBaseToken(ethAmount); require(payTokenAmount <= maxPayTokenAmount, "PAY_TOO_MUCH"); _transferIn(quoteTokenAddress, msg.sender, payTokenAmount); @@ -102,6 +103,7 @@ contract DODOEthProxy is ReentrancyGuard { { require(msg.value == ethAmount, "ETH_AMOUNT_NOT_MATCH"); address DODO = IDODOZoo(_DODO_ZOO_).getDODO(_WETH_, quoteTokenAddress); + require(DODO != address(0), "DODO_NOT_EXIST"); IWETH(_WETH_).deposit{value: ethAmount}(); IWETH(_WETH_).approve(DODO, ethAmount); IDODO(DODO).depositBaseTo(msg.sender, ethAmount); From bd2608270532b3dc85576ca22d691c935484675a Mon Sep 17 00:00:00 2001 From: mingda Date: Wed, 8 Jul 2020 17:59:57 +0800 Subject: [PATCH 016/118] [audit]#8 handle sqrt coner case --- contracts/lib/SafeMath.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/lib/SafeMath.sol b/contracts/lib/SafeMath.sol index 92eb396..8454b3a 100644 --- a/contracts/lib/SafeMath.sol +++ b/contracts/lib/SafeMath.sol @@ -53,7 +53,7 @@ library SafeMath { } function sqrt(uint256 x) internal pure returns (uint256 y) { - uint256 z = (x + 1) / 2; + uint256 z = add(x, 1) / 2; y = x; while (z < y) { y = z; From 37cfca3fbadaf909f8f90dc065937fe722d02cbb Mon Sep 17 00:00:00 2001 From: mingda Date: Wed, 8 Jul 2020 18:22:12 +0800 Subject: [PATCH 017/118] [audit]#9 improve math precision --- contracts/lib/DODOMath.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/lib/DODOMath.sol b/contracts/lib/DODOMath.sol index 181073a..3c1b5a3 100644 --- a/contracts/lib/DODOMath.sol +++ b/contracts/lib/DODOMath.sol @@ -85,7 +85,7 @@ library DODOMath { DecimalMath.ONE.sub(k).mul(4), DecimalMath.mul(k, Q0).mul(Q0) ); // 4(1-k)kQ0^2 - squareRoot = b.mul(b).add(squareRoot).sqrt(); // sqrt(b*b-4(1-k)kQ0*Q0) + squareRoot = b.mul(b).add(squareRoot).sqrt(); // sqrt(b*b+4(1-k)kQ0*Q0) // final res uint256 denominator = DecimalMath.ONE.sub(k).mul(2); // 2(1-k) @@ -108,7 +108,7 @@ library DODOMath { uint256 fairAmount ) internal pure returns (uint256 V0) { // V0 = V1+V1*(sqrt-1)/2k - uint256 sqrt = DecimalMath.divFloor(DecimalMath.mul(k, fairAmount), V1).mul(4); + uint256 sqrt = DecimalMath.divFloor(DecimalMath.mul(k, fairAmount).mul(4), V1); sqrt = sqrt.add(DecimalMath.ONE).mul(DecimalMath.ONE).sqrt(); uint256 premium = DecimalMath.divFloor(sqrt.sub(DecimalMath.ONE), k.mul(2)); // V0 is greater than or equal to V1 according to the solution From ded1375619021419bb282ae80ed1e963c3e732dd Mon Sep 17 00:00:00 2001 From: mingda Date: Thu, 9 Jul 2020 16:55:40 +0800 Subject: [PATCH 018/118] [audit]#10 remove dodo from zoo --- contracts/DODOZoo.sol | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contracts/DODOZoo.sol b/contracts/DODOZoo.sol index d42ce99..0dc08b8 100644 --- a/contracts/DODOZoo.sol +++ b/contracts/DODOZoo.sol @@ -58,6 +58,10 @@ contract DODOZoo is Ownable { return newBornDODO; } + function removeDODO(address baseToken, address quoteToken) public onlyOwner { + _DODO_REGISTER_[baseToken][quoteToken] = address(0); + } + // ============ View Functions ============ function isDODORegistered(address baseToken, address quoteToken) public view returns (bool) { From 9af81c1bd92c484c982a4ae432572be57c3eb1a6 Mon Sep 17 00:00:00 2001 From: mingda Date: Thu, 9 Jul 2020 17:59:25 +0800 Subject: [PATCH 019/118] gas optimize --- contracts/DODOEthProxy.sol | 5 +---- contracts/impl/Trader.sol | 24 ++++++++++++++++++------ 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/contracts/DODOEthProxy.sol b/contracts/DODOEthProxy.sol index bd64db3..6c831ac 100644 --- a/contracts/DODOEthProxy.sol +++ b/contracts/DODOEthProxy.sol @@ -68,11 +68,9 @@ contract DODOEthProxy is ReentrancyGuard { require(msg.value == ethAmount, "ETH_AMOUNT_NOT_MATCH"); address DODO = IDODOZoo(_DODO_ZOO_).getDODO(_WETH_, quoteTokenAddress); require(DODO != address(0), "DODO_NOT_EXIST"); - receiveTokenAmount = IDODO(DODO).querySellBaseToken(ethAmount); - require(receiveTokenAmount >= minReceiveTokenAmount, "RECEIVE_NOT_ENOUGH"); IWETH(_WETH_).deposit{value: ethAmount}(); IWETH(_WETH_).approve(DODO, ethAmount); - IDODO(DODO).sellBaseToken(ethAmount, minReceiveTokenAmount); + receiveTokenAmount = IDODO(DODO).sellBaseToken(ethAmount, minReceiveTokenAmount); _transferOut(quoteTokenAddress, msg.sender, receiveTokenAmount); emit ProxySellEth(msg.sender, quoteTokenAddress, ethAmount, receiveTokenAmount); return receiveTokenAmount; @@ -86,7 +84,6 @@ contract DODOEthProxy is ReentrancyGuard { address DODO = IDODOZoo(_DODO_ZOO_).getDODO(_WETH_, quoteTokenAddress); require(DODO != address(0), "DODO_NOT_EXIST"); payTokenAmount = IDODO(DODO).queryBuyBaseToken(ethAmount); - require(payTokenAmount <= maxPayTokenAmount, "PAY_TOO_MUCH"); _transferIn(quoteTokenAddress, msg.sender, payTokenAmount); IERC20(quoteTokenAddress).approve(DODO, payTokenAmount); IDODO(DODO).buyBaseToken(ethAmount, maxPayTokenAmount); diff --git a/contracts/impl/Trader.sol b/contracts/impl/Trader.sol index 19d9673..65b3060 100644 --- a/contracts/impl/Trader.sol +++ b/contracts/impl/Trader.sol @@ -70,9 +70,15 @@ contract Trader is Storage, Pricing, Settlement { _quoteTokenTransferOut(_MAINTAINER_, mtFeeQuote); // update TARGET - _TARGET_QUOTE_TOKEN_AMOUNT_ = newQuoteTarget; - _TARGET_BASE_TOKEN_AMOUNT_ = newBaseTarget; - _R_STATUS_ = newRStatus; + if (_TARGET_QUOTE_TOKEN_AMOUNT_ != newQuoteTarget) { + _TARGET_QUOTE_TOKEN_AMOUNT_ = newQuoteTarget; + } + if (_TARGET_BASE_TOKEN_AMOUNT_ != newBaseTarget) { + _TARGET_BASE_TOKEN_AMOUNT_ = newBaseTarget; + } + if (_R_STATUS_ != newRStatus) { + _R_STATUS_ = newRStatus; + } _donateQuoteToken(lpFeeQuote); emit SellBaseToken(msg.sender, amount, receiveQuote); @@ -105,9 +111,15 @@ contract Trader is Storage, Pricing, Settlement { _baseTokenTransferOut(_MAINTAINER_, mtFeeBase); // update TARGET - _TARGET_QUOTE_TOKEN_AMOUNT_ = newQuoteTarget; - _TARGET_BASE_TOKEN_AMOUNT_ = newBaseTarget; - _R_STATUS_ = newRStatus; + if (_TARGET_QUOTE_TOKEN_AMOUNT_ != newQuoteTarget) { + _TARGET_QUOTE_TOKEN_AMOUNT_ = newQuoteTarget; + } + if (_TARGET_BASE_TOKEN_AMOUNT_ != newBaseTarget) { + _TARGET_BASE_TOKEN_AMOUNT_ = newBaseTarget; + } + if (_R_STATUS_ != newRStatus) { + _R_STATUS_ = newRStatus; + } _donateBaseToken(lpFeeBase); emit BuyBaseToken(msg.sender, amount, payQuote); From 51be40478a079e449fcc94e5228d8694537eb401 Mon Sep 17 00:00:00 2001 From: mingda Date: Fri, 10 Jul 2020 13:32:20 +0800 Subject: [PATCH 020/118] [audit]#9.1 improve math precision --- contracts/lib/DODOMath.sol | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/contracts/lib/DODOMath.sol b/contracts/lib/DODOMath.sol index 3c1b5a3..606f344 100644 --- a/contracts/lib/DODOMath.sol +++ b/contracts/lib/DODOMath.sol @@ -35,9 +35,8 @@ library DODOMath { uint256 k ) internal pure returns (uint256) { uint256 fairAmount = DecimalMath.mul(i, V1.sub(V2)); // i*delta - uint256 V0V1 = DecimalMath.divCeil(V0, V1); // V0/V1 - uint256 V0V2 = DecimalMath.divCeil(V0, V2); // V0/V2 - uint256 penalty = DecimalMath.mul(DecimalMath.mul(k, V0V1), V0V2); // k(V0^2/V1/V2) + uint256 V0V0V1V2 = DecimalMath.divCeil(V0.mul(V0).div(V1), V2); + uint256 penalty = DecimalMath.mul(k, V0V0V1V2); // k(V0^2/V1/V2) return DecimalMath.mul(fairAmount, DecimalMath.ONE.sub(k).add(penalty)); } @@ -70,7 +69,7 @@ library DODOMath { if (deltaBSig) { b = b.add(ideltaB); // (1-k)Q1+i*deltaB } else { - kQ02Q1 = kQ02Q1.add(ideltaB); // -i*(-deltaB)-kQ0^2/Q1 + kQ02Q1 = kQ02Q1.add(ideltaB); // i*deltaB+kQ0^2/Q1 } if (b >= kQ02Q1) { b = b.sub(kQ02Q1); @@ -89,10 +88,17 @@ library DODOMath { // final res uint256 denominator = DecimalMath.ONE.sub(k).mul(2); // 2(1-k) + uint256 numerator; if (minusbSig) { - return DecimalMath.divFloor(b.add(squareRoot), denominator); + numerator = b.add(squareRoot); } else { - return DecimalMath.divFloor(squareRoot.sub(b), denominator); + numerator = squareRoot.sub(b); + } + + if (deltaBSig) { + return DecimalMath.divFloor(numerator, denominator); + } else { + return DecimalMath.divCeil(numerator, denominator); } } @@ -108,9 +114,9 @@ library DODOMath { uint256 fairAmount ) internal pure returns (uint256 V0) { // V0 = V1+V1*(sqrt-1)/2k - uint256 sqrt = DecimalMath.divFloor(DecimalMath.mul(k, fairAmount).mul(4), V1); + uint256 sqrt = DecimalMath.divCeil(DecimalMath.mul(k, fairAmount).mul(4), V1); sqrt = sqrt.add(DecimalMath.ONE).mul(DecimalMath.ONE).sqrt(); - uint256 premium = DecimalMath.divFloor(sqrt.sub(DecimalMath.ONE), k.mul(2)); + uint256 premium = DecimalMath.divCeil(sqrt.sub(DecimalMath.ONE), k.mul(2)); // V0 is greater than or equal to V1 according to the solution return DecimalMath.mul(V1, DecimalMath.ONE.add(premium)); } From 7ead33bc3745765d41e89ee61dd6fac39a5c7a9c Mon Sep 17 00:00:00 2001 From: mingda Date: Fri, 10 Jul 2020 13:33:12 +0800 Subject: [PATCH 021/118] [audit]#1.1 add symbol "DLP" to lptoken --- contracts/impl/DODOLpToken.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/impl/DODOLpToken.sol b/contracts/impl/DODOLpToken.sol index 9347be9..545b3a6 100644 --- a/contracts/impl/DODOLpToken.sol +++ b/contracts/impl/DODOLpToken.sol @@ -20,6 +20,7 @@ import {Ownable} from "../lib/Ownable.sol"; contract DODOLpToken is Ownable { using SafeMath for uint256; + string public symbol = "DLP"; string public name; uint8 public decimals; From f7bfead589f96b0e3446b292a9365505bc26bbee Mon Sep 17 00:00:00 2001 From: mingda Date: Fri, 10 Jul 2020 13:34:04 +0800 Subject: [PATCH 022/118] [audit]#8.1 handel sqrt coner case --- contracts/lib/SafeMath.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/lib/SafeMath.sol b/contracts/lib/SafeMath.sol index 8454b3a..f543fb4 100644 --- a/contracts/lib/SafeMath.sol +++ b/contracts/lib/SafeMath.sol @@ -53,7 +53,7 @@ library SafeMath { } function sqrt(uint256 x) internal pure returns (uint256 y) { - uint256 z = add(x, 1) / 2; + uint256 z = x / 2 + 1; y = x; while (z < y) { y = z; From be649f7750f1106eec51d1e67a8442a089c053ec Mon Sep 17 00:00:00 2001 From: mingda Date: Fri, 10 Jul 2020 13:35:10 +0800 Subject: [PATCH 023/118] [audit]#11 check balance when transfer in/out --- contracts/impl/Settlement.sol | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/contracts/impl/Settlement.sol b/contracts/impl/Settlement.sol index 7a7d769..016be05 100644 --- a/contracts/impl/Settlement.sol +++ b/contracts/impl/Settlement.sol @@ -36,23 +36,31 @@ contract Settlement is Storage { // ============ Assets IN/OUT Functions ============ function _baseTokenTransferIn(address from, uint256 amount) internal { + uint256 beforeBalance = IERC20(_BASE_TOKEN_).balanceOf(address(this)); IERC20(_BASE_TOKEN_).safeTransferFrom(from, address(this), amount); - _BASE_BALANCE_ = _BASE_BALANCE_.add(amount); + uint256 afterBalance = IERC20(_BASE_TOKEN_).balanceOf(address(this)); + _BASE_BALANCE_ = _BASE_BALANCE_.add(afterBalance.sub(beforeBalance)); } function _quoteTokenTransferIn(address from, uint256 amount) internal { + uint256 beforeBalance = IERC20(_QUOTE_TOKEN_).balanceOf(address(this)); IERC20(_QUOTE_TOKEN_).safeTransferFrom(from, address(this), amount); - _QUOTE_BALANCE_ = _QUOTE_BALANCE_.add(amount); + uint256 afterBalance = IERC20(_QUOTE_TOKEN_).balanceOf(address(this)); + _QUOTE_BALANCE_ = _QUOTE_BALANCE_.add(afterBalance.sub(beforeBalance)); } function _baseTokenTransferOut(address to, uint256 amount) internal { + uint256 beforeBalance = IERC20(_BASE_TOKEN_).balanceOf(address(this)); IERC20(_BASE_TOKEN_).safeTransfer(to, amount); - _BASE_BALANCE_ = _BASE_BALANCE_.sub(amount); + uint256 afterBalance = IERC20(_BASE_TOKEN_).balanceOf(address(this)); + _BASE_BALANCE_ = _BASE_BALANCE_.sub(beforeBalance.sub(afterBalance)); } function _quoteTokenTransferOut(address to, uint256 amount) internal { + uint256 beforeBalance = IERC20(_QUOTE_TOKEN_).balanceOf(address(this)); IERC20(_QUOTE_TOKEN_).safeTransfer(to, amount); - _QUOTE_BALANCE_ = _QUOTE_BALANCE_.sub(amount); + uint256 afterBalance = IERC20(_QUOTE_TOKEN_).balanceOf(address(this)); + _QUOTE_BALANCE_ = _QUOTE_BALANCE_.sub(beforeBalance.sub(afterBalance)); } // ============ Donate to Liquidity Pool Functions ============ From 6f3f1557d7ffd252744b33ba10714dbea6eb809a Mon Sep 17 00:00:00 2001 From: mingda Date: Sat, 11 Jul 2020 00:57:00 +0800 Subject: [PATCH 024/118] more events --- contracts/impl/Admin.sol | 16 ++++++++++++++-- contracts/impl/Trader.sol | 12 +++++++++--- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/contracts/impl/Admin.sol b/contracts/impl/Admin.sol index 9e0a7a1..fd89052 100644 --- a/contracts/impl/Admin.sol +++ b/contracts/impl/Admin.sol @@ -19,7 +19,16 @@ import {Storage} from "./Storage.sol"; contract Admin is Storage { // ============ Events ============ - event UpdateGasPriceLimit(uint256 newGasPriceLimit); + event UpdateGasPriceLimit(uint256 oldGasPriceLimit, uint256 newGasPriceLimit); + + event UpdateLiquidityProviderFeeRate( + uint256 oldLiquidityProviderFeeRate, + uint256 newLiquidityProviderFeeRate + ); + + event UpdateMaintainerFeeRate(uint256 oldMaintainerFeeRate, uint256 newMaintainerFeeRate); + + event UpdateK(uint256 oldK, uint256 newK); // ============ Params Setting Functions ============ @@ -36,23 +45,26 @@ contract Admin is Storage { } function setLiquidityProviderFeeRate(uint256 newLiquidityPorviderFeeRate) external onlyOwner { + emit UpdateLiquidityProviderFeeRate(_LP_FEE_RATE_, newLiquidityPorviderFeeRate); _LP_FEE_RATE_ = newLiquidityPorviderFeeRate; _checkDODOParameters(); } function setMaintainerFeeRate(uint256 newMaintainerFeeRate) external onlyOwner { + emit UpdateMaintainerFeeRate(_MT_FEE_RATE_, newMaintainerFeeRate); _MT_FEE_RATE_ = newMaintainerFeeRate; _checkDODOParameters(); } function setK(uint256 newK) external onlyOwner { + emit UpdateK(_K_, newK); _K_ = newK; _checkDODOParameters(); } function setGasPriceLimit(uint256 newGasPriceLimit) external onlySupervisorOrOwner { + emit UpdateGasPriceLimit(_GAS_PRICE_LIMIT_, newGasPriceLimit); _GAS_PRICE_LIMIT_ = newGasPriceLimit; - emit UpdateGasPriceLimit(newGasPriceLimit); } // ============ System Control Functions ============ diff --git a/contracts/impl/Trader.sol b/contracts/impl/Trader.sol index 65b3060..ecb8c1e 100644 --- a/contracts/impl/Trader.sol +++ b/contracts/impl/Trader.sol @@ -30,7 +30,9 @@ contract Trader is Storage, Pricing, Settlement { event BuyBaseToken(address indexed buyer, uint256 receiveBase, uint256 payQuote); - event MaintainerFee(bool isBaseToken, uint256 amount); + event ChargeMaintainerFeeBase(address indexed maintainer, uint256 amount); + + event ChargeMaintainerFeeQuote(address indexed maintainer, uint256 amount); // ============ Modifiers ============ @@ -82,7 +84,9 @@ contract Trader is Storage, Pricing, Settlement { _donateQuoteToken(lpFeeQuote); emit SellBaseToken(msg.sender, amount, receiveQuote); - emit MaintainerFee(false, mtFeeQuote); + if (mtFeeQuote != 0) { + emit ChargeMaintainerFeeQuote(_MAINTAINER_, mtFeeQuote); + } return receiveQuote; } @@ -123,7 +127,9 @@ contract Trader is Storage, Pricing, Settlement { _donateBaseToken(lpFeeBase); emit BuyBaseToken(msg.sender, amount, payQuote); - emit MaintainerFee(true, mtFeeBase); + if (mtFeeBase != 0) { + emit ChargeMaintainerFeeBase(_MAINTAINER_, mtFeeBase); + } return payQuote; } From 31e325e9c6bda42748bf9528e953cc02968ceb4d Mon Sep 17 00:00:00 2001 From: mingda Date: Sat, 11 Jul 2020 01:11:10 +0800 Subject: [PATCH 025/118] add withdraw & withdrawAll func to DODO Eth proxy --- contracts/DODOEthProxy.sol | 58 ++++++++++++++++++++++++++++++++++++-- contracts/intf/IDODO.sol | 4 +++ 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/contracts/DODOEthProxy.sol b/contracts/DODOEthProxy.sol index 6c831ac..2a3edd2 100644 --- a/contracts/DODOEthProxy.sol +++ b/contracts/DODOEthProxy.sol @@ -19,7 +19,7 @@ import {IWETH} from "./intf/IWETH.sol"; * @title DODO Eth Proxy * @author DODO Breeder * - * @notice Handle ETH-WETH converting for users + * @notice Handle ETH-WETH converting for users. Use it only when WETH is base token */ contract DODOEthProxy is ReentrancyGuard { using SafeERC20 for IERC20; @@ -43,7 +43,9 @@ contract DODOEthProxy is ReentrancyGuard { uint256 payQuote ); - event ProxyDepositEth(address indexed lp, address indexed quoteToken, uint256 ethAmount); + event ProxyDepositEth(address indexed lp, address indexed DODO, uint256 ethAmount); + + event ProxyWithdrawEth(address indexed lp, address indexed DODO, uint256 ethAmount); // ============ Functions ============ @@ -104,7 +106,57 @@ contract DODOEthProxy is ReentrancyGuard { IWETH(_WETH_).deposit{value: ethAmount}(); IWETH(_WETH_).approve(DODO, ethAmount); IDODO(DODO).depositBaseTo(msg.sender, ethAmount); - emit ProxyDepositEth(msg.sender, quoteTokenAddress, ethAmount); + emit ProxyDepositEth(msg.sender, DODO, ethAmount); + } + + function withdrawEth(uint256 ethAmount, address quoteTokenAddress) + external + preventReentrant + returns (uint256 withdrawAmount) + { + address DODO = IDODOZoo(_DODO_ZOO_).getDODO(_WETH_, quoteTokenAddress); + require(DODO != address(0), "DODO_NOT_EXIST"); + address ethLpToken = IDODO(DODO)._BASE_CAPITAL_TOKEN_(); + + // transfer all pool shares to proxy + uint256 lpBalance = IERC20(ethLpToken).balanceOf(msg.sender); + IERC20(ethLpToken).transferFrom(msg.sender, address(this), lpBalance); + IDODO(DODO).withdrawBase(ethAmount); + + // transfer remain shares back to msg.sender + lpBalance = IERC20(ethLpToken).balanceOf(address(this)); + IERC20(ethLpToken).transfer(msg.sender, lpBalance); + + // because of withdraw penalty, withdrawAmount may not equal to ethAmount + // query weth amount first and than transfer ETH to msg.sender + uint256 wethAmount = IERC20(_WETH_).balanceOf(address(this)); + IWETH(_WETH_).withdraw(wethAmount); + msg.sender.transfer(wethAmount); + emit ProxyWithdrawEth(msg.sender, DODO, wethAmount); + return wethAmount; + } + + function withdrawAllEth(address quoteTokenAddress) + external + preventReentrant + returns (uint256 withdrawAmount) + { + address DODO = IDODOZoo(_DODO_ZOO_).getDODO(_WETH_, quoteTokenAddress); + require(DODO != address(0), "DODO_NOT_EXIST"); + address ethLpToken = IDODO(DODO)._BASE_CAPITAL_TOKEN_(); + + // transfer all pool shares to proxy + uint256 lpBalance = IERC20(ethLpToken).balanceOf(msg.sender); + IERC20(ethLpToken).transferFrom(msg.sender, address(this), lpBalance); + IDODO(DODO).withdrawAllBase(); + + // because of withdraw penalty, withdrawAmount may not equal to ethAmount + // query weth amount first and than transfer ETH to msg.sender + uint256 wethAmount = IERC20(_WETH_).balanceOf(address(this)); + IWETH(_WETH_).withdraw(wethAmount); + msg.sender.transfer(wethAmount); + emit ProxyWithdrawEth(msg.sender, DODO, wethAmount); + return wethAmount; } // ============ Helper Functions ============ diff --git a/contracts/intf/IDODO.sol b/contracts/intf/IDODO.sol index c27119a..2b6e45d 100644 --- a/contracts/intf/IDODO.sol +++ b/contracts/intf/IDODO.sol @@ -44,4 +44,8 @@ interface IDODO { function withdrawQuote(uint256 amount) external returns (uint256); function withdrawAllQuote() external returns (uint256); + + function _BASE_CAPITAL_TOKEN_() external returns (address); + + function _QUOTE_CAPITAL_TOKEN_() external returns (address); } From 40fb80e9e79f639f19a63d64628966fc153069d4 Mon Sep 17 00:00:00 2001 From: mingda Date: Sat, 11 Jul 2020 01:16:26 +0800 Subject: [PATCH 026/118] add getMidPrice --- contracts/impl/Pricing.sol | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/contracts/impl/Pricing.sol b/contracts/impl/Pricing.sol index eaeda9b..ee88a7f 100644 --- a/contracts/impl/Pricing.sol +++ b/contracts/impl/Pricing.sol @@ -157,6 +157,25 @@ contract Pricing is Storage { } } + function getMidPrice() public view returns (uint256 midPrice) { + (uint256 baseTarget, uint256 quoteTarget) = getExpectedTarget(); + if (_R_STATUS_ == Types.RStatus.BELOW_ONE) { + uint256 R = DecimalMath.divFloor( + quoteTarget.mul(quoteTarget).div(_QUOTE_BALANCE_), + _QUOTE_BALANCE_ + ); + R = DecimalMath.ONE.sub(_K_).add(DecimalMath.mul(_K_, R)); + return DecimalMath.divFloor(getOraclePrice(), R); + } else { + uint256 R = DecimalMath.divFloor( + baseTarget.mul(baseTarget).div(_BASE_BALANCE_), + _BASE_BALANCE_ + ); + R = DecimalMath.ONE.sub(_K_).add(DecimalMath.mul(_K_, R)); + return DecimalMath.mul(getOraclePrice(), R); + } + } + function _RAboveIntegrate( uint256 B0, uint256 B1, From 4270042fa944bbe5125d7203c3d2d33bfe632856 Mon Sep 17 00:00:00 2001 From: mingda Date: Sat, 11 Jul 2020 01:28:21 +0800 Subject: [PATCH 027/118] log lp token change --- contracts/impl/LiquidityProvider.sol | 46 ++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/contracts/impl/LiquidityProvider.sol b/contracts/impl/LiquidityProvider.sol index 2e10523..2e88a4e 100644 --- a/contracts/impl/LiquidityProvider.sol +++ b/contracts/impl/LiquidityProvider.sol @@ -28,13 +28,33 @@ contract LiquidityProvider is Storage, Pricing, Settlement { // ============ Events ============ - event DepositBaseToken(address indexed payer, address indexed receiver, uint256 amount); + event DepositBaseToken( + address indexed payer, + address indexed receiver, + uint256 amount, + uint256 lpTokenAmount + ); - event DepositQuoteToken(address indexed payer, address indexed receiver, uint256 amount); + event DepositQuoteToken( + address indexed payer, + address indexed receiver, + uint256 amount, + uint256 lpTokenAmount + ); - event WithdrawBaseToken(address indexed payer, address indexed receiver, uint256 amount); + event WithdrawBaseToken( + address indexed payer, + address indexed receiver, + uint256 amount, + uint256 lpTokenAmount + ); - event WithdrawQuoteToken(address indexed payer, address indexed receiver, uint256 amount); + event WithdrawQuoteToken( + address indexed payer, + address indexed receiver, + uint256 amount, + uint256 lpTokenAmount + ); event ChargeBasePenalty(address indexed payer, uint256 amount); @@ -100,7 +120,7 @@ contract LiquidityProvider is Storage, Pricing, Settlement { _mintQuoteCapital(to, capital); _TARGET_QUOTE_TOKEN_AMOUNT_ = _TARGET_QUOTE_TOKEN_AMOUNT_.add(amount); - emit DepositQuoteToken(msg.sender, to, amount); + emit DepositQuoteToken(msg.sender, to, amount, capital); } function depositBaseTo(address to, uint256 amount) public preventReentrant depositBaseAllowed { @@ -119,7 +139,7 @@ contract LiquidityProvider is Storage, Pricing, Settlement { _mintBaseCapital(to, capital); _TARGET_BASE_TOKEN_AMOUNT_ = _TARGET_BASE_TOKEN_AMOUNT_.add(amount); - emit DepositBaseToken(msg.sender, to, amount); + emit DepositBaseToken(msg.sender, to, amount, capital); } // ============ Withdraw Functions ============ @@ -146,7 +166,7 @@ contract LiquidityProvider is Storage, Pricing, Settlement { _quoteTokenTransferOut(to, amount.sub(penalty)); _donateQuoteToken(penalty); - emit WithdrawQuoteToken(msg.sender, to, amount.sub(penalty)); + emit WithdrawQuoteToken(msg.sender, to, amount.sub(penalty), requireQuoteCapital); emit ChargeQuotePenalty(msg.sender, penalty); return amount.sub(penalty); @@ -174,7 +194,7 @@ contract LiquidityProvider is Storage, Pricing, Settlement { _baseTokenTransferOut(to, amount.sub(penalty)); _donateBaseToken(penalty); - emit WithdrawBaseToken(msg.sender, to, amount.sub(penalty)); + emit WithdrawBaseToken(msg.sender, to, amount.sub(penalty), requireBaseCapital); emit ChargeBasePenalty(msg.sender, penalty); return amount.sub(penalty); @@ -184,6 +204,7 @@ contract LiquidityProvider is Storage, Pricing, Settlement { function withdrawAllQuoteTo(address to) public preventReentrant returns (uint256) { uint256 withdrawAmount = getLpQuoteBalance(msg.sender); + uint256 capital = getQuoteCapitalBalanceOf(msg.sender); // handle penalty, penalty may exceed amount uint256 penalty = getWithdrawQuotePenalty(withdrawAmount); @@ -191,11 +212,11 @@ contract LiquidityProvider is Storage, Pricing, Settlement { // settlement _TARGET_QUOTE_TOKEN_AMOUNT_ = _TARGET_QUOTE_TOKEN_AMOUNT_.sub(withdrawAmount); - _burnQuoteCapital(msg.sender, getQuoteCapitalBalanceOf(msg.sender)); + _burnQuoteCapital(msg.sender, capital); _quoteTokenTransferOut(to, withdrawAmount.sub(penalty)); _donateQuoteToken(penalty); - emit WithdrawQuoteToken(msg.sender, to, withdrawAmount); + emit WithdrawQuoteToken(msg.sender, to, withdrawAmount, capital); emit ChargeQuotePenalty(msg.sender, penalty); return withdrawAmount.sub(penalty); @@ -203,6 +224,7 @@ contract LiquidityProvider is Storage, Pricing, Settlement { function withdrawAllBaseTo(address to) public preventReentrant returns (uint256) { uint256 withdrawAmount = getLpBaseBalance(msg.sender); + uint256 capital = getBaseCapitalBalanceOf(msg.sender); // handle penalty, penalty may exceed amount uint256 penalty = getWithdrawBasePenalty(withdrawAmount); @@ -210,11 +232,11 @@ contract LiquidityProvider is Storage, Pricing, Settlement { // settlement _TARGET_BASE_TOKEN_AMOUNT_ = _TARGET_BASE_TOKEN_AMOUNT_.sub(withdrawAmount); - _burnBaseCapital(msg.sender, getBaseCapitalBalanceOf(msg.sender)); + _burnBaseCapital(msg.sender, capital); _baseTokenTransferOut(to, withdrawAmount.sub(penalty)); _donateBaseToken(penalty); - emit WithdrawBaseToken(msg.sender, to, withdrawAmount); + emit WithdrawBaseToken(msg.sender, to, withdrawAmount, capital); emit ChargeBasePenalty(msg.sender, penalty); return withdrawAmount.sub(penalty); From ad552cf969c57c254a1760aabb483d7a62afbb1e Mon Sep 17 00:00:00 2001 From: mingda Date: Sat, 11 Jul 2020 11:50:33 +0800 Subject: [PATCH 028/118] fix test --- test/Admin.test.ts | 2 +- test/DODOEthProxy.test.ts | 30 ++++++++++++++--- test/DODOZoo.test.ts | 10 ++++-- test/LiquidityProvider.test.ts | 60 ++++++++++++++++----------------- test/LongTailTokenlMode.test.ts | 6 ++-- test/StableCoinMode.test.ts | 8 ++--- test/Trader.test.ts | 60 ++++++++++++++++++--------------- test/utils/Context.ts | 6 ++-- 8 files changed, 108 insertions(+), 74 deletions(-) diff --git a/test/Admin.test.ts b/test/Admin.test.ts index 44080e5..400c00c 100644 --- a/test/Admin.test.ts +++ b/test/Admin.test.ts @@ -221,7 +221,7 @@ describe("Admin", () => { await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp1)) await ctx.DODO.methods.withdrawAllQuote().send(ctx.sendParam(lp1)) assert.equal(await ctx.BASE.methods.balanceOf(lp1).call(), decimalStr("105")) - assert.equal(await ctx.QUOTE.methods.balanceOf(lp1).call(), "9540265973590798352834") + assert.equal(await ctx.QUOTE.methods.balanceOf(lp1).call(), "9540265973590798352835") }) it("final settlement revert cases", async () => { diff --git a/test/DODOEthProxy.test.ts b/test/DODOEthProxy.test.ts index db3e7d7..8be69d2 100644 --- a/test/DODOEthProxy.test.ts +++ b/test/DODOEthProxy.test.ts @@ -10,6 +10,7 @@ import * as contracts from "./utils/Contracts"; import * as assert from "assert" import { decimalStr, MAX_UINT256 } from './utils/Converter'; import { Contract } from "web3-eth-contract"; +import { logGas } from './utils/Log'; let lp: string let trader: string @@ -37,7 +38,6 @@ async function init(ctx: DODOContext): Promise { DODOEthProxy = await contracts.newContract(contracts.DODO_ETH_PROXY_CONTRACT_NAME, [ctx.DODOZoo.options.address, WETH.options.address]) - // env lp = ctx.spareAccounts[0] trader = ctx.spareAccounts[1] @@ -76,16 +76,38 @@ describe("DODO ETH PROXY", () => { describe("buy&sell eth directly", () => { it("buy", async () => { let buyAmount = "1" - await DODOEthProxy.methods.buyEthWith(ctx.QUOTE.options.address, decimalStr(buyAmount), decimalStr("200")).send(ctx.sendParam(trader)) + logGas(await DODOEthProxy.methods.buyEthWith(ctx.QUOTE.options.address, decimalStr(buyAmount), decimalStr("200")).send(ctx.sendParam(trader)), "buy with eth directly") assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("8.999")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "898581839502056240973") ctx.Web3 }) it("sell", async () => { let sellAmount = "1" - await DODOEthProxy.methods.sellEthTo(ctx.QUOTE.options.address, decimalStr(sellAmount), decimalStr("50")).send(ctx.sendParam(trader, sellAmount)) + logGas(await DODOEthProxy.methods.sellEthTo(ctx.QUOTE.options.address, decimalStr(sellAmount), decimalStr("50")).send(ctx.sendParam(trader, sellAmount)), "sell to eth directly") assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("11")) - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1098617454226610630664") + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1098617454226610630663") + }) + }) + + describe("withdraw eth directly", () => { + it("withdraw", async () => { + let baseLpTokenAddress = await ctx.DODO.methods._BASE_CAPITAL_TOKEN_().call() + let baseLpToken = contracts.getContractWithAddress(contracts.TEST_ERC20_CONTRACT_NAME, baseLpTokenAddress) + await baseLpToken.methods.approve(DODOEthProxy.options.address, MAX_UINT256).send(ctx.sendParam(lp)) + await DODOEthProxy.methods.withdrawEth(decimalStr("5"), ctx.QUOTE.options.address).send(ctx.sendParam(lp)) + + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp).call(), decimalStr("5")) + // console.log(await ctx.Web3.eth.getBalance(lp)) eth balance confirmed + }) + + it("withdraw all", async () => { + let baseLpTokenAddress = await ctx.DODO.methods._BASE_CAPITAL_TOKEN_().call() + let baseLpToken = contracts.getContractWithAddress(contracts.TEST_ERC20_CONTRACT_NAME, baseLpTokenAddress) + await baseLpToken.methods.approve(DODOEthProxy.options.address, MAX_UINT256).send(ctx.sendParam(lp)) + await DODOEthProxy.methods.withdrawAllEth(ctx.QUOTE.options.address).send(ctx.sendParam(lp)) + + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp).call(), "0") + // console.log(await ctx.Web3.eth.getBalance(lp)) eth balance confirmed }) }) diff --git a/test/DODOZoo.test.ts b/test/DODOZoo.test.ts index 83b0a0f..ce3ddd7 100644 --- a/test/DODOZoo.test.ts +++ b/test/DODOZoo.test.ts @@ -44,8 +44,8 @@ describe("DODO ZOO", () => { }) it("breed new dodo", async () => { - let newBase = await newContract(TEST_ERC20_CONTRACT_NAME) - let newQuote = await newContract(TEST_ERC20_CONTRACT_NAME) + let newBase = await newContract(TEST_ERC20_CONTRACT_NAME, ["AnotherBase", 18]) + let newQuote = await newContract(TEST_ERC20_CONTRACT_NAME, ["AnotherQuote", 18]) await assert.rejects( ctx.DODOZoo.methods.breedDODO(ctx.Supervisor, ctx.Maintainer, newBase.options.address, newQuote.options.address, ctx.ORACLE.options.address, "0", "0", "1", "0").send(ctx.sendParam(ctx.Maintainer)), /NOT_OWNER/ @@ -56,6 +56,8 @@ describe("DODO ZOO", () => { assert.equal(await newDODO.methods._BASE_TOKEN_().call(), newBase.options.address) assert.equal(await newDODO.methods._QUOTE_TOKEN_().call(), newQuote.options.address) + await newDODO.methods.claimOwnership().send(ctx.sendParam(ctx.Deployer)) + // could not init twice await assert.rejects( newDODO.methods.init(ctx.Supervisor, ctx.Maintainer, ctx.QUOTE.options.address, ctx.BASE.options.address, ctx.ORACLE.options.address, "0", "0", "1", "0").send(ctx.sendParam(ctx.Deployer)), @@ -63,6 +65,10 @@ describe("DODO ZOO", () => { ) }) + it("remove dodo", async () => { + await ctx.DODOZoo.methods.removeDODO(ctx.BASE.options.address, ctx.QUOTE.options.address).send(ctx.sendParam(ctx.Deployer)) + assert.equal(await ctx.DODOZoo.methods.getDODO(ctx.BASE.options.address, ctx.QUOTE.options.address).call(), "0x0000000000000000000000000000000000000000") + }) }) }) \ No newline at end of file diff --git a/test/LiquidityProvider.test.ts b/test/LiquidityProvider.test.ts index 658c318..95f7306 100644 --- a/test/LiquidityProvider.test.ts +++ b/test/LiquidityProvider.test.ts @@ -100,13 +100,13 @@ describe("LiquidityProvider", () => { // lp1 & lp2 would both have profit because the curve becomes flatter // but the withdraw penalty is greater than this free profit - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "10163234422929069690") + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "10163234422929069723") assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), decimalStr("1000")) - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp2).call(), "5076114129127759275") + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp2).call(), "5076114129127759292") assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp2).call(), decimalStr("100")) - assert.equal(await ctx.DODO.methods.getWithdrawBasePenalty(decimalStr("5")).call(), "228507420047606043") + assert.equal(await ctx.DODO.methods.getWithdrawBasePenalty(decimalStr("5")).call(), "228507420047606093") assert.equal(await ctx.DODO.methods.getWithdrawQuotePenalty(decimalStr("100")).call(), "0") }) @@ -115,13 +115,13 @@ describe("LiquidityProvider", () => { await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000")).send(ctx.sendParam(trader)) - assert.equal(await ctx.DODO.methods.getWithdrawBasePenalty(decimalStr("4")).call(), "1065045389392391670") + assert.equal(await ctx.DODO.methods.getWithdrawBasePenalty(decimalStr("4")).call(), "1065045389392391665") assert.equal(await ctx.DODO.methods.getWithdrawQuotePenalty(decimalStr("100")).call(), "0") await ctx.DODO.methods.withdrawBase(decimalStr("4")).send(ctx.sendParam(lp1)) - assert.equal(await ctx.BASE.methods.balanceOf(lp1).call(), "92934954610607608330") - assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), "2060045389392391670") - assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "7075045389392391670") + assert.equal(await ctx.BASE.methods.balanceOf(lp1).call(), "92934954610607608335") + assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), "2060045389392391665") + assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "7075045389392391665") await ctx.DODO.methods.withdrawQuote(decimalStr("100")).send(ctx.sendParam(lp1)) assert.equal(await ctx.QUOTE.methods.balanceOf(lp1).call(), decimalStr("9100")) @@ -137,19 +137,19 @@ describe("LiquidityProvider", () => { await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("200")).send(ctx.sendParam(trader)) assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), decimalStr("10")) - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), "1000978629616255274293") + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), "1000978629616255276996") await ctx.DODO.methods.depositQuote(decimalStr("500")).send(ctx.sendParam(lp2)) await ctx.DODO.methods.depositBase(decimalStr("5")).send(ctx.sendParam(lp2)) assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), decimalStr("10")) - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), "1012529270910521748792") + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), "1012529270910521756641") assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp2).call(), decimalStr("5")) - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp2).call(), "505769674273013520099") + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp2).call(), "505769674273013522654") assert.equal(await ctx.DODO.methods.getWithdrawBasePenalty(decimalStr("5")).call(), "0") - assert.equal(await ctx.DODO.methods.getWithdrawQuotePenalty(decimalStr("500")).call(), "17320315567279994599") + assert.equal(await ctx.DODO.methods.getWithdrawQuotePenalty(decimalStr("500")).call(), "17320315567280002300") }) it("withdraw", async () => { @@ -158,12 +158,12 @@ describe("LiquidityProvider", () => { await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("200")).send(ctx.sendParam(trader)) assert.equal(await ctx.DODO.methods.getWithdrawBasePenalty(decimalStr("4")).call(), "0") - assert.equal(await ctx.DODO.methods.getWithdrawQuotePenalty(decimalStr("100")).call(), "7389428846238898052") + assert.equal(await ctx.DODO.methods.getWithdrawQuotePenalty(decimalStr("100")).call(), "7389428846238900753") await ctx.DODO.methods.withdrawQuote(decimalStr("100")).send(ctx.sendParam(lp1)) - assert.equal(await ctx.QUOTE.methods.balanceOf(lp1).call(), "9092610571153761101948") - assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "447655402437037250886") - assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), "908310739520405634819") + assert.equal(await ctx.QUOTE.methods.balanceOf(lp1).call(), "9092610571153761099247") + assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "447655402437037253588") + assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), "908310739520405637520") await ctx.DODO.methods.withdrawBase(decimalStr("4")).send(ctx.sendParam(lp1)) assert.equal(await ctx.BASE.methods.balanceOf(lp1).call(), decimalStr("94")) @@ -181,12 +181,12 @@ describe("LiquidityProvider", () => { await ctx.setOraclePrice(decimalStr("80")); assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), decimalStr("10")) - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), "914362409397559034505") + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), "914362409397559037208") await ctx.setOraclePrice(decimalStr("120")) assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), decimalStr("10")) - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), "1085284653936129403614") + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), "1085284653936129406317") }) it("quote side lp don't has pnl when R is ABOVE ONE", async () => { @@ -201,7 +201,7 @@ describe("LiquidityProvider", () => { await ctx.setOraclePrice(decimalStr("120")) - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "9234731968726215538") + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "9234731968726215588") assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), decimalStr("1000")) }) @@ -281,13 +281,13 @@ describe("LiquidityProvider", () => { await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("0")).send(ctx.sendParam(trader)) assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "2") - assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "9234731968726215513") + assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "9234731968726215603") assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), "1105993618321025490") await ctx.DODO.methods.depositQuote("1").send(ctx.sendParam(lp2)) - assert.equal(await ctx.DODO.methods.getQuoteCapitalBalanceOf(lp2).call(), "7221653398290522326") - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp2).call(), "7221653398290522382") - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "9234731968726215513") + assert.equal(await ctx.DODO.methods.getQuoteCapitalBalanceOf(lp2).call(), "7221653398290521828") + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp2).call(), "7221653398290521884") + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "9234731968726215603") }) it("single side deposit (base) & oracle change introduces profit", async () => { @@ -303,8 +303,8 @@ describe("LiquidityProvider", () => { assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), "1105408308382702868") await ctx.DODO.methods.depositQuote("1").send(ctx.sendParam(lp2)) - assert.equal(await ctx.DODO.methods.getQuoteCapitalBalanceOf(lp2).call(), "21553269260529319697") - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp2).call(), "21553269260529319725") + assert.equal(await ctx.DODO.methods.getQuoteCapitalBalanceOf(lp2).call(), "21553269260529319669") + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp2).call(), "21553269260529319697") assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "11138732839027528584") }) @@ -318,12 +318,12 @@ describe("LiquidityProvider", () => { assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "1") assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "9980000000000000") - assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), "914362409397559031579") + assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), "914362409397559035414") await ctx.DODO.methods.depositBase("1").send(ctx.sendParam(lp2)) assert.equal(await ctx.DODO.methods.getBaseCapitalBalanceOf(lp2).call(), "10247647352975730") assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp2).call(), "10247647352975730") - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), "914362409397559031579") + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), "914362409397559035414") }) it("deposit and withdraw immediately", async () => { @@ -334,13 +334,13 @@ describe("LiquidityProvider", () => { await ctx.DODO.methods.depositBase(decimalStr("5")).send(ctx.sendParam(lp2)) - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "10163234422929069690") - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp2).call(), "5076114129127759275") + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "10163234422929069723") + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp2).call(), "5076114129127759292") await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp2)) - assert.equal(await ctx.BASE.methods.balanceOf(lp2).call(), "99841132414635941818") - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "10182702153814588570") + assert.equal(await ctx.BASE.methods.balanceOf(lp2).call(), "99841132414635941792") + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "10182702153814588648") }) }) diff --git a/test/LongTailTokenlMode.test.ts b/test/LongTailTokenlMode.test.ts index bdc7707..cc2d19d 100644 --- a/test/LongTailTokenlMode.test.ts +++ b/test/LongTailTokenlMode.test.ts @@ -63,19 +63,19 @@ describe("Trader", () => { // avg price = 12.475 await ctx.DODO.methods.buyBaseToken(decimalStr("1000"), decimalStr("100000")).send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("2000")) - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "9975050000000000000020000") + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "9975049999999999999970000") // 50% depth // avg price = 19.9 await ctx.DODO.methods.buyBaseToken(decimalStr("3000"), decimalStr("300000")).send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("5000")) - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "9900500000000000000260000") + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "9900499999999999999970000") // 80% depth // avg price = 49.6 await ctx.DODO.methods.buyBaseToken(decimalStr("3000"), decimalStr("300000")).send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("8000")) - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "9603200000000000001130000") + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "9603199999999999999970000") }) it("user has no pnl if buy and sell immediately", async () => { diff --git a/test/StableCoinMode.test.ts b/test/StableCoinMode.test.ts index c1bd248..204a88f 100644 --- a/test/StableCoinMode.test.ts +++ b/test/StableCoinMode.test.ts @@ -61,12 +61,12 @@ describe("Trader", () => { // 99.9% depth avg price 1.00010109 await ctx.DODO.methods.buyBaseToken(decimalStr("8990"), decimalStr("10000")).send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("19990")) - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "8990031967821738650") + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "8990031967806921648") // sell to 99.9% depth avg price 0.9999 await ctx.DODO.methods.sellBaseToken(decimalStr("19980"), decimalStr("19970")).send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("10")) - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "19986992950440794519885") + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "19986992950440794518402") }) it("huge sell trading amount", async () => { @@ -76,7 +76,7 @@ describe("Trader", () => { await ctx.DODO.methods.sellBaseToken(decimalStr("20000"), decimalStr("0")).send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("0")) - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "19998999990001000029998") + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "19998999990001000029997") }) it("huge buy trading amount", async () => { @@ -97,7 +97,7 @@ describe("Trader", () => { await ctx.DODO.methods.buyBaseToken(decimalStr("9990"), decimalStr("10000")).send(ctx.sendParam(trader)) // penalty only 0.2% even if withdraw make pool utilization rate raise to 99.5% - assert.equal(await ctx.DODO.methods.getWithdrawBasePenalty(decimalStr("5")).call(), "9981962500000000") + assert.equal(await ctx.DODO.methods.getWithdrawBasePenalty(decimalStr("5")).call(), "9981967500000000") }) }) }) \ No newline at end of file diff --git a/test/Trader.test.ts b/test/Trader.test.ts index 1fbbd59..58fcdb7 100644 --- a/test/Trader.test.ts +++ b/test/Trader.test.ts @@ -48,7 +48,7 @@ describe("Trader", () => { describe("R goes above ONE", () => { it("buy when R equals ONE", async () => { - logGas(await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110")).send(ctx.sendParam(trader)), "buy base token") + logGas(await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110")).send(ctx.sendParam(trader)), "buy base token when balanced") // trader balances assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("11")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "898581839502056240973") @@ -58,25 +58,27 @@ describe("Trader", () => { // dodo balances assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("8.999")) assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "1101418160497943759027") + // price update + assert.equal(await ctx.DODO.methods.getMidPrice().call(), "102353368821735563400") }) it("buy when R is ABOVE ONE", async () => { await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110")).send(ctx.sendParam(trader)) - await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("130")).send(ctx.sendParam(trader)) + logGas(await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("130")).send(ctx.sendParam(trader)), "buy when R is ABOVE ONE") // trader balances assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("12")) - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "794367183433412077753") + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "794367183433412077653") // maintainer balances assert.equal(await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), decimalStr("0.002")) assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), decimalStr("0")) // dodo balances assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("7.998")) - assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "1205632816566587922247") + assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "1205632816566587922347") }) it("sell when R is ABOVE ONE", async () => { await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110")).send(ctx.sendParam(trader)) - await ctx.DODO.methods.sellBaseToken(decimalStr("0.5"), decimalStr("40")).send(ctx.sendParam(trader)) + logGas(await ctx.DODO.methods.sellBaseToken(decimalStr("0.5"), decimalStr("40")).send(ctx.sendParam(trader)), "sell when R is ABOVE ONE") // trader balances assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("10.5")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "949280846351657143136") @@ -90,7 +92,7 @@ describe("Trader", () => { it("sell when R is ABOVE ONE and RStatus back to ONE", async () => { await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110")).send(ctx.sendParam(trader)) - await ctx.DODO.methods.sellBaseToken("1003002430889317763", decimalStr("90")).send(ctx.sendParam(trader)) + logGas(await ctx.DODO.methods.sellBaseToken("1003002430889317763", decimalStr("90")).send(ctx.sendParam(trader)), "sell when R is ABOVE ONE and RStatus back to ONE") // R status assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0") // trader balances @@ -109,18 +111,18 @@ describe("Trader", () => { it("sell when R is ABOVE ONE and RStatus becomes BELOW ONE", async () => { await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110")).send(ctx.sendParam(trader)) - logGas(await ctx.DODO.methods.sellBaseToken(decimalStr("2"), decimalStr("90")).send(ctx.sendParam(trader)), "sell base token gas cost worst case") + logGas(await ctx.DODO.methods.sellBaseToken(decimalStr("2"), decimalStr("90")).send(ctx.sendParam(trader)), "sell when R is ABOVE ONE and RStatus becomes BELOW ONE [gas cost worst case]") // R status assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "2") // trader balances assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("9")) - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1098020621600061709145") + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1098020621600061709144") // maintainer balances assert.equal(await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), decimalStr("0.001")) assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), "200038898794388634") // dodo balances assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("10.999")) - assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "901779339501143902221") + assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "901779339501143902222") // target status assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "10002002430889317763") assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), "1000400077797588777268") @@ -129,82 +131,84 @@ describe("Trader", () => { describe("R goes below ONE", () => { it("sell when R equals ONE", async () => { - logGas(await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90")).send(ctx.sendParam(trader)), "sell base token") + logGas(await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90")).send(ctx.sendParam(trader)), "sell base token when balanced") // trader balances assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("9")) - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1098617454226610630664") + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1098617454226610630663") // maintainer balances assert.equal(await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), "0") assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), "98914196817061816") // dodo balances assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("11")) - assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "901283631576572307520") + assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "901283631576572307521") + // price update + assert.equal(await ctx.DODO.methods.getMidPrice().call(), "97736983274307939149") }) it("sell when R is BELOW ONE", async () => { await ctx.DODO.methods.sellBaseToken(decimalStr("3"), decimalStr("90")).send(ctx.sendParam(trader)) - await ctx.DODO.methods.sellBaseToken(decimalStr("3"), decimalStr("90")).send(ctx.sendParam(trader)) + logGas(await ctx.DODO.methods.sellBaseToken(decimalStr("3"), decimalStr("90")).send(ctx.sendParam(trader)), "sell when R is BELOW ONE") // trader balances assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("4")) - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1535961012052716726546") + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1535961012052716726151") // maintainer balances assert.equal(await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), "0") assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), "537573733252474148") // dodo balances assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("16")) - assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "463501414214030799306") + assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "463501414214030799701") }) it("buy when R is BELOW ONE", async () => { await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90")).send(ctx.sendParam(trader)) - await ctx.DODO.methods.buyBaseToken(decimalStr("0.5"), decimalStr("60")).send(ctx.sendParam(trader)) + logGas(await ctx.DODO.methods.buyBaseToken(decimalStr("0.5"), decimalStr("60")).send(ctx.sendParam(trader)), "buy when R is BELOW ONE") // trader balances assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("9.5")) - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1049294316148665165351") + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1049294316148665165453") // maintainer balances assert.equal(await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), decimalStr("0.0005")) assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), "98914196817061816") // dodo balances assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("10.4995")) - assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "950606769654517772833") + assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "950606769654517772731") }) it("buy when R is BELOW ONE and RStatus back to ONE", async () => { await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90")).send(ctx.sendParam(trader)) - await ctx.DODO.methods.buyBaseToken("997008973080757728", decimalStr("110")).send(ctx.sendParam(trader)) + logGas(await ctx.DODO.methods.buyBaseToken("997008973080757728", decimalStr("110")).send(ctx.sendParam(trader)), "buy when R is BELOW ONE and RStatus back to ONE") // R status assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0") // trader balances assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), "9997008973080757728") - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "999703024198699420514") + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "999703024198699411500") // maintainer balances assert.equal(await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), "997008973080757") assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), "98914196817061816") // dodo balances assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), "10001994017946161515") - assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "1000198061604483517670") + assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "1000198061604483526684") // target status assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "10001994017946161515") - assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), "1000198061604483517670") + assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), "1000198061604483526684") }) it("buy when R is BELOW ONE and RStatus becomes ABOVE ONE", async () => { await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90")).send(ctx.sendParam(trader)) - logGas(await ctx.DODO.methods.buyBaseToken(decimalStr("2"), decimalStr("220")).send(ctx.sendParam(trader)), "buy base token gas cost worst case") + logGas(await ctx.DODO.methods.buyBaseToken(decimalStr("2"), decimalStr("220")).send(ctx.sendParam(trader)), "buy when R is BELOW ONE and RStatus becomes ABOVE ONE [gas cost worst case]") // R status assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "1") // trader balances assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("11")) - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "897977789597854412810") + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "897977789597854403796") // maintainer balances assert.equal(await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), decimalStr("0.002")) assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), "98914196817061816") // dodo balances assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("8.998")) - assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "1101923296205328525374") + assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "1101923296205328534388") // target status assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "10004000000000000000") - assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), "1000198061604483517670") + assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), "1000198061604483526684") }) }) @@ -243,8 +247,8 @@ describe("Trader", () => { // nearly drain out quote pool // because the fee donated is greater than remaining quote pool // quote lp earn a considerable profit - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1996900220185135480814") - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp).call(), "4574057156329524018663") + assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1996900220185135480813") + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp).call(), "4574057156329524019750") }) }) diff --git a/test/utils/Context.ts b/test/utils/Context.ts index 945da2e..d50f03c 100644 --- a/test/utils/Context.ts +++ b/test/utils/Context.ts @@ -66,8 +66,8 @@ export class DODOContext { this.EVM = new EVM this.Web3 = getDefaultWeb3() this.DODOZoo = await contracts.newContract(contracts.DODO_ZOO_CONTRACT_NAME) - this.BASE = await contracts.newContract(contracts.TEST_ERC20_CONTRACT_NAME) - this.QUOTE = await contracts.newContract(contracts.TEST_ERC20_CONTRACT_NAME) + this.BASE = await contracts.newContract(contracts.TEST_ERC20_CONTRACT_NAME, ["TestBase", 18]) + this.QUOTE = await contracts.newContract(contracts.TEST_ERC20_CONTRACT_NAME, ["TestQuote", 18]) this.ORACLE = await contracts.newContract(contracts.NAIVE_ORACLE_CONTRACT_NAME) const allAccounts = await this.Web3.eth.getAccounts(); @@ -93,6 +93,8 @@ export class DODOContext { this.BaseCapital = contracts.getContractWithAddress(contracts.DODO_LP_TOKEN_CONTRACT_NAME, await this.DODO.methods._BASE_CAPITAL_TOKEN_().call()) this.QuoteCapital = contracts.getContractWithAddress(contracts.DODO_LP_TOKEN_CONTRACT_NAME, await this.DODO.methods._QUOTE_CAPITAL_TOKEN_().call()) + this.DODO.methods.claimOwnership().send(this.sendParam(this.Deployer)) + console.log(log.blueText("[Init dodo context]")) } From edec5e57115e578f9b642cd49be2123f32a7e3cf Mon Sep 17 00:00:00 2001 From: mingda Date: Sat, 11 Jul 2020 13:57:07 +0800 Subject: [PATCH 029/118] simplify events --- contracts/impl/LiquidityProvider.sol | 44 ++++++++++------------------ contracts/impl/Settlement.sol | 8 ++--- contracts/impl/Trader.sol | 8 ++--- 3 files changed, 21 insertions(+), 39 deletions(-) diff --git a/contracts/impl/LiquidityProvider.sol b/contracts/impl/LiquidityProvider.sol index 2e88a4e..596b6f6 100644 --- a/contracts/impl/LiquidityProvider.sol +++ b/contracts/impl/LiquidityProvider.sol @@ -28,37 +28,23 @@ contract LiquidityProvider is Storage, Pricing, Settlement { // ============ Events ============ - event DepositBaseToken( + event Deposit( address indexed payer, address indexed receiver, + bool isBaseToken, uint256 amount, uint256 lpTokenAmount ); - event DepositQuoteToken( + event Withdraw( address indexed payer, address indexed receiver, + bool isBaseToken, uint256 amount, uint256 lpTokenAmount ); - event WithdrawBaseToken( - address indexed payer, - address indexed receiver, - uint256 amount, - uint256 lpTokenAmount - ); - - event WithdrawQuoteToken( - address indexed payer, - address indexed receiver, - uint256 amount, - uint256 lpTokenAmount - ); - - event ChargeBasePenalty(address indexed payer, uint256 amount); - - event ChargeQuotePenalty(address indexed payer, uint256 amount); + event ChargePenalty(address indexed payer, bool isBaseToken, uint256 amount); // ============ Modifiers ============ @@ -120,7 +106,7 @@ contract LiquidityProvider is Storage, Pricing, Settlement { _mintQuoteCapital(to, capital); _TARGET_QUOTE_TOKEN_AMOUNT_ = _TARGET_QUOTE_TOKEN_AMOUNT_.add(amount); - emit DepositQuoteToken(msg.sender, to, amount, capital); + emit Deposit(msg.sender, to, false, amount, capital); } function depositBaseTo(address to, uint256 amount) public preventReentrant depositBaseAllowed { @@ -139,7 +125,7 @@ contract LiquidityProvider is Storage, Pricing, Settlement { _mintBaseCapital(to, capital); _TARGET_BASE_TOKEN_AMOUNT_ = _TARGET_BASE_TOKEN_AMOUNT_.add(amount); - emit DepositBaseToken(msg.sender, to, amount, capital); + emit Deposit(msg.sender, to, true, amount, capital); } // ============ Withdraw Functions ============ @@ -166,8 +152,8 @@ contract LiquidityProvider is Storage, Pricing, Settlement { _quoteTokenTransferOut(to, amount.sub(penalty)); _donateQuoteToken(penalty); - emit WithdrawQuoteToken(msg.sender, to, amount.sub(penalty), requireQuoteCapital); - emit ChargeQuotePenalty(msg.sender, penalty); + emit Withdraw(msg.sender, to, false, amount.sub(penalty), requireQuoteCapital); + emit ChargePenalty(msg.sender, false, penalty); return amount.sub(penalty); } @@ -194,8 +180,8 @@ contract LiquidityProvider is Storage, Pricing, Settlement { _baseTokenTransferOut(to, amount.sub(penalty)); _donateBaseToken(penalty); - emit WithdrawBaseToken(msg.sender, to, amount.sub(penalty), requireBaseCapital); - emit ChargeBasePenalty(msg.sender, penalty); + emit Withdraw(msg.sender, to, true, amount.sub(penalty), requireBaseCapital); + emit ChargePenalty(msg.sender, true, penalty); return amount.sub(penalty); } @@ -216,8 +202,8 @@ contract LiquidityProvider is Storage, Pricing, Settlement { _quoteTokenTransferOut(to, withdrawAmount.sub(penalty)); _donateQuoteToken(penalty); - emit WithdrawQuoteToken(msg.sender, to, withdrawAmount, capital); - emit ChargeQuotePenalty(msg.sender, penalty); + emit Withdraw(msg.sender, to, false, withdrawAmount, capital); + emit ChargePenalty(msg.sender, false, penalty); return withdrawAmount.sub(penalty); } @@ -236,8 +222,8 @@ contract LiquidityProvider is Storage, Pricing, Settlement { _baseTokenTransferOut(to, withdrawAmount.sub(penalty)); _donateBaseToken(penalty); - emit WithdrawBaseToken(msg.sender, to, withdrawAmount, capital); - emit ChargeBasePenalty(msg.sender, penalty); + emit Withdraw(msg.sender, to, true, withdrawAmount, capital); + emit ChargePenalty(msg.sender, true, penalty); return withdrawAmount.sub(penalty); } diff --git a/contracts/impl/Settlement.sol b/contracts/impl/Settlement.sol index 016be05..f5ceaff 100644 --- a/contracts/impl/Settlement.sol +++ b/contracts/impl/Settlement.sol @@ -27,9 +27,7 @@ contract Settlement is Storage { // ============ Events ============ - event DonateBaseToken(uint256 amount); - - event DonateQuoteToken(uint256 amount); + event Donate(uint256 amount, bool isBaseToken); event Claim(address indexed user, uint256 baseTokenAmount, uint256 quoteTokenAmount); @@ -67,12 +65,12 @@ contract Settlement is Storage { function _donateBaseToken(uint256 amount) internal { _TARGET_BASE_TOKEN_AMOUNT_ = _TARGET_BASE_TOKEN_AMOUNT_.add(amount); - emit DonateBaseToken(amount); + emit Donate(amount, true); } function _donateQuoteToken(uint256 amount) internal { _TARGET_QUOTE_TOKEN_AMOUNT_ = _TARGET_QUOTE_TOKEN_AMOUNT_.add(amount); - emit DonateQuoteToken(amount); + emit Donate(amount, false); } function donateBaseToken(uint256 amount) external { diff --git a/contracts/impl/Trader.sol b/contracts/impl/Trader.sol index ecb8c1e..ee75ae3 100644 --- a/contracts/impl/Trader.sol +++ b/contracts/impl/Trader.sol @@ -30,9 +30,7 @@ contract Trader is Storage, Pricing, Settlement { event BuyBaseToken(address indexed buyer, uint256 receiveBase, uint256 payQuote); - event ChargeMaintainerFeeBase(address indexed maintainer, uint256 amount); - - event ChargeMaintainerFeeQuote(address indexed maintainer, uint256 amount); + event ChargeMaintainerFee(address indexed maintainer, bool isBaseToken, uint256 amount); // ============ Modifiers ============ @@ -85,7 +83,7 @@ contract Trader is Storage, Pricing, Settlement { _donateQuoteToken(lpFeeQuote); emit SellBaseToken(msg.sender, amount, receiveQuote); if (mtFeeQuote != 0) { - emit ChargeMaintainerFeeQuote(_MAINTAINER_, mtFeeQuote); + emit ChargeMaintainerFee(_MAINTAINER_, false, mtFeeQuote); } return receiveQuote; @@ -128,7 +126,7 @@ contract Trader is Storage, Pricing, Settlement { _donateBaseToken(lpFeeBase); emit BuyBaseToken(msg.sender, amount, payQuote); if (mtFeeBase != 0) { - emit ChargeMaintainerFeeBase(_MAINTAINER_, mtFeeBase); + emit ChargeMaintainerFee(_MAINTAINER_, true, mtFeeBase); } return payQuote; From a955c7faca44f902b0fc6cdfec450ecc72173330 Mon Sep 17 00:00:00 2001 From: mingda Date: Sat, 11 Jul 2020 15:34:12 +0800 Subject: [PATCH 030/118] slimplify dodo lp token constructor --- contracts/dodo.sol | 17 +++-------------- contracts/impl/DODOLpToken.sol | 21 +++++++++++++-------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/contracts/dodo.sol b/contracts/dodo.sol index 08a60c2..f902034 100644 --- a/contracts/dodo.sol +++ b/contracts/dodo.sol @@ -34,7 +34,7 @@ contract DODO is Admin, Trader, LiquidityProvider { uint256 k, uint256 gasPriceLimit ) external onlyOwner preventReentrant { - require(!_INITIALIZED_, "DODO_ALREADY_INITIALIZED"); + require(!_INITIALIZED_, "DODO_INITIALIZED"); _INITIALIZED_ = true; _SUPERVISOR_ = supervisor; @@ -53,19 +53,8 @@ contract DODO is Admin, Trader, LiquidityProvider { _K_ = k; _R_STATUS_ = Types.RStatus.ONE; - string memory lpTokenSuffix = "_DODO_LP_TOKEN_"; - - string memory baseName = string( - abi.encodePacked(IERC20(_BASE_TOKEN_).name(), lpTokenSuffix) - ); - uint8 baseDecimals = IERC20(_BASE_TOKEN_).decimals(); - _BASE_CAPITAL_TOKEN_ = address(new DODOLpToken(baseName, baseDecimals)); - - string memory quoteName = string( - abi.encodePacked(IERC20(_QUOTE_TOKEN_).name(), lpTokenSuffix) - ); - uint8 quoteDecimals = IERC20(_QUOTE_TOKEN_).decimals(); - _QUOTE_CAPITAL_TOKEN_ = address(new DODOLpToken(quoteName, quoteDecimals)); + _BASE_CAPITAL_TOKEN_ = address(new DODOLpToken(_BASE_TOKEN_)); + _QUOTE_CAPITAL_TOKEN_ = address(new DODOLpToken(_QUOTE_TOKEN_)); _checkDODOParameters(); } diff --git a/contracts/impl/DODOLpToken.sol b/contracts/impl/DODOLpToken.sol index 545b3a6..e64652c 100644 --- a/contracts/impl/DODOLpToken.sol +++ b/contracts/impl/DODOLpToken.sol @@ -8,6 +8,7 @@ pragma solidity 0.6.9; pragma experimental ABIEncoderV2; +import {IERC20} from "../intf/IERC20.sol"; import {SafeMath} from "../lib/SafeMath.sol"; import {Ownable} from "../lib/Ownable.sol"; @@ -21,8 +22,7 @@ contract DODOLpToken is Ownable { using SafeMath for uint256; string public symbol = "DLP"; - string public name; - uint8 public decimals; + address public originToken; uint256 public totalSupply; mapping(address => uint256) internal balances; @@ -40,9 +40,17 @@ contract DODOLpToken is Ownable { // ============ Functions ============ - constructor(string memory _name, uint8 _decimals) public { - name = _name; - decimals = _decimals; + constructor(address _originToken) public { + originToken = _originToken; + } + + function name() public view returns (string memory) { + string memory lpTokenSuffix = "_DODO_LP_TOKEN_"; + return string(abi.encodePacked(IERC20(originToken).name(), lpTokenSuffix)); + } + + function decimals() public view returns (uint8) { + return IERC20(originToken).decimals(); } /** @@ -51,7 +59,6 @@ contract DODOLpToken is Ownable { * @param amount The amount to be transferred. */ function transfer(address to, uint256 amount) public returns (bool) { - require(to != address(0), "TO_ADDRESS_IS_EMPTY"); require(amount <= balances[msg.sender], "BALANCE_NOT_ENOUGH"); balances[msg.sender] = balances[msg.sender].sub(amount); @@ -80,7 +87,6 @@ contract DODOLpToken is Ownable { address to, uint256 amount ) public returns (bool) { - require(to != address(0), "TO_ADDRESS_IS_EMPTY"); require(amount <= balances[from], "BALANCE_NOT_ENOUGH"); require(amount <= allowed[from][msg.sender], "ALLOWANCE_NOT_ENOUGH"); @@ -123,6 +129,5 @@ contract DODOLpToken is Ownable { balances[user] = balances[user].sub(value); totalSupply = totalSupply.sub(value); emit Burn(user, value); - emit Transfer(user, address(0), value); } } From 2c8ba643a8c92691dcc763a1f4f8cc027064f53b Mon Sep 17 00:00:00 2001 From: mingda Date: Sat, 11 Jul 2020 16:21:54 +0800 Subject: [PATCH 031/118] simplify code to reduce deploy gas cost --- contracts/DODOZoo.sol | 3 +-- contracts/impl/LiquidityProvider.sol | 16 ++++++++-------- contracts/impl/Pricing.sol | 4 ++-- contracts/impl/Settlement.sol | 2 +- contracts/impl/Storage.sol | 8 ++++---- contracts/intf/IERC20.sol | 14 -------------- contracts/lib/ReentrancyGuard.sol | 2 +- 7 files changed, 17 insertions(+), 32 deletions(-) diff --git a/contracts/DODOZoo.sol b/contracts/DODOZoo.sol index 0dc08b8..62b3555 100644 --- a/contracts/DODOZoo.sol +++ b/contracts/DODOZoo.sol @@ -38,8 +38,7 @@ contract DODOZoo is Ownable { uint256 k, uint256 gasPriceLimit ) public onlyOwner returns (address) { - require(!isDODORegistered(baseToken, quoteToken), "DODO_IS_REGISTERED"); - require(baseToken != quoteToken, "BASE_IS_SAME_WITH_QUOTE"); + require(!isDODORegistered(baseToken, quoteToken), "DODO_REGISTERED"); address newBornDODO = address(new DODO()); IDODO(newBornDODO).init( supervisor, diff --git a/contracts/impl/LiquidityProvider.sol b/contracts/impl/LiquidityProvider.sol index 596b6f6..7bb2600 100644 --- a/contracts/impl/LiquidityProvider.sol +++ b/contracts/impl/LiquidityProvider.sol @@ -49,12 +49,12 @@ contract LiquidityProvider is Storage, Pricing, Settlement { // ============ Modifiers ============ modifier depositQuoteAllowed() { - require(_DEPOSIT_QUOTE_ALLOWED_, "DEPOSIT_QUOTE_TOKEN_NOT_ALLOWED"); + require(_DEPOSIT_QUOTE_ALLOWED_, "DEPOSIT_QUOTE_NOT_ALLOWED"); _; } modifier depositBaseAllowed() { - require(_DEPOSIT_BASE_ALLOWED_, "DEPOSIT_BASE_TOKEN_NOT_ALLOWED"); + require(_DEPOSIT_BASE_ALLOWED_, "DEPOSIT_BASE_NOT_ALLOWED"); _; } @@ -144,7 +144,7 @@ contract LiquidityProvider is Storage, Pricing, Settlement { // handle penalty, penalty may exceed amount uint256 penalty = getWithdrawQuotePenalty(amount); - require(penalty < amount, "COULD_NOT_AFFORD_LIQUIDITY_PENALTY"); + require(penalty < amount, "PENALTY_EXCEED"); // settlement _TARGET_QUOTE_TOKEN_AMOUNT_ = _TARGET_QUOTE_TOKEN_AMOUNT_.sub(amount); @@ -172,7 +172,7 @@ contract LiquidityProvider is Storage, Pricing, Settlement { // handle penalty, penalty may exceed amount uint256 penalty = getWithdrawBasePenalty(amount); - require(penalty <= amount, "COULD_NOT_AFFORD_LIQUIDITY_PENALTY"); + require(penalty <= amount, "PENALTY_EXCEED"); // settlement _TARGET_BASE_TOKEN_AMOUNT_ = _TARGET_BASE_TOKEN_AMOUNT_.sub(amount); @@ -194,7 +194,7 @@ contract LiquidityProvider is Storage, Pricing, Settlement { // handle penalty, penalty may exceed amount uint256 penalty = getWithdrawQuotePenalty(withdrawAmount); - require(penalty <= withdrawAmount, "COULD_NOT_AFFORD_LIQUIDITY_PENALTY"); + require(penalty <= withdrawAmount, "PENALTY_EXCEED"); // settlement _TARGET_QUOTE_TOKEN_AMOUNT_ = _TARGET_QUOTE_TOKEN_AMOUNT_.sub(withdrawAmount); @@ -214,7 +214,7 @@ contract LiquidityProvider is Storage, Pricing, Settlement { // handle penalty, penalty may exceed amount uint256 penalty = getWithdrawBasePenalty(withdrawAmount); - require(penalty <= withdrawAmount, "COULD_NOT_AFFORD_LIQUIDITY_PENALTY"); + require(penalty <= withdrawAmount, "PENALTY_EXCEED"); // settlement _TARGET_BASE_TOKEN_AMOUNT_ = _TARGET_BASE_TOKEN_AMOUNT_.sub(withdrawAmount); @@ -269,7 +269,7 @@ contract LiquidityProvider is Storage, Pricing, Settlement { } function getWithdrawQuotePenalty(uint256 amount) public view returns (uint256 penalty) { - require(amount <= _QUOTE_BALANCE_, "DODO_QUOTE_TOKEN_BALANCE_NOT_ENOUGH"); + require(amount <= _QUOTE_BALANCE_, "DODO_QUOTE_BALANCE_NOT_ENOUGH"); if (_R_STATUS_ == Types.RStatus.BELOW_ONE) { uint256 spareBase = _BASE_BALANCE_.sub(_TARGET_BASE_TOKEN_AMOUNT_); uint256 price = getOraclePrice(); @@ -292,7 +292,7 @@ contract LiquidityProvider is Storage, Pricing, Settlement { } function getWithdrawBasePenalty(uint256 amount) public view returns (uint256 penalty) { - require(amount <= _BASE_BALANCE_, "DODO_BASE_TOKEN_BALANCE_NOT_ENOUGH"); + require(amount <= _BASE_BALANCE_, "DODO_BASE_BALANCE_NOT_ENOUGH"); if (_R_STATUS_ == Types.RStatus.ABOVE_ONE) { uint256 spareQuote = _QUOTE_BALANCE_.sub(_TARGET_QUOTE_TOKEN_AMOUNT_); uint256 price = getOraclePrice(); diff --git a/contracts/impl/Pricing.sol b/contracts/impl/Pricing.sol index ee88a7f..f9ce3ee 100644 --- a/contracts/impl/Pricing.sol +++ b/contracts/impl/Pricing.sol @@ -48,7 +48,7 @@ contract Pricing is Storage { view returns (uint256 payQuoteToken) { - require(amount < targetBaseTokenAmount, "DODO_BASE_TOKEN_BALANCE_NOT_ENOUGH"); + require(amount < targetBaseTokenAmount, "DODO_BASE_BALANCE_NOT_ENOUGH"); uint256 B2 = targetBaseTokenAmount.sub(amount); payQuoteToken = _RAboveIntegrate(targetBaseTokenAmount, targetBaseTokenAmount, B2); return payQuoteToken; @@ -111,7 +111,7 @@ contract Pricing is Storage { uint256 baseBalance, uint256 targetBaseAmount ) internal view returns (uint256 payQuoteToken) { - require(amount < baseBalance, "DODO_BASE_TOKEN_BALANCE_NOT_ENOUGH"); + require(amount < baseBalance, "DODO_BASE_BALANCE_NOT_ENOUGH"); uint256 B2 = baseBalance.sub(amount); return _RAboveIntegrate(targetBaseAmount, baseBalance, B2); } diff --git a/contracts/impl/Settlement.sol b/contracts/impl/Settlement.sol index f5ceaff..5c1b0cb 100644 --- a/contracts/impl/Settlement.sol +++ b/contracts/impl/Settlement.sol @@ -113,7 +113,7 @@ contract Settlement is Storage { // claim remaining assets after final settlement function claim() external preventReentrant { - require(_CLOSED_, "DODO_IS_NOT_CLOSED"); + require(_CLOSED_, "DODO_NOT_CLOSED"); require(!_CLAIMED_[msg.sender], "ALREADY_CLAIMED"); _CLAIMED_[msg.sender] = true; uint256 quoteAmount = DecimalMath.mul( diff --git a/contracts/impl/Storage.sol b/contracts/impl/Storage.sol index a56e5bd..63f8d1d 100644 --- a/contracts/impl/Storage.sol +++ b/contracts/impl/Storage.sol @@ -72,16 +72,16 @@ contract Storage is Ownable, ReentrancyGuard { } modifier notClosed() { - require(!_CLOSED_, "DODO_IS_CLOSED"); + require(!_CLOSED_, "DODO_CLOSED"); _; } // ============ Helper Functions ============ function _checkDODOParameters() internal view returns (uint256) { - require(_K_ < DecimalMath.ONE, "K_MUST_BE_LESS_THAN_ONE"); - require(_K_ > 0, "K_MUST_BE_GREATER_THAN_ZERO"); - require(_LP_FEE_RATE_.add(_MT_FEE_RATE_) < DecimalMath.ONE, "FEE_MUST_BE_LESS_THAN_ONE"); + require(_K_ < DecimalMath.ONE, "K>=1"); + require(_K_ > 0, "K=0"); + require(_LP_FEE_RATE_.add(_MT_FEE_RATE_) < DecimalMath.ONE, "FEE_RATE>=1"); } function getOraclePrice() public view returns (uint256) { diff --git a/contracts/intf/IERC20.sol b/contracts/intf/IERC20.sol index 2f1810b..252e1f5 100644 --- a/contracts/intf/IERC20.sol +++ b/contracts/intf/IERC20.sol @@ -70,18 +70,4 @@ interface IERC20 { address recipient, uint256 amount ) external returns (bool); - - /** - * @dev Emitted when `value` tokens are moved from one account (`from`) to - * another (`to`). - * - * Note that `value` may be zero. - */ - event Transfer(address indexed from, address indexed to, uint256 value); - - /** - * @dev Emitted when the allowance of a `spender` for an `owner` is set by - * a call to {approve}. `value` is the new allowance. - */ - event Approval(address indexed owner, address indexed spender, uint256 value); } diff --git a/contracts/lib/ReentrancyGuard.sol b/contracts/lib/ReentrancyGuard.sol index dee0bea..f56a8ef 100644 --- a/contracts/lib/ReentrancyGuard.sol +++ b/contracts/lib/ReentrancyGuard.sol @@ -24,7 +24,7 @@ contract ReentrancyGuard { } modifier preventReentrant() { - require(_ENTER_STATUS_ != Types.EnterStatus.ENTERED, "ReentrancyGuard: reentrant call"); + require(_ENTER_STATUS_ != Types.EnterStatus.ENTERED, "REENTRANT"); _ENTER_STATUS_ = Types.EnterStatus.ENTERED; _; _ENTER_STATUS_ = Types.EnterStatus.NOT_ENTERED; From 6f5a3f99091ca78dd6232ef8fc418167a138eb43 Mon Sep 17 00:00:00 2001 From: mingda Date: Sun, 12 Jul 2020 15:30:32 +0800 Subject: [PATCH 032/118] fix tests --- test/Admin.test.ts | 22 +++++++++++----------- test/DODOZoo.test.ts | 6 +++--- test/LiquidityProvider.test.ts | 20 ++++++++++---------- test/StableCoinMode.test.ts | 2 +- test/Trader.test.ts | 4 ++-- 5 files changed, 27 insertions(+), 27 deletions(-) diff --git a/test/Admin.test.ts b/test/Admin.test.ts index 400c00c..d9c60a5 100644 --- a/test/Admin.test.ts +++ b/test/Admin.test.ts @@ -89,7 +89,7 @@ describe("Admin", () => { await ctx.DODO.methods.disableBaseDeposit().send(ctx.sendParam(ctx.Supervisor)) await assert.rejects( ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)), - /DEPOSIT_BASE_TOKEN_NOT_ALLOWED/ + /DEPOSIT_BASE_NOT_ALLOWED/ ) await ctx.DODO.methods.enableBaseDeposit().send(ctx.sendParam(ctx.Deployer)) @@ -99,7 +99,7 @@ describe("Admin", () => { await ctx.DODO.methods.disableQuoteDeposit().send(ctx.sendParam(ctx.Supervisor)) await assert.rejects( ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)), - /DEPOSIT_QUOTE_TOKEN_NOT_ALLOWED/ + /DEPOSIT_QUOTE_NOT_ALLOWED/ ) await ctx.DODO.methods.enableQuoteDeposit().send(ctx.sendParam(ctx.Deployer)) @@ -227,7 +227,7 @@ describe("Admin", () => { it("final settlement revert cases", async () => { await assert.rejects( ctx.DODO.methods.claim().send(ctx.sendParam(lp1)), - /DODO_IS_NOT_CLOSED/ + /DODO_NOT_CLOSED/ ) await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) await ctx.DODO.methods.depositQuote(decimalStr("500")).send(ctx.sendParam(lp2)) @@ -236,7 +236,7 @@ describe("Admin", () => { await ctx.DODO.methods.finalSettlement().send(ctx.sendParam(ctx.Deployer)) await assert.rejects( ctx.DODO.methods.finalSettlement().send(ctx.sendParam(ctx.Deployer)), - / DODO_IS_CLOSED/ + / DODO_CLOSED/ ) await ctx.DODO.methods.claim().send(ctx.sendParam(lp2)) @@ -247,15 +247,15 @@ describe("Admin", () => { await assert.rejects( ctx.DODO.methods.enableQuoteDeposit().send(ctx.sendParam(ctx.Deployer)), - /DODO_IS_CLOSED/ + /DODO_CLOSED/ ) await assert.rejects( ctx.DODO.methods.enableBaseDeposit().send(ctx.sendParam(ctx.Deployer)), - /DODO_IS_CLOSED/ + /DODO_CLOSED/ ) await assert.rejects( ctx.DODO.methods.enableTrading().send(ctx.sendParam(ctx.Deployer)), - /DODO_IS_CLOSED/ + /DODO_CLOSED/ ) }) }) @@ -318,22 +318,22 @@ describe("Admin", () => { it("k revert cases", async () => { await assert.rejects( ctx.DODO.methods.setK(decimalStr("1")).send(ctx.sendParam(ctx.Deployer)), - /K_MUST_BE_LESS_THAN_ONE/ + /K>=1/ ) await assert.rejects( ctx.DODO.methods.setK(decimalStr("0")).send(ctx.sendParam(ctx.Deployer)), - /K_MUST_BE_GREATER_THAN_ZERO/ + /K=0/ ) }) it("fee revert cases", async () => { await assert.rejects( ctx.DODO.methods.setLiquidityProviderFeeRate(decimalStr("0.999")).send(ctx.sendParam(ctx.Deployer)), - /FEE_MUST_BE_LESS_THAN_ONE/ + /FEE_RATE>=1/ ) await assert.rejects( ctx.DODO.methods.setMaintainerFeeRate(decimalStr("0.998")).send(ctx.sendParam(ctx.Deployer)), - /FEE_MUST_BE_LESS_THAN_ONE/ + /FEE_RATE>=1/ ) }) }) diff --git a/test/DODOZoo.test.ts b/test/DODOZoo.test.ts index ce3ddd7..9ebf82f 100644 --- a/test/DODOZoo.test.ts +++ b/test/DODOZoo.test.ts @@ -34,12 +34,12 @@ describe("DODO ZOO", () => { it("could not deploy the same dodo", async () => { await assert.rejects( ctx.DODOZoo.methods.breedDODO(ctx.Supervisor, ctx.Maintainer, ctx.BASE.options.address, ctx.QUOTE.options.address, ctx.ORACLE.options.address, "0", "0", "1", "0").send(ctx.sendParam(ctx.Deployer)), - /DODO_IS_REGISTERED/ + /DODO_REGISTERED/ ) await assert.rejects( ctx.DODOZoo.methods.breedDODO(ctx.Supervisor, ctx.Maintainer, ctx.QUOTE.options.address, ctx.BASE.options.address, ctx.ORACLE.options.address, "0", "0", "1", "0").send(ctx.sendParam(ctx.Deployer)), - /DODO_IS_REGISTERED/ + /DODO_REGISTERED/ ) }) @@ -61,7 +61,7 @@ describe("DODO ZOO", () => { // could not init twice await assert.rejects( newDODO.methods.init(ctx.Supervisor, ctx.Maintainer, ctx.QUOTE.options.address, ctx.BASE.options.address, ctx.ORACLE.options.address, "0", "0", "1", "0").send(ctx.sendParam(ctx.Deployer)), - /DODO_ALREADY_INITIALIZED/ + /DODO_INITIALIZED/ ) }) diff --git a/test/LiquidityProvider.test.ts b/test/LiquidityProvider.test.ts index 95f7306..6a86353 100644 --- a/test/LiquidityProvider.test.ts +++ b/test/LiquidityProvider.test.ts @@ -351,12 +351,12 @@ describe("LiquidityProvider", () => { await assert.rejects( ctx.DODO.methods.withdrawBase(decimalStr("6")).send(ctx.sendParam(lp1)), - /DODO_BASE_TOKEN_BALANCE_NOT_ENOUGH/ + /DODO_BASE_BALANCE_NOT_ENOUGH/ ) await assert.rejects( ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp1)), - /DODO_BASE_TOKEN_BALANCE_NOT_ENOUGH/ + /DODO_BASE_BALANCE_NOT_ENOUGH/ ) }) @@ -366,12 +366,12 @@ describe("LiquidityProvider", () => { await assert.rejects( ctx.DODO.methods.withdrawQuote(decimalStr("600")).send(ctx.sendParam(lp1)), - /DODO_QUOTE_TOKEN_BALANCE_NOT_ENOUGH/ + /DODO_QUOTE_BALANCE_NOT_ENOUGH/ ) await assert.rejects( ctx.DODO.methods.withdrawAllQuote().send(ctx.sendParam(lp1)), - /DODO_QUOTE_TOKEN_BALANCE_NOT_ENOUGH/ + /DODO_QUOTE_BALANCE_NOT_ENOUGH/ ) }) @@ -381,12 +381,12 @@ describe("LiquidityProvider", () => { await assert.rejects( ctx.DODO.methods.withdrawBase(decimalStr("0.5")).send(ctx.sendParam(lp1)), - /COULD_NOT_AFFORD_LIQUIDITY_PENALTY/ + /PENALTY_EXCEED/ ) await assert.rejects( ctx.DODO.methods.getWithdrawBasePenalty(decimalStr("10")).call(), - /DODO_BASE_TOKEN_BALANCE_NOT_ENOUGH/ + /DODO_BASE_BALANCE_NOT_ENOUGH/ ) }) @@ -396,12 +396,12 @@ describe("LiquidityProvider", () => { await assert.rejects( ctx.DODO.methods.withdrawQuote(decimalStr("200")).send(ctx.sendParam(lp1)), - /COULD_NOT_AFFORD_LIQUIDITY_PENALTY/ + /PENALTY_EXCEED/ ) await assert.rejects( ctx.DODO.methods.getWithdrawQuotePenalty(decimalStr("1000")).call(), - /DODO_QUOTE_TOKEN_BALANCE_NOT_ENOUGH/ + /DODO_QUOTE_BALANCE_NOT_ENOUGH/ ) }) @@ -412,7 +412,7 @@ describe("LiquidityProvider", () => { await assert.rejects( ctx.DODO.methods.withdrawBase(decimalStr("0.5")).send(ctx.sendParam(lp2)), - /COULD_NOT_AFFORD_LIQUIDITY_PENALTY/ + /PENALTY_EXCEED/ ) }) @@ -423,7 +423,7 @@ describe("LiquidityProvider", () => { await assert.rejects( ctx.DODO.methods.withdrawQuote(decimalStr("200")).send(ctx.sendParam(lp2)), - /COULD_NOT_AFFORD_LIQUIDITY_PENALTY/ + /PENALTY_EXCEED/ ) }) diff --git a/test/StableCoinMode.test.ts b/test/StableCoinMode.test.ts index 204a88f..b85a8ab 100644 --- a/test/StableCoinMode.test.ts +++ b/test/StableCoinMode.test.ts @@ -83,7 +83,7 @@ describe("Trader", () => { // could not buy all base balance await assert.rejects( ctx.DODO.methods.buyBaseToken(decimalStr("10000"), decimalStr("10010")).send(ctx.sendParam(trader)), - /DODO_BASE_TOKEN_BALANCE_NOT_ENOUGH/ + /DODO_BASE_BALANCE_NOT_ENOUGH/ ) // when buy amount close to base balance, price will increase quickly diff --git a/test/Trader.test.ts b/test/Trader.test.ts index 58fcdb7..ae3b759 100644 --- a/test/Trader.test.ts +++ b/test/Trader.test.ts @@ -267,14 +267,14 @@ describe("Trader", () => { it("base balance limit", async () => { await assert.rejects( ctx.DODO.methods.buyBaseToken(decimalStr("11"), decimalStr("10000")).send(ctx.sendParam(trader)), - /DODO_BASE_TOKEN_BALANCE_NOT_ENOUGH/ + /DODO_BASE_BALANCE_NOT_ENOUGH/ ) await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("200")).send(ctx.sendParam(trader)) await assert.rejects( ctx.DODO.methods.buyBaseToken(decimalStr("11"), decimalStr("10000")).send(ctx.sendParam(trader)), - /DODO_BASE_TOKEN_BALANCE_NOT_ENOUGH/ + /DODO_BASE_BALANCE_NOT_ENOUGH/ ) }) }) From 0fcdb68cde4c60ea935a70b1ef7928fdc92e5919 Mon Sep 17 00:00:00 2001 From: mingda Date: Mon, 13 Jul 2020 13:24:21 +0800 Subject: [PATCH 033/118] audit report finished --- audit/dodo_audit_report_2020_16_en_1.0.pdf | Bin 0 -> 525620 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 audit/dodo_audit_report_2020_16_en_1.0.pdf diff --git a/audit/dodo_audit_report_2020_16_en_1.0.pdf b/audit/dodo_audit_report_2020_16_en_1.0.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ae4ee1e5499c5ddf6230f9ccf609c835e5fa56c3 GIT binary patch literal 525620 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

w;U|C(lHdlgWo-loE|*gce0(Mh$cyzthe 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�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


wr$(?>H7vf>%ki(sSHz<+R0vPec26Z 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 =W{z!T~}_ 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

x2olpx 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 C=&&jP literal 0 HcmV?d00001 From 0c86c33ed3b32b964b73bf18ed495ac87d0243bb Mon Sep 17 00:00:00 2001 From: mingda Date: Mon, 13 Jul 2020 13:35:35 +0800 Subject: [PATCH 034/118] link to audit and docs --- README.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ba0539c..226ad19 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,22 @@ # DODO:10x better liquidity than uniswap +## What is DODO? + ✍️[Introducing DODO](https://medium.com/@dodo.in.the.zoo/introducing-dodo-10x-better-liquidity-than-uniswap-852ce2137c57) -- Current AMM failed in providing comparable liquidity in mainstream trading pairs because AMM cannot really work as human market makers. - DODO is based on a brand new market maker algorithm with an essential idea of risk neutrality to keep liquidity providers’ portfolio stable. - Compared with AMMs, DODO will perform 10x better in liquidity. + +## Who audit DODO? + +[PeckShield Inc.](https://peckshield.cn/en) is a leading blockchain security company with the goal of elevating the security, privacy, and usability of current blockchain ecosystems by offering top-notch, industry-leading services and products. + +You could find the audit report [here](https://raw.githubusercontent.com/radar-bear/dodo-smart-contract/master/audit/dodo_audit_report_2020_16_en_1.0.pdf) + +## More details and deployment info + +You could find all documents and info about DODO in [this repo](https://github.com/radar-bear/dodo-docs) + +## Contact Us + +Send E-mail to dodo_breeder@dodoex.io \ No newline at end of file From 5a74bb822b9961a70886f4caebe2ea435722e1f7 Mon Sep 17 00:00:00 2001 From: mingda Date: Mon, 13 Jul 2020 16:55:55 +0800 Subject: [PATCH 035/118] chainlink price oracle proxy --- .../helper/ChainlinkEthPriceOracleProxy.sol | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 contracts/helper/ChainlinkEthPriceOracleProxy.sol diff --git a/contracts/helper/ChainlinkEthPriceOracleProxy.sol b/contracts/helper/ChainlinkEthPriceOracleProxy.sol new file mode 100644 index 0000000..47a6852 --- /dev/null +++ b/contracts/helper/ChainlinkEthPriceOracleProxy.sol @@ -0,0 +1,23 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +interface IChainlink { + function latestAnswer() external view returns (uint256); +} + +// for WETH-USDC(decimals=6) price convert + +contract ChainlinkETHPriceOracleProxy { + address public chainlink = 0xF79D6aFBb6dA890132F9D7c355e3015f15F3406F; + + function getPrice() external view returns (uint256) { + return IChainlink(chainlink).latestAnswer() / 100; + } +} From 50f3180c824bf616e7662dc2021840501c21f655 Mon Sep 17 00:00:00 2001 From: mingda Date: Fri, 24 Jul 2020 01:48:32 +0800 Subject: [PATCH 036/118] reduce gas cost --- contracts/impl/Settlement.sol | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/contracts/impl/Settlement.sol b/contracts/impl/Settlement.sol index 5c1b0cb..d11eb29 100644 --- a/contracts/impl/Settlement.sol +++ b/contracts/impl/Settlement.sol @@ -34,31 +34,23 @@ contract Settlement is Storage { // ============ Assets IN/OUT Functions ============ function _baseTokenTransferIn(address from, uint256 amount) internal { - uint256 beforeBalance = IERC20(_BASE_TOKEN_).balanceOf(address(this)); IERC20(_BASE_TOKEN_).safeTransferFrom(from, address(this), amount); - uint256 afterBalance = IERC20(_BASE_TOKEN_).balanceOf(address(this)); - _BASE_BALANCE_ = _BASE_BALANCE_.add(afterBalance.sub(beforeBalance)); + _BASE_BALANCE_ = _BASE_BALANCE_.add(amount); } function _quoteTokenTransferIn(address from, uint256 amount) internal { - uint256 beforeBalance = IERC20(_QUOTE_TOKEN_).balanceOf(address(this)); IERC20(_QUOTE_TOKEN_).safeTransferFrom(from, address(this), amount); - uint256 afterBalance = IERC20(_QUOTE_TOKEN_).balanceOf(address(this)); - _QUOTE_BALANCE_ = _QUOTE_BALANCE_.add(afterBalance.sub(beforeBalance)); + _QUOTE_BALANCE_ = _QUOTE_BALANCE_.add(amount); } function _baseTokenTransferOut(address to, uint256 amount) internal { - uint256 beforeBalance = IERC20(_BASE_TOKEN_).balanceOf(address(this)); IERC20(_BASE_TOKEN_).safeTransfer(to, amount); - uint256 afterBalance = IERC20(_BASE_TOKEN_).balanceOf(address(this)); - _BASE_BALANCE_ = _BASE_BALANCE_.sub(beforeBalance.sub(afterBalance)); + _BASE_BALANCE_ = _BASE_BALANCE_.sub(amount); } function _quoteTokenTransferOut(address to, uint256 amount) internal { - uint256 beforeBalance = IERC20(_QUOTE_TOKEN_).balanceOf(address(this)); IERC20(_QUOTE_TOKEN_).safeTransfer(to, amount); - uint256 afterBalance = IERC20(_QUOTE_TOKEN_).balanceOf(address(this)); - _QUOTE_BALANCE_ = _QUOTE_BALANCE_.sub(beforeBalance.sub(afterBalance)); + _QUOTE_BALANCE_ = _QUOTE_BALANCE_.sub(amount); } // ============ Donate to Liquidity Pool Functions ============ From 58f189b957099ac245db5b79b2220696b6f89b24 Mon Sep 17 00:00:00 2001 From: mingda Date: Fri, 24 Jul 2020 01:50:48 +0800 Subject: [PATCH 037/118] simplify reentrancyGuard --- contracts/lib/ReentrancyGuard.sol | 16 ++++++---------- contracts/lib/Types.sol | 1 - 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/contracts/lib/ReentrancyGuard.sol b/contracts/lib/ReentrancyGuard.sol index f56a8ef..e2a3c21 100644 --- a/contracts/lib/ReentrancyGuard.sol +++ b/contracts/lib/ReentrancyGuard.sol @@ -8,8 +8,6 @@ pragma solidity 0.6.9; pragma experimental ABIEncoderV2; -import {Types} from "./Types.sol"; - /** * @title ReentrancyGuard * @author DODO Breeder @@ -17,16 +15,14 @@ import {Types} from "./Types.sol"; * @notice Protect functions from Reentrancy Attack */ contract ReentrancyGuard { - Types.EnterStatus private _ENTER_STATUS_; - - constructor() internal { - _ENTER_STATUS_ = Types.EnterStatus.NOT_ENTERED; - } + // https://solidity.readthedocs.io/en/latest/control-structures.html?highlight=zero-state#scoping-and-declarations + // zero-state of _ENTERED_ is false + bool private _ENTERED_; modifier preventReentrant() { - require(_ENTER_STATUS_ != Types.EnterStatus.ENTERED, "REENTRANT"); - _ENTER_STATUS_ = Types.EnterStatus.ENTERED; + require(!_ENTERED_, "REENTRANT"); + _ENTERED_ = true; _; - _ENTER_STATUS_ = Types.EnterStatus.NOT_ENTERED; + _ENTERED_ = false; } } diff --git a/contracts/lib/Types.sol b/contracts/lib/Types.sol index 606f509..0892400 100644 --- a/contracts/lib/Types.sol +++ b/contracts/lib/Types.sol @@ -10,5 +10,4 @@ pragma experimental ABIEncoderV2; library Types { enum RStatus {ONE, ABOVE_ONE, BELOW_ONE} - enum EnterStatus {ENTERED, NOT_ENTERED} } From c750bbea8d48eba2919df6a1611aa4ee0a0fe86f Mon Sep 17 00:00:00 2001 From: mingda Date: Fri, 24 Jul 2020 01:53:58 +0800 Subject: [PATCH 038/118] clone dodo using minimal proxy --- contracts/DODOZoo.sol | 43 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/contracts/DODOZoo.sol b/contracts/DODOZoo.sol index 62b3555..928f829 100644 --- a/contracts/DODOZoo.sol +++ b/contracts/DODOZoo.sol @@ -9,8 +9,22 @@ pragma solidity 0.6.9; pragma experimental ABIEncoderV2; import {Ownable} from "./lib/Ownable.sol"; -import {IDODO} from "./intf/IDODO.sol"; -import {DODO} from "./DODO.sol"; + +interface IDODO { + function init( + address supervisor, + address maintainer, + address baseToken, + address quoteToken, + address oracle, + uint256 lpFeeRate, + uint256 mtFeeRate, + uint256 k, + uint256 gasPriceLimit + ) external; + + function transferOwnership(address newOwner) external; +} /** * @title DODOZoo @@ -19,12 +33,19 @@ import {DODO} from "./DODO.sol"; * @notice Register of All DODO */ contract DODOZoo is Ownable { + address public _DODO_LOGIC_; mapping(address => mapping(address => address)) internal _DODO_REGISTER_; // ============ Events ============ event DODOBirth(address newBorn, address baseToken, address quoteToken); + // ============ Constructor Function ============ + + constructor(address _dodoLogic) public { + _DODO_LOGIC_ = _dodoLogic; + } + // ============ Breed DODO Function ============ function breedDODO( @@ -37,9 +58,21 @@ contract DODOZoo is Ownable { uint256 mtFeeRate, uint256 k, uint256 gasPriceLimit - ) public onlyOwner returns (address) { + ) external onlyOwner returns (address newBornDODO) { require(!isDODORegistered(baseToken, quoteToken), "DODO_REGISTERED"); - address newBornDODO = address(new DODO()); + // Adapted from https://github.com/optionality/clone-factory/blob/32782f82dfc5a00d103a7e61a17a5dedbd1e8e9d/contracts/CloneFactory.sol + // create proxy + bytes20 targetBytes = bytes20(_DODO_LOGIC_); + assembly { + let clone := mload(0x40) + mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) + mstore(add(clone, 0x14), targetBytes) + mstore( + add(clone, 0x28), + 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000 + ) + newBornDODO := create(0, clone, 0x37) + } IDODO(newBornDODO).init( supervisor, maintainer, @@ -57,7 +90,7 @@ contract DODOZoo is Ownable { return newBornDODO; } - function removeDODO(address baseToken, address quoteToken) public onlyOwner { + function removeDODO(address baseToken, address quoteToken) external onlyOwner { _DODO_REGISTER_[baseToken][quoteToken] = address(0); } From bb366f71c4dea4ac99c7921be30db1879fa9e08b Mon Sep 17 00:00:00 2001 From: mingda Date: Fri, 24 Jul 2020 01:55:09 +0800 Subject: [PATCH 039/118] remove constructor because using proxy mode clone --- contracts/dodo.sol | 6 +++- contracts/impl/Storage.sol | 4 +-- contracts/lib/InitializableOwnable.sol | 48 ++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 contracts/lib/InitializableOwnable.sol diff --git a/contracts/dodo.sol b/contracts/dodo.sol index f902034..5313063 100644 --- a/contracts/dodo.sol +++ b/contracts/dodo.sol @@ -33,10 +33,14 @@ contract DODO is Admin, Trader, LiquidityProvider { uint256 mtFeeRate, uint256 k, uint256 gasPriceLimit - ) external onlyOwner preventReentrant { + ) external { require(!_INITIALIZED_, "DODO_INITIALIZED"); _INITIALIZED_ = true; + // constructor + _OWNER_ = msg.sender; + emit OwnershipTransferred(address(0), _OWNER_); + _SUPERVISOR_ = supervisor; _MAINTAINER_ = maintainer; _BASE_TOKEN_ = baseToken; diff --git a/contracts/impl/Storage.sol b/contracts/impl/Storage.sol index 63f8d1d..3135772 100644 --- a/contracts/impl/Storage.sol +++ b/contracts/impl/Storage.sol @@ -8,7 +8,7 @@ pragma solidity 0.6.9; pragma experimental ABIEncoderV2; -import {Ownable} from "../lib/Ownable.sol"; +import {InitializableOwnable} from "../lib/InitializableOwnable.sol"; import {SafeMath} from "../lib/SafeMath.sol"; import {DecimalMath} from "../lib/DecimalMath.sol"; import {ReentrancyGuard} from "../lib/ReentrancyGuard.sol"; @@ -22,7 +22,7 @@ import {Types} from "../lib/Types.sol"; * * @notice Local Variables */ -contract Storage is Ownable, ReentrancyGuard { +contract Storage is InitializableOwnable, ReentrancyGuard { using SafeMath for uint256; // ============ Variables for Control ============ diff --git a/contracts/lib/InitializableOwnable.sol b/contracts/lib/InitializableOwnable.sol new file mode 100644 index 0000000..c90dde0 --- /dev/null +++ b/contracts/lib/InitializableOwnable.sol @@ -0,0 +1,48 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +/** + * @title Ownable + * @author DODO Breeder + * + * @notice Ownership related functions + */ +contract InitializableOwnable { + address public _OWNER_; + address public _NEW_OWNER_; + + // ============ Events ============ + + event OwnershipTransferPrepared(address indexed previousOwner, address indexed newOwner); + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + // ============ Modifiers ============ + + modifier onlyOwner() { + require(msg.sender == _OWNER_, "NOT_OWNER"); + _; + } + + // ============ Functions ============ + + function transferOwnership(address newOwner) external onlyOwner { + require(newOwner != address(0), "INVALID_OWNER"); + emit OwnershipTransferPrepared(_OWNER_, newOwner); + _NEW_OWNER_ = newOwner; + } + + function claimOwnership() external { + require(msg.sender == _NEW_OWNER_, "INVALID_CLAIM"); + emit OwnershipTransferred(_OWNER_, _NEW_OWNER_); + _OWNER_ = _NEW_OWNER_; + _NEW_OWNER_ = address(0); + } +} From d431baffb120d85c56077b112904c66e7bccf00f Mon Sep 17 00:00:00 2001 From: mingda Date: Fri, 24 Jul 2020 01:55:47 +0800 Subject: [PATCH 040/118] add flash trade --- contracts/impl/Trader.sol | 51 ++++++++++++++++++---------------- contracts/intf/IDODO.sol | 12 ++++++-- contracts/intf/IDODOCallee.sol | 18 ++++++++++++ 3 files changed, 55 insertions(+), 26 deletions(-) create mode 100644 contracts/intf/IDODOCallee.sol diff --git a/contracts/impl/Trader.sol b/contracts/impl/Trader.sol index ee75ae3..c18d4cf 100644 --- a/contracts/impl/Trader.sol +++ b/contracts/impl/Trader.sol @@ -11,6 +11,7 @@ pragma experimental ABIEncoderV2; import {SafeMath} from "../lib/SafeMath.sol"; import {DecimalMath} from "../lib/DecimalMath.sol"; import {Types} from "../lib/Types.sol"; +import {IDODOCallee} from "../intf/IDODOCallee.sol"; import {Storage} from "./Storage.sol"; import {Pricing} from "./Pricing.sol"; import {Settlement} from "./Settlement.sol"; @@ -46,13 +47,11 @@ contract Trader is Storage, Pricing, Settlement { // ============ Trade Functions ============ - function sellBaseToken(uint256 amount, uint256 minReceiveQuote) - external - tradeAllowed - gasPriceLimit - preventReentrant - returns (uint256) - { + function sellBaseToken( + uint256 amount, + uint256 minReceiveQuote, + bytes calldata data + ) external tradeAllowed gasPriceLimit preventReentrant returns (uint256) { // query price ( uint256 receiveQuote, @@ -65,9 +64,15 @@ contract Trader is Storage, Pricing, Settlement { require(receiveQuote >= minReceiveQuote, "SELL_BASE_RECEIVE_NOT_ENOUGH"); // settle assets - _baseTokenTransferIn(msg.sender, amount); _quoteTokenTransferOut(msg.sender, receiveQuote); - _quoteTokenTransferOut(_MAINTAINER_, mtFeeQuote); + if (data.length > 0) { + IDODOCallee(msg.sender).dodoCall(false, amount, receiveQuote, data); + } + _baseTokenTransferIn(msg.sender, amount); + if (mtFeeQuote != 0) { + _quoteTokenTransferOut(_MAINTAINER_, mtFeeQuote); + emit ChargeMaintainerFee(_MAINTAINER_, false, mtFeeQuote); + } // update TARGET if (_TARGET_QUOTE_TOKEN_AMOUNT_ != newQuoteTarget) { @@ -82,20 +87,15 @@ contract Trader is Storage, Pricing, Settlement { _donateQuoteToken(lpFeeQuote); emit SellBaseToken(msg.sender, amount, receiveQuote); - if (mtFeeQuote != 0) { - emit ChargeMaintainerFee(_MAINTAINER_, false, mtFeeQuote); - } return receiveQuote; } - function buyBaseToken(uint256 amount, uint256 maxPayQuote) - external - tradeAllowed - gasPriceLimit - preventReentrant - returns (uint256) - { + function buyBaseToken( + uint256 amount, + uint256 maxPayQuote, + bytes calldata data + ) external tradeAllowed gasPriceLimit preventReentrant returns (uint256) { // query price ( uint256 payQuote, @@ -108,9 +108,15 @@ contract Trader is Storage, Pricing, Settlement { require(payQuote <= maxPayQuote, "BUY_BASE_COST_TOO_MUCH"); // settle assets - _quoteTokenTransferIn(msg.sender, payQuote); _baseTokenTransferOut(msg.sender, amount); - _baseTokenTransferOut(_MAINTAINER_, mtFeeBase); + if (data.length > 0) { + IDODOCallee(msg.sender).dodoCall(true, amount, payQuote, data); + } + _quoteTokenTransferIn(msg.sender, payQuote); + if (mtFeeBase != 0) { + _baseTokenTransferOut(_MAINTAINER_, mtFeeBase); + emit ChargeMaintainerFee(_MAINTAINER_, true, mtFeeBase); + } // update TARGET if (_TARGET_QUOTE_TOKEN_AMOUNT_ != newQuoteTarget) { @@ -125,9 +131,6 @@ contract Trader is Storage, Pricing, Settlement { _donateBaseToken(lpFeeBase); emit BuyBaseToken(msg.sender, amount, payQuote); - if (mtFeeBase != 0) { - emit ChargeMaintainerFee(_MAINTAINER_, true, mtFeeBase); - } return payQuote; } diff --git a/contracts/intf/IDODO.sol b/contracts/intf/IDODO.sol index 2b6e45d..acbbea7 100644 --- a/contracts/intf/IDODO.sol +++ b/contracts/intf/IDODO.sol @@ -25,9 +25,17 @@ interface IDODO { function claimOwnership() external; - function sellBaseToken(uint256 amount, uint256 minReceiveQuote) external returns (uint256); + function sellBaseToken( + uint256 amount, + uint256 minReceiveQuote, + bytes calldata data + ) external returns (uint256); - function buyBaseToken(uint256 amount, uint256 maxPayQuote) external returns (uint256); + function buyBaseToken( + uint256 amount, + uint256 maxPayQuote, + bytes calldata data + ) external returns (uint256); function querySellBaseToken(uint256 amount) external view returns (uint256 receiveQuote); diff --git a/contracts/intf/IDODOCallee.sol b/contracts/intf/IDODOCallee.sol new file mode 100644 index 0000000..3b9b70d --- /dev/null +++ b/contracts/intf/IDODOCallee.sol @@ -0,0 +1,18 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +interface IDODOCallee { + function dodoCall( + bool isBuyBaseToken, + uint256 baseAmount, + uint256 quoteAmount, + bytes calldata data + ) external; +} From 522c11230f4a1a57ef58974034f0730ad6bdfffe Mon Sep 17 00:00:00 2001 From: mingda Date: Sat, 25 Jul 2020 01:18:50 +0800 Subject: [PATCH 041/118] Use Clone Factory --- contracts/DODOZoo.sol | 18 ++++++------------ contracts/helper/CloneFactory.sol | 30 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 12 deletions(-) create mode 100644 contracts/helper/CloneFactory.sol diff --git a/contracts/DODOZoo.sol b/contracts/DODOZoo.sol index 928f829..01a98b9 100644 --- a/contracts/DODOZoo.sol +++ b/contracts/DODOZoo.sol @@ -9,6 +9,7 @@ pragma solidity 0.6.9; pragma experimental ABIEncoderV2; import {Ownable} from "./lib/Ownable.sol"; +import {ICloneFactory} from "./helper/CloneFactory.sol"; interface IDODO { function init( @@ -34,6 +35,8 @@ interface IDODO { */ contract DODOZoo is Ownable { address public _DODO_LOGIC_; + address public _CLONE_FACTORY_; + mapping(address => mapping(address => address)) internal _DODO_REGISTER_; // ============ Events ============ @@ -42,8 +45,9 @@ contract DODOZoo is Ownable { // ============ Constructor Function ============ - constructor(address _dodoLogic) public { + constructor(address _dodoLogic, address _cloneFactory) public { _DODO_LOGIC_ = _dodoLogic; + _CLONE_FACTORY_ = _cloneFactory; } // ============ Breed DODO Function ============ @@ -62,17 +66,7 @@ contract DODOZoo is Ownable { require(!isDODORegistered(baseToken, quoteToken), "DODO_REGISTERED"); // Adapted from https://github.com/optionality/clone-factory/blob/32782f82dfc5a00d103a7e61a17a5dedbd1e8e9d/contracts/CloneFactory.sol // create proxy - bytes20 targetBytes = bytes20(_DODO_LOGIC_); - assembly { - let clone := mload(0x40) - mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) - mstore(add(clone, 0x14), targetBytes) - mstore( - add(clone, 0x28), - 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000 - ) - newBornDODO := create(0, clone, 0x37) - } + newBornDODO = ICloneFactory(_CLONE_FACTORY_).clone(_DODO_LOGIC_); IDODO(newBornDODO).init( supervisor, maintainer, diff --git a/contracts/helper/CloneFactory.sol b/contracts/helper/CloneFactory.sol new file mode 100644 index 0000000..0476913 --- /dev/null +++ b/contracts/helper/CloneFactory.sol @@ -0,0 +1,30 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +interface ICloneFactory { + function clone(address prototype) external returns (address proxy); +} + +contract CloneFactory is ICloneFactory { + function clone(address prototype) external override returns (address proxy) { + bytes20 targetBytes = bytes20(prototype); + assembly { + let clone := mload(0x40) + mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) + mstore(add(clone, 0x14), targetBytes) + mstore( + add(clone, 0x28), + 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000 + ) + proxy := create(0, clone, 0x37) + } + return proxy; + } +} From 1e5a905f61c19696bfec1bd20ea605f294745a97 Mon Sep 17 00:00:00 2001 From: mingda Date: Sat, 25 Jul 2020 01:19:26 +0800 Subject: [PATCH 042/118] Public Arbitrageur between UniswapV2 and DODO --- contracts/helper/UniswapArbitrageur.sol | 176 +++++++ contracts/helper/UniswapV2.sol | 636 ++++++++++++++++++++++++ contracts/intf/IDODO.sol | 4 + 3 files changed, 816 insertions(+) create mode 100644 contracts/helper/UniswapArbitrageur.sol create mode 100644 contracts/helper/UniswapV2.sol diff --git a/contracts/helper/UniswapArbitrageur.sol b/contracts/helper/UniswapArbitrageur.sol new file mode 100644 index 0000000..35460a9 --- /dev/null +++ b/contracts/helper/UniswapArbitrageur.sol @@ -0,0 +1,176 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +import {Ownable} from "../lib/Ownable.sol"; +import {IDODO} from "../intf/IDODO.sol"; +import {IERC20} from "../intf/IERC20.sol"; +import {SafeERC20} from "../lib/SafeERC20.sol"; +import {SafeMath} from "../lib/SafeMath.sol"; + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +interface IUniswapV2Pair { + function token0() external view returns (address); + + function token1() external view returns (address); + + function getReserves() + external + view + returns ( + uint112 reserve0, + uint112 reserve1, + uint32 blockTimestampLast + ); + + function swap( + uint256 amount0Out, + uint256 amount1Out, + address to, + bytes calldata data + ) external; +} + +contract UniswapArbitrageur { + using SafeMath for uint256; + using SafeERC20 for IERC20; + + bool public _INITIALIZED_; + + address public _UNISWAP_; + address public _DODO_; + address public _BASE_; + address public _QUOTE_; + + bool public _REVERSE_; // true if dodo.baseToken=uniswap.token0 + + uint256 public lastArbitrageProfit; + + function init(address _uniswap, address _dodo) external { + require(!_INITIALIZED_, "ALREADY_INITIALIZED"); + _INITIALIZED_ = true; + _UNISWAP_ = _uniswap; + _DODO_ = _dodo; + + _BASE_ = IDODO(_DODO_)._BASE_TOKEN_(); + _QUOTE_ = IDODO(_DODO_)._QUOTE_TOKEN_(); + + address token0 = IUniswapV2Pair(_UNISWAP_).token0(); + address token1 = IUniswapV2Pair(_UNISWAP_).token1(); + + if (token0 == _BASE_ && token1 == _QUOTE_) { + _REVERSE_ = false; + } else if (token0 == _QUOTE_ && token1 == _BASE_) { + _REVERSE_ = true; + } else { + require(true, "DODO_UNISWAP_NOT_MATCH"); + } + } + + function executeBuyArbitrage(uint256 baseAmount) external returns (uint256 quoteProfit) { + IDODO(_DODO_).buyBaseToken(baseAmount, uint256(-1), "0xd"); + return lastArbitrageProfit; + } + + function executeSellArbitrage(uint256 baseAmount) external returns (uint256 baseProfit) { + IDODO(_DODO_).sellBaseToken(baseAmount, 0, "0xd"); + return lastArbitrageProfit; + } + + function dodoCall( + bool isDODOBuy, + uint256 baseAmount, + uint256 quoteAmount, + bytes calldata + ) external { + require(msg.sender == _DODO_, "WRONG_DODO"); + if (_REVERSE_) { + _inverseArbitrage(isDODOBuy, baseAmount, quoteAmount); + } else { + _arbitrage(isDODOBuy, baseAmount, quoteAmount); + } + } + + function _inverseArbitrage( + bool isDODOBuy, + uint256 baseAmount, + uint256 quoteAmount + ) internal { + (uint112 _reserve0, uint112 _reserve1, ) = IUniswapV2Pair(_UNISWAP_).getReserves(); + uint256 token0Balance = uint256(_reserve0); + uint256 token1Balance = uint256(_reserve1); + uint256 token0Amount; + uint256 token1Amount; + if (isDODOBuy) { + IERC20(_BASE_).transfer(_UNISWAP_, baseAmount); + // transfer token1 into uniswap + uint256 newToken0Balance = token0Balance.mul(token1Balance).div( + token1Balance.add(baseAmount) + ); + token0Amount = token0Balance.sub(newToken0Balance).mul(9969).div(10000); // mul 0.9969 + require(token0Amount > quoteAmount, "NOT_PROFITABLE"); + lastArbitrageProfit = token0Amount.sub(quoteAmount); + IUniswapV2Pair(_UNISWAP_).swap(token0Amount, token1Amount, address(this), ""); + IERC20(_QUOTE_).transfer(tx.origin, lastArbitrageProfit); + } else { + IERC20(_QUOTE_).transfer(_UNISWAP_, quoteAmount); + // transfer token0 into uniswap + uint256 newToken1Balance = token0Balance.mul(token1Balance).div( + token0Balance.add(quoteAmount) + ); + token1Amount = token1Balance.sub(newToken1Balance).mul(9969).div(10000); // mul 0.9969 + require(token1Amount > baseAmount, "NOT_PROFITABLE"); + lastArbitrageProfit = token1Amount.sub(baseAmount); + IUniswapV2Pair(_UNISWAP_).swap(token0Amount, token1Amount, address(this), ""); + IERC20(_BASE_).transfer(tx.origin, lastArbitrageProfit); + } + } + + function _arbitrage( + bool isDODOBuy, + uint256 baseAmount, + uint256 quoteAmount + ) internal { + (uint112 _reserve0, uint112 _reserve1, ) = IUniswapV2Pair(_UNISWAP_).getReserves(); + uint256 token0Balance = uint256(_reserve0); + uint256 token1Balance = uint256(_reserve1); + uint256 token0Amount; + uint256 token1Amount; + if (isDODOBuy) { + IERC20(_BASE_).transfer(_UNISWAP_, baseAmount); + // transfer token0 into uniswap + uint256 newToken1Balance = token1Balance.mul(token0Balance).div( + token0Balance.add(baseAmount) + ); + token1Amount = token1Balance.sub(newToken1Balance).mul(9969).div(10000); // mul 0.9969 + require(token1Amount > quoteAmount, "NOT_PROFITABLE"); + lastArbitrageProfit = token1Amount.sub(quoteAmount); + IUniswapV2Pair(_UNISWAP_).swap(token0Amount, token1Amount, address(this), ""); + IERC20(_QUOTE_).transfer(tx.origin, lastArbitrageProfit); + } else { + IERC20(_QUOTE_).transfer(_UNISWAP_, quoteAmount); + // transfer token1 into uniswap + uint256 newToken0Balance = token1Balance.mul(token0Balance).div( + token1Balance.add(quoteAmount) + ); + token0Amount = token0Balance.sub(newToken0Balance).mul(9969).div(10000); // mul 0.9969 + require(token0Amount > baseAmount, "NOT_PROFITABLE"); + lastArbitrageProfit = token0Amount.sub(baseAmount); + IUniswapV2Pair(_UNISWAP_).swap(token0Amount, token1Amount, address(this), ""); + IERC20(_BASE_).transfer(tx.origin, lastArbitrageProfit); + } + } + + function retrieve(address token, uint256 amount) external { + IERC20(token).safeTransfer(msg.sender, amount); + } + + function approve(address token, address spender) external { + IERC20(token).approve(spender, uint256(-1)); + } +} diff --git a/contracts/helper/UniswapV2.sol b/contracts/helper/UniswapV2.sol new file mode 100644 index 0000000..282d07b --- /dev/null +++ b/contracts/helper/UniswapV2.sol @@ -0,0 +1,636 @@ +/** + *Submitted for verification at Etherscan.io on 2020-05-05 + */ + +// File: contracts/interfaces/IUniswapV2Pair.sol + +pragma solidity >=0.5.0; + +interface IUniswapV2Pair { + event Approval(address indexed owner, address indexed spender, uint256 value); + event Transfer(address indexed from, address indexed to, uint256 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 (uint256); + + function balanceOf(address owner) external view returns (uint256); + + function allowance(address owner, address spender) external view returns (uint256); + + function approve(address spender, uint256 value) external returns (bool); + + function transfer(address to, uint256 value) external returns (bool); + + function transferFrom( + address from, + address to, + uint256 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 (uint256); + + function permit( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; + + event Mint(address indexed sender, uint256 amount0, uint256 amount1); + event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to); + event Swap( + address indexed sender, + uint256 amount0In, + uint256 amount1In, + uint256 amount0Out, + uint256 amount1Out, + address indexed to + ); + event Sync(uint112 reserve0, uint112 reserve1); + + function MINIMUM_LIQUIDITY() external pure returns (uint256); + + 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 (uint256); + + function price1CumulativeLast() external view returns (uint256); + + function kLast() external view returns (uint256); + + function mint(address to) external returns (uint256 liquidity); + + function burn(address to) external returns (uint256 amount0, uint256 amount1); + + function swap( + uint256 amount0Out, + uint256 amount1Out, + address to, + bytes calldata data + ) external; + + function skim(address to) external; + + function sync() external; + + function initialize(address, address) external; +} + +// File: contracts/interfaces/IUniswapV2ERC20.sol + +pragma solidity >=0.5.0; + +interface IUniswapV2ERC20 { + event Approval(address indexed owner, address indexed spender, uint256 value); + event Transfer(address indexed from, address indexed to, uint256 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 (uint256); + + function balanceOf(address owner) external view returns (uint256); + + function allowance(address owner, address spender) external view returns (uint256); + + function approve(address spender, uint256 value) external returns (bool); + + function transfer(address to, uint256 value) external returns (bool); + + function transferFrom( + address from, + address to, + uint256 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 (uint256); + + function permit( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; +} + +// File: contracts/libraries/SafeMath.sol + +pragma solidity 0.6.9; + +// a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math) + +library SafeMath { + function add(uint256 x, uint256 y) internal pure returns (uint256 z) { + require((z = x + y) >= x, "ds-math-add-overflow"); + } + + function sub(uint256 x, uint256 y) internal pure returns (uint256 z) { + require((z = x - y) <= x, "ds-math-sub-underflow"); + } + + function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { + require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow"); + } +} + +// File: contracts/UniswapV2ERC20.sol + +pragma solidity 0.6.9; + +contract UniswapV2ERC20 { + using SafeMath for uint256; + + string public constant name = "Uniswap V2"; + string public constant symbol = "UNI-V2"; + uint8 public constant decimals = 18; + uint256 public totalSupply; + mapping(address => uint256) public balanceOf; + mapping(address => mapping(address => uint256)) 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 => uint256) public nonces; + + event Approval(address indexed owner, address indexed spender, uint256 value); + event Transfer(address indexed from, address indexed to, uint256 value); + + function _mint(address to, uint256 value) internal { + totalSupply = totalSupply.add(value); + balanceOf[to] = balanceOf[to].add(value); + emit Transfer(address(0), to, value); + } + + function _burn(address from, uint256 value) internal { + balanceOf[from] = balanceOf[from].sub(value); + totalSupply = totalSupply.sub(value); + emit Transfer(from, address(0), value); + } + + function _approve( + address owner, + address spender, + uint256 value + ) private { + allowance[owner][spender] = value; + emit Approval(owner, spender, value); + } + + function _transfer( + address from, + address to, + uint256 value + ) private { + balanceOf[from] = balanceOf[from].sub(value); + balanceOf[to] = balanceOf[to].add(value); + emit Transfer(from, to, value); + } + + function approve(address spender, uint256 value) external returns (bool) { + _approve(msg.sender, spender, value); + return true; + } + + function transfer(address to, uint256 value) external returns (bool) { + _transfer(msg.sender, to, value); + return true; + } + + function transferFrom( + address from, + address to, + uint256 value + ) external returns (bool) { + if (allowance[from][msg.sender] != uint256(-1)) { + allowance[from][msg.sender] = allowance[from][msg.sender].sub(value); + } + _transfer(from, to, value); + return true; + } + + function permit( + address owner, + address spender, + uint256 value, + uint256 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); + } +} + +// File: contracts/libraries/Math.sol + +pragma solidity 0.6.9; + +// a library for performing various math operations + +library Math { + function min(uint256 x, uint256 y) internal pure returns (uint256 z) { + z = x < y ? x : y; + } + + // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method) + function sqrt(uint256 y) internal pure returns (uint256 z) { + if (y > 3) { + z = y; + uint256 x = y / 2 + 1; + while (x < z) { + z = x; + x = (y / x + x) / 2; + } + } else if (y != 0) { + z = 1; + } + } +} + +// File: contracts/libraries/UQ112x112.sol + +pragma solidity 0.6.9; + +// 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); + } +} + +// File: contracts/interfaces/IERC20.sol + +pragma solidity >=0.5.0; + +interface IERC20 { + event Approval(address indexed owner, address indexed spender, uint256 value); + event Transfer(address indexed from, address indexed to, uint256 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 (uint256); + + function balanceOf(address owner) external view returns (uint256); + + function allowance(address owner, address spender) external view returns (uint256); + + function approve(address spender, uint256 value) external returns (bool); + + function transfer(address to, uint256 value) external returns (bool); + + function transferFrom( + address from, + address to, + uint256 value + ) external returns (bool); +} + +// File: contracts/interfaces/IUniswapV2Factory.sol + +pragma solidity >=0.5.0; + +interface IUniswapV2Factory { + event PairCreated(address indexed token0, address indexed token1, address pair, uint256); + + function feeTo() external view returns (address); + + function feeToSetter() external view returns (address); + + function getPair(address tokenA, address tokenB) external view returns (address pair); + + function allPairs(uint256) external view returns (address pair); + + function allPairsLength() external view returns (uint256); + + function createPair(address tokenA, address tokenB) external returns (address pair); + + function setFeeTo(address) external; + + function setFeeToSetter(address) external; +} + +// File: contracts/interfaces/IUniswapV2Callee.sol + +pragma solidity >=0.5.0; + +interface IUniswapV2Callee { + function uniswapV2Call( + address sender, + uint256 amount0, + uint256 amount1, + bytes calldata data + ) external; +} + +// File: contracts/UniswapV2Pair.sol + +pragma solidity 0.6.9; + +contract UniswapV2Pair is UniswapV2ERC20 { + using SafeMath for uint256; + using UQ112x112 for uint224; + + uint256 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 + + uint256 public price0CumulativeLast; + uint256 public price1CumulativeLast; + uint256 public kLast; // reserve0 * reserve1, as of immediately after the most recent liquidity event + + uint256 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, + uint256 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, uint256 amount0, uint256 amount1); + event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to); + event Swap( + address indexed sender, + uint256 amount0In, + uint256 amount1In, + uint256 amount0Out, + uint256 amount1Out, + address indexed to + ); + event Sync(uint112 reserve0, uint112 reserve1); + + constructor() public { + factory = msg.sender; + } + + // 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( + uint256 balance0, + uint256 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 += + uint256(UQ112x112.encode(_reserve1).uqdiv(_reserve0)) * + timeElapsed; + price1CumulativeLast += + uint256(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) + function _mintFee(uint112 _reserve0, uint112 _reserve1) private returns (bool feeOn) { + address feeTo = IUniswapV2Factory(factory).feeTo(); + feeOn = feeTo != address(0); + uint256 _kLast = kLast; // gas savings + if (feeOn) { + if (_kLast != 0) { + uint256 rootK = Math.sqrt(uint256(_reserve0).mul(_reserve1)); + uint256 rootKLast = Math.sqrt(_kLast); + if (rootK > rootKLast) { + uint256 numerator = totalSupply.mul(rootK.sub(rootKLast)); + uint256 denominator = rootK.mul(5).add(rootKLast); + uint256 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 (uint256 liquidity) { + (uint112 _reserve0, uint112 _reserve1, ) = getReserves(); // gas savings + uint256 balance0 = IERC20(token0).balanceOf(address(this)); + uint256 balance1 = IERC20(token1).balanceOf(address(this)); + uint256 amount0 = balance0.sub(_reserve0); + uint256 amount1 = balance1.sub(_reserve1); + + bool feeOn = _mintFee(_reserve0, _reserve1); + uint256 _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee + if (_totalSupply == 0) { + 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 = uint256(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 (uint256 amount0, uint256 amount1) { + (uint112 _reserve0, uint112 _reserve1, ) = getReserves(); // gas savings + address _token0 = token0; // gas savings + address _token1 = token1; // gas savings + uint256 balance0 = IERC20(_token0).balanceOf(address(this)); + uint256 balance1 = IERC20(_token1).balanceOf(address(this)); + uint256 liquidity = balanceOf[address(this)]; + + bool feeOn = _mintFee(_reserve0, _reserve1); + uint256 _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 = IERC20(_token0).balanceOf(address(this)); + balance1 = IERC20(_token1).balanceOf(address(this)); + + _update(balance0, balance1, _reserve0, _reserve1); + if (feeOn) kLast = uint256(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date + emit Burn(msg.sender, amount0, amount1, to); + } + + // this low-level function should be called from a contract which performs important safety checks + function swap( + uint256 amount0Out, + uint256 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" + ); + + uint256 balance0; + uint256 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 = IERC20(_token0).balanceOf(address(this)); + balance1 = IERC20(_token1).balanceOf(address(this)); + } + uint256 amount0In = balance0 > _reserve0 - amount0Out + ? balance0 - (_reserve0 - amount0Out) + : 0; + uint256 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 + uint256 balance0Adjusted = balance0.mul(1000).sub(amount0In.mul(3)); + uint256 balance1Adjusted = balance1.mul(1000).sub(amount1In.mul(3)); + require( + balance0Adjusted.mul(balance1Adjusted) >= + uint256(_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, IERC20(_token0).balanceOf(address(this)).sub(reserve0)); + _safeTransfer(_token1, to, IERC20(_token1).balanceOf(address(this)).sub(reserve1)); + } + + // force reserves to match balances + function sync() external lock { + _update( + IERC20(token0).balanceOf(address(this)), + IERC20(token1).balanceOf(address(this)), + reserve0, + reserve1 + ); + } +} diff --git a/contracts/intf/IDODO.sol b/contracts/intf/IDODO.sol index acbbea7..04ef9f0 100644 --- a/contracts/intf/IDODO.sol +++ b/contracts/intf/IDODO.sol @@ -56,4 +56,8 @@ interface IDODO { function _BASE_CAPITAL_TOKEN_() external returns (address); function _QUOTE_CAPITAL_TOKEN_() external returns (address); + + function _BASE_TOKEN_() external returns (address); + + function _QUOTE_TOKEN_() external returns (address); } From fa80a2b0fd27687afb793d901c45a2a6371dcf1f Mon Sep 17 00:00:00 2001 From: mingda Date: Sat, 25 Jul 2020 14:52:36 +0800 Subject: [PATCH 043/118] set default supervisor in dodozoo --- contracts/DODOZoo.sol | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/contracts/DODOZoo.sol b/contracts/DODOZoo.sol index 01a98b9..a7347ba 100644 --- a/contracts/DODOZoo.sol +++ b/contracts/DODOZoo.sol @@ -37,6 +37,8 @@ contract DODOZoo is Ownable { address public _DODO_LOGIC_; address public _CLONE_FACTORY_; + address public _DEFAULT_SUPERVISOR_; + mapping(address => mapping(address => address)) internal _DODO_REGISTER_; // ============ Events ============ @@ -45,15 +47,19 @@ contract DODOZoo is Ownable { // ============ Constructor Function ============ - constructor(address _dodoLogic, address _cloneFactory) public { + constructor( + address _dodoLogic, + address _cloneFactory, + address _defaultSupervisor + ) public { _DODO_LOGIC_ = _dodoLogic; _CLONE_FACTORY_ = _cloneFactory; + _DEFAULT_SUPERVISOR_ = _defaultSupervisor; } // ============ Breed DODO Function ============ function breedDODO( - address supervisor, address maintainer, address baseToken, address quoteToken, @@ -68,7 +74,7 @@ contract DODOZoo is Ownable { // create proxy newBornDODO = ICloneFactory(_CLONE_FACTORY_).clone(_DODO_LOGIC_); IDODO(newBornDODO).init( - supervisor, + _DEFAULT_SUPERVISOR_, maintainer, baseToken, quoteToken, From 71cb3852ca8465cf08f9bb7f9cd49db6aee89d5f Mon Sep 17 00:00:00 2001 From: mingda Date: Sat, 25 Jul 2020 14:56:11 +0800 Subject: [PATCH 044/118] dodo eth proxy fit new dodo trade abi --- contracts/DODOEthProxy.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/DODOEthProxy.sol b/contracts/DODOEthProxy.sol index 2a3edd2..53e25dd 100644 --- a/contracts/DODOEthProxy.sol +++ b/contracts/DODOEthProxy.sol @@ -72,7 +72,7 @@ contract DODOEthProxy is ReentrancyGuard { require(DODO != address(0), "DODO_NOT_EXIST"); IWETH(_WETH_).deposit{value: ethAmount}(); IWETH(_WETH_).approve(DODO, ethAmount); - receiveTokenAmount = IDODO(DODO).sellBaseToken(ethAmount, minReceiveTokenAmount); + receiveTokenAmount = IDODO(DODO).sellBaseToken(ethAmount, minReceiveTokenAmount, ""); _transferOut(quoteTokenAddress, msg.sender, receiveTokenAmount); emit ProxySellEth(msg.sender, quoteTokenAddress, ethAmount, receiveTokenAmount); return receiveTokenAmount; @@ -88,7 +88,7 @@ contract DODOEthProxy is ReentrancyGuard { payTokenAmount = IDODO(DODO).queryBuyBaseToken(ethAmount); _transferIn(quoteTokenAddress, msg.sender, payTokenAmount); IERC20(quoteTokenAddress).approve(DODO, payTokenAmount); - IDODO(DODO).buyBaseToken(ethAmount, maxPayTokenAmount); + IDODO(DODO).buyBaseToken(ethAmount, maxPayTokenAmount, ""); IWETH(_WETH_).withdraw(ethAmount); msg.sender.transfer(ethAmount); emit ProxyBuyEth(msg.sender, quoteTokenAddress, ethAmount, payTokenAmount); From d58cd90a1f09669b1a816e4d3dd1d4dbce31cd5f Mon Sep 17 00:00:00 2001 From: mingda Date: Sat, 25 Jul 2020 15:48:50 +0800 Subject: [PATCH 045/118] Add Admin control to dodo zoo --- contracts/DODOZoo.sol | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/contracts/DODOZoo.sol b/contracts/DODOZoo.sol index a7347ba..75124ad 100644 --- a/contracts/DODOZoo.sol +++ b/contracts/DODOZoo.sol @@ -57,6 +57,24 @@ contract DODOZoo is Ownable { _DEFAULT_SUPERVISOR_ = _defaultSupervisor; } + // ============ Admin Function ============ + + function setDODOLogic(address _dodoLogic) external onlyOwner { + _DODO_LOGIC_ = _dodoLogic; + } + + function setCloneFactory(address _cloneFactory) external onlyOwner { + _CLONE_FACTORY_ = _cloneFactory; + } + + function setDefaultSupervisor(address _defaultSupervisor) external onlyOwner { + _DEFAULT_SUPERVISOR_ = _defaultSupervisor; + } + + function removeDODO(address baseToken, address quoteToken) external onlyOwner { + _DODO_REGISTER_[baseToken][quoteToken] = address(0); + } + // ============ Breed DODO Function ============ function breedDODO( @@ -90,10 +108,6 @@ contract DODOZoo is Ownable { return newBornDODO; } - function removeDODO(address baseToken, address quoteToken) external onlyOwner { - _DODO_REGISTER_[baseToken][quoteToken] = address(0); - } - // ============ View Functions ============ function isDODORegistered(address baseToken, address quoteToken) public view returns (bool) { From f5d1e1830a7f1e7fd5f40a6e1bbc388111628499 Mon Sep 17 00:00:00 2001 From: mingda Date: Sat, 25 Jul 2020 15:49:01 +0800 Subject: [PATCH 046/118] add version control to storage --- contracts/impl/Storage.sol | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/contracts/impl/Storage.sol b/contracts/impl/Storage.sol index 3135772..f805dc1 100644 --- a/contracts/impl/Storage.sol +++ b/contracts/impl/Storage.sol @@ -103,4 +103,9 @@ contract Storage is InitializableOwnable, ReentrancyGuard { function getTotalQuoteCapital() public view returns (uint256) { return IDODOLpToken(_QUOTE_CAPITAL_TOKEN_).totalSupply(); } + + // ============ Version Control ============ + function version() external pure returns (uint256) { + return 1; + } } From a908a078cc185d32b937fef82142a22b14fcb565 Mon Sep 17 00:00:00 2001 From: mingda Date: Sat, 25 Jul 2020 17:58:06 +0800 Subject: [PATCH 047/118] set dodo owner in init function --- contracts/DODOZoo.sol | 5 ++--- contracts/dodo.sol | 3 ++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/contracts/DODOZoo.sol b/contracts/DODOZoo.sol index 75124ad..722eeb3 100644 --- a/contracts/DODOZoo.sol +++ b/contracts/DODOZoo.sol @@ -13,6 +13,7 @@ import {ICloneFactory} from "./helper/CloneFactory.sol"; interface IDODO { function init( + address owner, address supervisor, address maintainer, address baseToken, @@ -88,10 +89,9 @@ contract DODOZoo is Ownable { uint256 gasPriceLimit ) external onlyOwner returns (address newBornDODO) { require(!isDODORegistered(baseToken, quoteToken), "DODO_REGISTERED"); - // Adapted from https://github.com/optionality/clone-factory/blob/32782f82dfc5a00d103a7e61a17a5dedbd1e8e9d/contracts/CloneFactory.sol - // create proxy newBornDODO = ICloneFactory(_CLONE_FACTORY_).clone(_DODO_LOGIC_); IDODO(newBornDODO).init( + _OWNER_, _DEFAULT_SUPERVISOR_, maintainer, baseToken, @@ -102,7 +102,6 @@ contract DODOZoo is Ownable { k, gasPriceLimit ); - IDODO(newBornDODO).transferOwnership(_OWNER_); _DODO_REGISTER_[baseToken][quoteToken] = newBornDODO; emit DODOBirth(newBornDODO, baseToken, quoteToken); return newBornDODO; diff --git a/contracts/dodo.sol b/contracts/dodo.sol index 5313063..81be5dd 100644 --- a/contracts/dodo.sol +++ b/contracts/dodo.sol @@ -24,6 +24,7 @@ import {DODOLpToken} from "./impl/DODOLpToken.sol"; */ contract DODO is Admin, Trader, LiquidityProvider { function init( + address owner, address supervisor, address maintainer, address baseToken, @@ -38,7 +39,7 @@ contract DODO is Admin, Trader, LiquidityProvider { _INITIALIZED_ = true; // constructor - _OWNER_ = msg.sender; + _OWNER_ = owner; emit OwnershipTransferred(address(0), _OWNER_); _SUPERVISOR_ = supervisor; From a075f40db380f95c9794470a055bc2ce96f99635 Mon Sep 17 00:00:00 2001 From: mingda Date: Sun, 26 Jul 2020 13:22:25 +0800 Subject: [PATCH 048/118] add comments --- contracts/helper/CloneFactory.sol | 3 +++ contracts/impl/Storage.sol | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/contracts/helper/CloneFactory.sol b/contracts/helper/CloneFactory.sol index 0476913..fd8f755 100644 --- a/contracts/helper/CloneFactory.sol +++ b/contracts/helper/CloneFactory.sol @@ -12,6 +12,9 @@ interface ICloneFactory { function clone(address prototype) external returns (address proxy); } +// introduction of proxy mode design: https://docs.openzeppelin.com/upgrades/2.8/ +// minimum implementation of transparent proxy: https://eips.ethereum.org/EIPS/eip-1167 + contract CloneFactory is ICloneFactory { function clone(address prototype) external override returns (address proxy) { bytes20 targetBytes = bytes20(prototype); diff --git a/contracts/impl/Storage.sol b/contracts/impl/Storage.sol index f805dc1..dd34d3e 100644 --- a/contracts/impl/Storage.sol +++ b/contracts/impl/Storage.sol @@ -106,6 +106,6 @@ contract Storage is InitializableOwnable, ReentrancyGuard { // ============ Version Control ============ function version() external pure returns (uint256) { - return 1; + return 100; // 1.0.0 } } From e5be1a065fb657dccde093ebbbe844ed22aa5b69 Mon Sep 17 00:00:00 2001 From: mingda Date: Sun, 26 Jul 2020 13:49:02 +0800 Subject: [PATCH 049/118] update IDODO --- contracts/intf/IDODO.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/intf/IDODO.sol b/contracts/intf/IDODO.sol index 04ef9f0..4a8dd39 100644 --- a/contracts/intf/IDODO.sol +++ b/contracts/intf/IDODO.sol @@ -10,6 +10,7 @@ pragma experimental ABIEncoderV2; interface IDODO { function init( + address owner, address supervisor, address maintainer, address baseToken, From 5b074c7b140d4a40230d54e9b500e29d8311b3a6 Mon Sep 17 00:00:00 2001 From: mingda Date: Thu, 30 Jul 2020 01:23:49 +0800 Subject: [PATCH 050/118] return capital change in deposit --- contracts/impl/LiquidityProvider.sol | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/contracts/impl/LiquidityProvider.sol b/contracts/impl/LiquidityProvider.sol index 7bb2600..338f22e 100644 --- a/contracts/impl/LiquidityProvider.sol +++ b/contracts/impl/LiquidityProvider.sol @@ -64,16 +64,16 @@ contract LiquidityProvider is Storage, Pricing, Settlement { return withdrawBaseTo(msg.sender, amount); } - function depositBase(uint256 amount) external { - depositBaseTo(msg.sender, amount); + function depositBase(uint256 amount) external returns (uint256) { + return depositBaseTo(msg.sender, amount); } function withdrawQuote(uint256 amount) external returns (uint256) { return withdrawQuoteTo(msg.sender, amount); } - function depositQuote(uint256 amount) external { - depositQuoteTo(msg.sender, amount); + function depositQuote(uint256 amount) external returns (uint256) { + return depositQuoteTo(msg.sender, amount); } function withdrawAllBase() external returns (uint256) { @@ -90,6 +90,7 @@ contract LiquidityProvider is Storage, Pricing, Settlement { public preventReentrant depositQuoteAllowed + returns (uint256) { (, uint256 quoteTarget) = getExpectedTarget(); uint256 totalQuoteCapital = getTotalQuoteCapital(); @@ -107,9 +108,15 @@ contract LiquidityProvider is Storage, Pricing, Settlement { _TARGET_QUOTE_TOKEN_AMOUNT_ = _TARGET_QUOTE_TOKEN_AMOUNT_.add(amount); emit Deposit(msg.sender, to, false, amount, capital); + return capital; } - function depositBaseTo(address to, uint256 amount) public preventReentrant depositBaseAllowed { + function depositBaseTo(address to, uint256 amount) + public + preventReentrant + depositBaseAllowed + returns (uint256) + { (uint256 baseTarget, ) = getExpectedTarget(); uint256 totalBaseCapital = getTotalBaseCapital(); uint256 capital = amount; @@ -126,6 +133,7 @@ contract LiquidityProvider is Storage, Pricing, Settlement { _TARGET_BASE_TOKEN_AMOUNT_ = _TARGET_BASE_TOKEN_AMOUNT_.add(amount); emit Deposit(msg.sender, to, true, amount, capital); + return capital; } // ============ Withdraw Functions ============ From 6b9151de3d93acf5f894823862d4fb7abb2428f1 Mon Sep 17 00:00:00 2001 From: mingda Date: Thu, 30 Jul 2020 01:24:00 +0800 Subject: [PATCH 051/118] emit transfer in burn --- contracts/impl/DODOLpToken.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/impl/DODOLpToken.sol b/contracts/impl/DODOLpToken.sol index e64652c..ece9f6d 100644 --- a/contracts/impl/DODOLpToken.sol +++ b/contracts/impl/DODOLpToken.sol @@ -129,5 +129,6 @@ contract DODOLpToken is Ownable { balances[user] = balances[user].sub(value); totalSupply = totalSupply.sub(value); emit Burn(user, value); + emit Transfer(user, address(0), value); } } From 319af8967cafc4a56507abd5c763175fe4f4ee2b Mon Sep 17 00:00:00 2001 From: mingda Date: Thu, 30 Jul 2020 01:32:22 +0800 Subject: [PATCH 052/118] add list of dodo in dodozoo --- contracts/DODOZoo.sol | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/contracts/DODOZoo.sol b/contracts/DODOZoo.sol index 722eeb3..08aed7e 100644 --- a/contracts/DODOZoo.sol +++ b/contracts/DODOZoo.sol @@ -9,25 +9,9 @@ pragma solidity 0.6.9; pragma experimental ABIEncoderV2; import {Ownable} from "./lib/Ownable.sol"; +import {IDODO} from "./intf/IDODO.sol"; import {ICloneFactory} from "./helper/CloneFactory.sol"; -interface IDODO { - function init( - address owner, - address supervisor, - address maintainer, - address baseToken, - address quoteToken, - address oracle, - uint256 lpFeeRate, - uint256 mtFeeRate, - uint256 k, - uint256 gasPriceLimit - ) external; - - function transferOwnership(address newOwner) external; -} - /** * @title DODOZoo * @author DODO Breeder @@ -41,6 +25,7 @@ contract DODOZoo is Ownable { address public _DEFAULT_SUPERVISOR_; mapping(address => mapping(address => address)) internal _DODO_REGISTER_; + address[] public _DODOs; // ============ Events ============ @@ -72,8 +57,25 @@ contract DODOZoo is Ownable { _DEFAULT_SUPERVISOR_ = _defaultSupervisor; } - function removeDODO(address baseToken, address quoteToken) external onlyOwner { + function removeDODO(address dodo) external onlyOwner { + address baseToken = IDODO(dodo)._BASE_TOKEN_(); + address quoteToken = IDODO(dodo)._QUOTE_TOKEN_(); + require(isDODORegistered(baseToken, quoteToken), "DODO_NOT_REGISTERED"); _DODO_REGISTER_[baseToken][quoteToken] = address(0); + for (uint256 i = 0; i < _DODOs.length - 1; i++) + if (_DODOs[i] == dodo) { + _DODOs[i] = _DODOs[_DODOs.length - 1]; + break; + } + _DODOs.pop(); + } + + function addDODO(address dodo) external onlyOwner { + address baseToken = IDODO(dodo)._BASE_TOKEN_(); + address quoteToken = IDODO(dodo)._QUOTE_TOKEN_(); + require(!isDODORegistered(baseToken, quoteToken), "DODO_REGISTERED"); + _DODO_REGISTER_[baseToken][quoteToken] = dodo; + _DODOs.push(dodo); } // ============ Breed DODO Function ============ @@ -103,6 +105,7 @@ contract DODOZoo is Ownable { gasPriceLimit ); _DODO_REGISTER_[baseToken][quoteToken] = newBornDODO; + _DODOs.push(newBornDODO); emit DODOBirth(newBornDODO, baseToken, quoteToken); return newBornDODO; } From 23aef577b888a9ab0fd7ae0d86c7d817a274380a Mon Sep 17 00:00:00 2001 From: mingda Date: Thu, 30 Jul 2020 02:10:37 +0800 Subject: [PATCH 053/118] update IDODO --- contracts/intf/IDODO.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/intf/IDODO.sol b/contracts/intf/IDODO.sol index 4a8dd39..fe273da 100644 --- a/contracts/intf/IDODO.sol +++ b/contracts/intf/IDODO.sol @@ -42,13 +42,13 @@ interface IDODO { function queryBuyBaseToken(uint256 amount) external view returns (uint256 payQuote); - function depositBaseTo(address to, uint256 amount) external; + function depositBaseTo(address to, uint256 amount) external returns (uint256); function withdrawBase(uint256 amount) external returns (uint256); function withdrawAllBase() external returns (uint256); - function depositQuoteTo(address to, uint256 amount) external; + function depositQuoteTo(address to, uint256 amount) external returns (uint256); function withdrawQuote(uint256 amount) external returns (uint256); From f2a6a10f1c09dfd60e9f2a4900d39d677efd5965 Mon Sep 17 00:00:00 2001 From: mingda Date: Thu, 30 Jul 2020 02:10:49 +0800 Subject: [PATCH 054/118] multi sig wallet with time lock --- .../helper/MultiSigWalletWithTimeLock.sol | 369 ++++++++++++++++++ 1 file changed, 369 insertions(+) create mode 100644 contracts/helper/MultiSigWalletWithTimeLock.sol diff --git a/contracts/helper/MultiSigWalletWithTimeLock.sol b/contracts/helper/MultiSigWalletWithTimeLock.sol new file mode 100644 index 0000000..a921c43 --- /dev/null +++ b/contracts/helper/MultiSigWalletWithTimeLock.sol @@ -0,0 +1,369 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +contract MultiSigWalletWithTimelock { + uint256 public constant MAX_OWNER_COUNT = 50; + uint256 public lockSeconds = 86400; + + event Confirmation(address indexed sender, uint256 indexed transactionId); + event Revocation(address indexed sender, uint256 indexed transactionId); + event Submission(uint256 indexed transactionId); + event Execution(uint256 indexed transactionId); + event ExecutionFailure(uint256 indexed transactionId); + event Deposit(address indexed sender, uint256 value); + event OwnerAddition(address indexed owner); + event OwnerRemoval(address indexed owner); + event RequirementChange(uint256 required); + event UnlockTimeSet(uint256 indexed transactionId, uint256 confirmationTime); + event LockSecondsChange(uint256 lockSeconds); + + mapping(uint256 => Transaction) public transactions; + mapping(uint256 => mapping(address => bool)) public confirmations; + mapping(address => bool) public isOwner; + mapping(uint256 => uint256) public unlockTimes; + + address[] public owners; + uint256 public required; + uint256 public transactionCount; + + struct Transaction { + address destination; + uint256 value; + bytes data; + bool executed; + } + + modifier onlyWallet() { + if (msg.sender != address(this)) revert("ONLY_WALLET_ERROR"); + _; + } + + modifier ownerDoesNotExist(address owner) { + if (isOwner[owner]) revert("OWNER_DOES_NOT_EXIST_ERROR"); + _; + } + + modifier ownerExists(address owner) { + if (!isOwner[owner]) revert("OWNER_EXISTS_ERROR"); + _; + } + + modifier transactionExists(uint256 transactionId) { + if (transactions[transactionId].destination == address(0)) + revert("TRANSACTION_EXISTS_ERROR"); + _; + } + + modifier confirmed(uint256 transactionId, address owner) { + if (!confirmations[transactionId][owner]) revert("CONFIRMED_ERROR"); + _; + } + + modifier notConfirmed(uint256 transactionId, address owner) { + if (confirmations[transactionId][owner]) revert("NOT_CONFIRMED_ERROR"); + _; + } + + modifier notExecuted(uint256 transactionId) { + if (transactions[transactionId].executed) revert("NOT_EXECUTED_ERROR"); + _; + } + + modifier notNull(address _address) { + if (_address == address(0)) revert("NOT_NULL_ERROR"); + _; + } + + modifier validRequirement(uint256 ownerCount, uint256 _required) { + if ( + ownerCount > MAX_OWNER_COUNT || + _required > ownerCount || + _required == 0 || + ownerCount == 0 + ) revert("VALID_REQUIREMENT_ERROR"); + _; + } + + /** @dev Fallback function allows to deposit ether. */ + fallback() external payable { + if (msg.value > 0) { + emit Deposit(msg.sender, msg.value); + } + } + + receive() external payable { + if (msg.value > 0) { + emit Deposit(msg.sender, msg.value); + } + } + + /** @dev Contract constructor sets initial owners and required number of confirmations. + * @param _owners List of initial owners. + * @param _required Number of required confirmations. + */ + constructor(address[] memory _owners, uint256 _required) + public + validRequirement(_owners.length, _required) + { + for (uint256 i = 0; i < _owners.length; i++) { + if (isOwner[_owners[i]] || _owners[i] == address(0)) { + revert("OWNER_ERROR"); + } + + isOwner[_owners[i]] = true; + } + + owners = _owners; + required = _required; + } + + /** @dev Allows to add a new owner. Transaction has to be sent by wallet. + * @param owner Address of new owner. + */ + function addOwner(address owner) + external + onlyWallet + ownerDoesNotExist(owner) + notNull(owner) + validRequirement(owners.length + 1, required) + { + isOwner[owner] = true; + owners.push(owner); + emit OwnerAddition(owner); + } + + /** @dev Allows to remove an owner. Transaction has to be sent by wallet. + * @param owner Address of owner. + */ + function removeOwner(address owner) external onlyWallet ownerExists(owner) { + isOwner[owner] = false; + for (uint256 i = 0; i < owners.length - 1; i++) { + if (owners[i] == owner) { + owners[i] = owners[owners.length - 1]; + break; + } + } + + owners.pop; + + if (required > owners.length) { + changeRequirement(owners.length); + } + + emit OwnerRemoval(owner); + } + + /** @dev Allows to replace an owner with a new owner. Transaction has to be sent by wallet. + * @param owner Address of owner to be replaced. + * @param owner Address of new owner. + */ + function replaceOwner(address owner, address newOwner) + external + onlyWallet + ownerExists(owner) + ownerDoesNotExist(newOwner) + { + for (uint256 i = 0; i < owners.length; i++) { + if (owners[i] == owner) { + owners[i] = newOwner; + break; + } + } + + isOwner[owner] = false; + isOwner[newOwner] = true; + emit OwnerRemoval(owner); + emit OwnerAddition(newOwner); + } + + /** @dev Allows to change the number of required confirmations. Transaction has to be sent by wallet. + * @param _required Number of required confirmations. + */ + function changeRequirement(uint256 _required) + public + onlyWallet + validRequirement(owners.length, _required) + { + required = _required; + emit RequirementChange(_required); + } + + /** @dev Changes the duration of the time lock for transactions. + * @param _lockSeconds Duration needed after a transaction is confirmed and before it becomes executable, in seconds. + */ + function changeLockSeconds(uint256 _lockSeconds) external onlyWallet { + lockSeconds = _lockSeconds; + emit LockSecondsChange(_lockSeconds); + } + + /** @dev Allows an owner to submit and confirm a transaction. + * @param destination Transaction target address. + * @param value Transaction ether value. + * @param data Transaction data payload. + * @return transactionId Returns transaction ID. + */ + function submitTransaction( + address destination, + uint256 value, + bytes calldata data + ) external ownerExists(msg.sender) notNull(destination) returns (uint256 transactionId) { + transactionId = transactionCount; + transactions[transactionId] = Transaction({ + destination: destination, + value: value, + data: data, + executed: false + }); + transactionCount += 1; + emit Submission(transactionId); + confirmTransaction(transactionId); + } + + /** @dev Allows an owner to confirm a transaction. + * @param transactionId Transaction ID. + */ + function confirmTransaction(uint256 transactionId) + public + ownerExists(msg.sender) + transactionExists(transactionId) + notConfirmed(transactionId, msg.sender) + { + confirmations[transactionId][msg.sender] = true; + emit Confirmation(msg.sender, transactionId); + + if (isConfirmed(transactionId) && unlockTimes[transactionId] == 0) { + uint256 unlockTime = block.timestamp + lockSeconds; + unlockTimes[transactionId] = unlockTime; + emit UnlockTimeSet(transactionId, unlockTime); + } + } + + /** @dev Allows an owner to revoke a confirmation for a transaction. + * @param transactionId Transaction ID. + */ + function revokeConfirmation(uint256 transactionId) + external + ownerExists(msg.sender) + confirmed(transactionId, msg.sender) + notExecuted(transactionId) + { + confirmations[transactionId][msg.sender] = false; + emit Revocation(msg.sender, transactionId); + } + + /** @dev Allows anyone to execute a confirmed transaction. + * @param transactionId Transaction ID. + */ + function executeTransaction(uint256 transactionId) + external + ownerExists(msg.sender) + notExecuted(transactionId) + { + require(block.timestamp >= unlockTimes[transactionId], "TRANSACTION_NEED_TO_UNLOCK"); + + if (isConfirmed(transactionId)) { + Transaction storage transaction = transactions[transactionId]; + transaction.executed = true; + (bool success, ) = transaction.destination.call{value: transaction.value}( + transaction.data + ); + if (success) emit Execution(transactionId); + else { + emit ExecutionFailure(transactionId); + transaction.executed = false; + } + } + } + + /** @dev Returns the confirmation status of a transaction. + * @param transactionId Transaction ID. + * @return Confirmation status. + */ + function isConfirmed(uint256 transactionId) public view returns (bool) { + uint256 count = 0; + + for (uint256 i = 0; i < owners.length; i++) { + if (confirmations[transactionId][owners[i]]) { + count += 1; + } + + if (count >= required) { + return true; + } + } + + return false; + } + + /* Web3 call functions */ + + /** @dev Returns number of confirmations of a transaction. + * @param transactionId Transaction ID. + * @return count Number of confirmations. + */ + function getConfirmationCount(uint256 transactionId) external view returns (uint256 count) { + for (uint256 i = 0; i < owners.length; i++) { + if (confirmations[transactionId][owners[i]]) { + count += 1; + } + } + } + + /** @dev Returns total number of transactions after filers are applied. + * @param pending Include pending transactions. + * @param executed Include executed transactions. + * @return count Total number of transactions after filters are applied. + */ + function getTransactionCount(bool pending, bool executed) + external + view + returns (uint256 count) + { + for (uint256 i = 0; i < transactionCount; i++) { + if ((pending && !transactions[i].executed) || (executed && transactions[i].executed)) { + count += 1; + } + } + } + + /** @dev Returns list of owners. + * @return List of owner addresses. + */ + function getOwners() external view returns (address[] memory) { + return owners; + } + + /** @dev Returns array with owner addresses, which confirmed transaction. + * @param transactionId Transaction ID. + * @return _confirmations Returns array of owner addresses. + */ + function getConfirmations(uint256 transactionId) + external + view + returns (address[] memory _confirmations) + { + address[] memory confirmationsTemp = new address[](owners.length); + uint256 count = 0; + uint256 i; + + for (i = 0; i < owners.length; i++) { + if (confirmations[transactionId][owners[i]]) { + confirmationsTemp[count] = owners[i]; + count += 1; + } + } + + _confirmations = new address[](count); + + for (i = 0; i < count; i++) { + _confirmations[i] = confirmationsTemp[i]; + } + } +} From 8450f84f33b6cbc4c0af9b50160691a439a31c64 Mon Sep 17 00:00:00 2001 From: mingda Date: Thu, 30 Jul 2020 13:57:38 +0800 Subject: [PATCH 055/118] get dodos --- contracts/DODOZoo.sol | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/contracts/DODOZoo.sol b/contracts/DODOZoo.sol index 08aed7e..882a30f 100644 --- a/contracts/DODOZoo.sol +++ b/contracts/DODOZoo.sol @@ -70,7 +70,7 @@ contract DODOZoo is Ownable { _DODOs.pop(); } - function addDODO(address dodo) external onlyOwner { + function addDODO(address dodo) public onlyOwner { address baseToken = IDODO(dodo)._BASE_TOKEN_(); address quoteToken = IDODO(dodo)._QUOTE_TOKEN_(); require(!isDODORegistered(baseToken, quoteToken), "DODO_REGISTERED"); @@ -104,8 +104,7 @@ contract DODOZoo is Ownable { k, gasPriceLimit ); - _DODO_REGISTER_[baseToken][quoteToken] = newBornDODO; - _DODOs.push(newBornDODO); + addDODO(newBornDODO); emit DODOBirth(newBornDODO, baseToken, quoteToken); return newBornDODO; } @@ -126,4 +125,8 @@ contract DODOZoo is Ownable { function getDODO(address baseToken, address quoteToken) external view returns (address) { return _DODO_REGISTER_[baseToken][quoteToken]; } + + function getDODOs() external view returns (address[] memory) { + return _DODOs; + } } From 50810bd4918fb87490b216d6bc4c3e3ff3571921 Mon Sep 17 00:00:00 2001 From: mingda Date: Thu, 30 Jul 2020 13:58:20 +0800 Subject: [PATCH 056/118] add prevent retrance to donate --- contracts/impl/Settlement.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/impl/Settlement.sol b/contracts/impl/Settlement.sol index d11eb29..bb133d1 100644 --- a/contracts/impl/Settlement.sol +++ b/contracts/impl/Settlement.sol @@ -65,12 +65,12 @@ contract Settlement is Storage { emit Donate(amount, false); } - function donateBaseToken(uint256 amount) external { + function donateBaseToken(uint256 amount) external preventReentrant { _baseTokenTransferIn(msg.sender, amount); _donateBaseToken(amount); } - function donateQuoteToken(uint256 amount) external { + function donateQuoteToken(uint256 amount) external preventReentrant { _quoteTokenTransferIn(msg.sender, amount); _donateQuoteToken(amount); } From 8def1e68a18fb6d48c5f1667dec531372a6432f8 Mon Sep 17 00:00:00 2001 From: mingda Date: Thu, 30 Jul 2020 13:58:43 +0800 Subject: [PATCH 057/118] uniswap arbitrageur constructor --- contracts/helper/UniswapArbitrageur.sol | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/contracts/helper/UniswapArbitrageur.sol b/contracts/helper/UniswapArbitrageur.sol index 35460a9..b956084 100644 --- a/contracts/helper/UniswapArbitrageur.sol +++ b/contracts/helper/UniswapArbitrageur.sol @@ -5,15 +5,15 @@ */ +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + import {Ownable} from "../lib/Ownable.sol"; import {IDODO} from "../intf/IDODO.sol"; import {IERC20} from "../intf/IERC20.sol"; import {SafeERC20} from "../lib/SafeERC20.sol"; import {SafeMath} from "../lib/SafeMath.sol"; -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - interface IUniswapV2Pair { function token0() external view returns (address); @@ -40,8 +40,6 @@ contract UniswapArbitrageur { using SafeMath for uint256; using SafeERC20 for IERC20; - bool public _INITIALIZED_; - address public _UNISWAP_; address public _DODO_; address public _BASE_; @@ -51,9 +49,7 @@ contract UniswapArbitrageur { uint256 public lastArbitrageProfit; - function init(address _uniswap, address _dodo) external { - require(!_INITIALIZED_, "ALREADY_INITIALIZED"); - _INITIALIZED_ = true; + constructor(address _uniswap, address _dodo) public { _UNISWAP_ = _uniswap; _DODO_ = _dodo; @@ -70,6 +66,9 @@ contract UniswapArbitrageur { } else { require(true, "DODO_UNISWAP_NOT_MATCH"); } + + IERC20(_BASE_).approve(_DODO_, uint256(-1)); + IERC20(_QUOTE_).approve(_DODO_, uint256(-1)); } function executeBuyArbitrage(uint256 baseAmount) external returns (uint256 quoteProfit) { @@ -169,8 +168,4 @@ contract UniswapArbitrageur { function retrieve(address token, uint256 amount) external { IERC20(token).safeTransfer(msg.sender, amount); } - - function approve(address token, address spender) external { - IERC20(token).approve(spender, uint256(-1)); - } } From 2a9ae441f848cf06da8c776ccede8b9f9466b41c Mon Sep 17 00:00:00 2001 From: mingda Date: Thu, 30 Jul 2020 16:13:30 +0800 Subject: [PATCH 058/118] move IDODOZoo to DODOEthProxy --- contracts/DODOEthProxy.sol | 5 ++++- contracts/intf/IDODOZoo.sol | 14 -------------- 2 files changed, 4 insertions(+), 15 deletions(-) delete mode 100644 contracts/intf/IDODOZoo.sol diff --git a/contracts/DODOEthProxy.sol b/contracts/DODOEthProxy.sol index 53e25dd..cbabd87 100644 --- a/contracts/DODOEthProxy.sol +++ b/contracts/DODOEthProxy.sol @@ -11,10 +11,13 @@ pragma experimental ABIEncoderV2; import {ReentrancyGuard} from "./lib/ReentrancyGuard.sol"; import {SafeERC20} from "./lib/SafeERC20.sol"; import {IDODO} from "./intf/IDODO.sol"; -import {IDODOZoo} from "./intf/IDODOZoo.sol"; import {IERC20} from "./intf/IERC20.sol"; import {IWETH} from "./intf/IWETH.sol"; +interface IDODOZoo { + function getDODO(address baseToken, address quoteToken) external view returns (address); +} + /** * @title DODO Eth Proxy * @author DODO Breeder diff --git a/contracts/intf/IDODOZoo.sol b/contracts/intf/IDODOZoo.sol deleted file mode 100644 index 1abedf9..0000000 --- a/contracts/intf/IDODOZoo.sol +++ /dev/null @@ -1,14 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - - -interface IDODOZoo { - function getDODO(address baseToken, address quoteToken) external view returns (address); -} From 8e01ec391f87e2a78a50fc8daa4c5c55d61540d3 Mon Sep 17 00:00:00 2001 From: mingda Date: Sat, 1 Aug 2020 16:08:27 +0800 Subject: [PATCH 059/118] fix test --- migrations/2_deploy.js | 10 +-- test/Admin.test.ts | 10 +-- test/Attacks.test.ts | 16 ++--- test/DODOEthProxy.test.ts | 1 - test/DODOZoo.test.ts | 28 +++++--- test/LiquidityProvider.test.ts | 50 ++++++------- test/LongTailTokenlMode.test.ts | 14 ++-- test/StableCoinMode.test.ts | 14 ++-- test/Trader.test.ts | 62 ++++++++--------- test/UniswapArbitrageur.test.ts | 120 ++++++++++++++++++++++++++++++++ test/utils/Context.ts | 9 +-- test/utils/Contracts.ts | 68 ++++++------------ 12 files changed, 251 insertions(+), 151 deletions(-) create mode 100644 test/UniswapArbitrageur.test.ts diff --git a/migrations/2_deploy.js b/migrations/2_deploy.js index 39dc335..434e5b6 100644 --- a/migrations/2_deploy.js +++ b/migrations/2_deploy.js @@ -1,11 +1,3 @@ const DODOZoo = artifacts.require("DODOZoo"); -module.exports = async (deployer, network) => { - const deployDODOZoo = async () => { - await deployer.deploy(DODOZoo); - }; - - if (network == "development") { - await deployDODOZoo(); - } -}; +module.exports = async (deployer, network) => {}; diff --git a/test/Admin.test.ts b/test/Admin.test.ts index d9c60a5..0375223 100644 --- a/test/Admin.test.ts +++ b/test/Admin.test.ts @@ -108,12 +108,12 @@ describe("Admin", () => { await ctx.DODO.methods.disableTrading().send(ctx.sendParam(ctx.Supervisor)) await assert.rejects( - ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("200")).send(ctx.sendParam(trader)), + ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("200"), "0x").send(ctx.sendParam(trader)), /TRADE_NOT_ALLOWED/ ) await ctx.DODO.methods.enableTrading().send(ctx.sendParam(ctx.Deployer)) - await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("200")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("200"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("101")) }) @@ -194,7 +194,7 @@ describe("Admin", () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x").send(ctx.sendParam(trader)) await ctx.DODO.methods.finalSettlement().send(ctx.sendParam(ctx.Deployer)) assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0") @@ -211,7 +211,7 @@ describe("Admin", () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("100")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("100"), "0x").send(ctx.sendParam(trader)) await ctx.DODO.methods.finalSettlement().send(ctx.sendParam(ctx.Deployer)) assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0") @@ -232,7 +232,7 @@ describe("Admin", () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) await ctx.DODO.methods.depositQuote(decimalStr("500")).send(ctx.sendParam(lp2)) - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x").send(ctx.sendParam(trader)) await ctx.DODO.methods.finalSettlement().send(ctx.sendParam(ctx.Deployer)) await assert.rejects( ctx.DODO.methods.finalSettlement().send(ctx.sendParam(ctx.Deployer)), diff --git a/test/Attacks.test.ts b/test/Attacks.test.ts index 288f34b..21552bb 100644 --- a/test/Attacks.test.ts +++ b/test/Attacks.test.ts @@ -71,15 +71,15 @@ describe("Attacks", () => { // attack step 1 await ctx.DODO.methods.depositBase(decimalStr("5000")).send(ctx.sendParam(hacker)) // attack step 2 - await ctx.DODO.methods.buyBaseToken(decimalStr("9.5"), decimalStr("2000")).send(ctx.sendParam(hacker)) + await ctx.DODO.methods.buyBaseToken(decimalStr("9.5"), decimalStr("2000"), "0x").send(ctx.sendParam(hacker)) // attack step 3 await ctx.DODO.methods.withdrawBase(decimalStr("5000")).send(ctx.sendParam(hacker)) // attack step 4 let hackerTempBaseBalance = new BigNumber(await ctx.BASE.methods.balanceOf(hacker).call()) if (hackerTempBaseBalance.isGreaterThan(hackerInitBaseBalance)) { - await ctx.DODO.methods.sellBaseToken(hackerTempBaseBalance.minus(hackerInitBaseBalance).toString(), "0").send(ctx.sendParam(hacker)) + await ctx.DODO.methods.sellBaseToken(hackerTempBaseBalance.minus(hackerInitBaseBalance).toString(), "0", "0x").send(ctx.sendParam(hacker)) } else { - await ctx.DODO.methods.buyBaseToken(hackerInitBaseBalance.minus(hackerTempBaseBalance).toString(), decimalStr("5000")).send(ctx.sendParam(hacker)) + await ctx.DODO.methods.buyBaseToken(hackerInitBaseBalance.minus(hackerTempBaseBalance).toString(), decimalStr("5000"), "0x").send(ctx.sendParam(hacker)) } // expected hacker no profit @@ -106,15 +106,15 @@ describe("Attacks", () => { // attack step 1 await ctx.DODO.methods.depositQuote(decimalStr("100000")).send(ctx.sendParam(hacker)) // attack step 2 - await ctx.DODO.methods.sellBaseToken(decimalStr("9"), decimalStr("500")).send(ctx.sendParam(hacker)) + await ctx.DODO.methods.sellBaseToken(decimalStr("9"), decimalStr("500"), "0x").send(ctx.sendParam(hacker)) // attack step 3 await ctx.DODO.methods.withdrawQuote(decimalStr("100000")).send(ctx.sendParam(hacker)) // attack step 4 let hackerTempBaseBalance = new BigNumber(await ctx.BASE.methods.balanceOf(hacker).call()) if (hackerTempBaseBalance.isGreaterThan(hackerInitBaseBalance)) { - await ctx.DODO.methods.sellBaseToken(hackerTempBaseBalance.minus(hackerInitBaseBalance).toString(), "0").send(ctx.sendParam(hacker)) + await ctx.DODO.methods.sellBaseToken(hackerTempBaseBalance.minus(hackerInitBaseBalance).toString(), "0", "0x").send(ctx.sendParam(hacker)) } else { - await ctx.DODO.methods.buyBaseToken(hackerInitBaseBalance.minus(hackerTempBaseBalance).toString(), decimalStr("5000")).send(ctx.sendParam(hacker)) + await ctx.DODO.methods.buyBaseToken(hackerInitBaseBalance.minus(hackerTempBaseBalance).toString(), decimalStr("5000"), "0x").send(ctx.sendParam(hacker)) } // expected hacker no profit @@ -145,10 +145,10 @@ describe("Attacks", () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) await assert.rejects( - ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("200")).send({ from: trader, gas: 300000, gasPrice: gweiStr("200") }), /GAS_PRICE_EXCEED/ + ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("200"), "0x").send({ from: trader, gas: 300000, gasPrice: gweiStr("200") }), /GAS_PRICE_EXCEED/ ) await assert.rejects( - ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("200")).send({ from: trader, gas: 300000, gasPrice: gweiStr("200") }), /GAS_PRICE_EXCEED/ + ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("200"), "0x").send({ from: trader, gas: 300000, gasPrice: gweiStr("200") }), /GAS_PRICE_EXCEED/ ) }) diff --git a/test/DODOEthProxy.test.ts b/test/DODOEthProxy.test.ts index 8be69d2..2bd6302 100644 --- a/test/DODOEthProxy.test.ts +++ b/test/DODOEthProxy.test.ts @@ -20,7 +20,6 @@ async function init(ctx: DODOContext): Promise { // switch ctx to eth proxy mode let WETH = await contracts.newContract(contracts.WETH_CONTRACT_NAME) await ctx.DODOZoo.methods.breedDODO( - ctx.Supervisor, ctx.Maintainer, WETH.options.address, ctx.QUOTE.options.address, diff --git a/test/DODOZoo.test.ts b/test/DODOZoo.test.ts index 9ebf82f..d275a5a 100644 --- a/test/DODOZoo.test.ts +++ b/test/DODOZoo.test.ts @@ -33,12 +33,12 @@ describe("DODO ZOO", () => { describe("Breed new dodo", () => { it("could not deploy the same dodo", async () => { await assert.rejects( - ctx.DODOZoo.methods.breedDODO(ctx.Supervisor, ctx.Maintainer, ctx.BASE.options.address, ctx.QUOTE.options.address, ctx.ORACLE.options.address, "0", "0", "1", "0").send(ctx.sendParam(ctx.Deployer)), + ctx.DODOZoo.methods.breedDODO(ctx.Maintainer, ctx.BASE.options.address, ctx.QUOTE.options.address, ctx.ORACLE.options.address, "0", "0", "1", "0").send(ctx.sendParam(ctx.Deployer)), /DODO_REGISTERED/ ) await assert.rejects( - ctx.DODOZoo.methods.breedDODO(ctx.Supervisor, ctx.Maintainer, ctx.QUOTE.options.address, ctx.BASE.options.address, ctx.ORACLE.options.address, "0", "0", "1", "0").send(ctx.sendParam(ctx.Deployer)), + ctx.DODOZoo.methods.breedDODO(ctx.Maintainer, ctx.QUOTE.options.address, ctx.BASE.options.address, ctx.ORACLE.options.address, "0", "0", "1", "0").send(ctx.sendParam(ctx.Deployer)), /DODO_REGISTERED/ ) }) @@ -47,27 +47,37 @@ describe("DODO ZOO", () => { let newBase = await newContract(TEST_ERC20_CONTRACT_NAME, ["AnotherBase", 18]) let newQuote = await newContract(TEST_ERC20_CONTRACT_NAME, ["AnotherQuote", 18]) await assert.rejects( - ctx.DODOZoo.methods.breedDODO(ctx.Supervisor, ctx.Maintainer, newBase.options.address, newQuote.options.address, ctx.ORACLE.options.address, "0", "0", "1", "0").send(ctx.sendParam(ctx.Maintainer)), + ctx.DODOZoo.methods.breedDODO(ctx.Maintainer, newBase.options.address, newQuote.options.address, ctx.ORACLE.options.address, "0", "0", "1", "0").send(ctx.sendParam(ctx.Maintainer)), /NOT_OWNER/ ) - await ctx.DODOZoo.methods.breedDODO(ctx.Supervisor, ctx.Maintainer, newBase.options.address, newQuote.options.address, ctx.ORACLE.options.address, "0", "0", "1", "0").send(ctx.sendParam(ctx.Deployer)) + await ctx.DODOZoo.methods.breedDODO(ctx.Maintainer, newBase.options.address, newQuote.options.address, ctx.ORACLE.options.address, "0", "0", "1", "0").send(ctx.sendParam(ctx.Deployer)) let newDODO = getContractWithAddress(DODO_CONTRACT_NAME, await ctx.DODOZoo.methods.getDODO(newBase.options.address, newQuote.options.address).call()) assert.equal(await newDODO.methods._BASE_TOKEN_().call(), newBase.options.address) assert.equal(await newDODO.methods._QUOTE_TOKEN_().call(), newQuote.options.address) - await newDODO.methods.claimOwnership().send(ctx.sendParam(ctx.Deployer)) - // could not init twice await assert.rejects( - newDODO.methods.init(ctx.Supervisor, ctx.Maintainer, ctx.QUOTE.options.address, ctx.BASE.options.address, ctx.ORACLE.options.address, "0", "0", "1", "0").send(ctx.sendParam(ctx.Deployer)), + newDODO.methods.init(ctx.Deployer, ctx.Supervisor, ctx.Maintainer, ctx.QUOTE.options.address, ctx.BASE.options.address, ctx.ORACLE.options.address, "0", "0", "1", "0").send(ctx.sendParam(ctx.Deployer)), /DODO_INITIALIZED/ ) + + // console.log(await ctx.DODOZoo.methods.getDODOs().call()) }) - it("remove dodo", async () => { - await ctx.DODOZoo.methods.removeDODO(ctx.BASE.options.address, ctx.QUOTE.options.address).send(ctx.sendParam(ctx.Deployer)) + it("dodo register control flow", async () => { + await ctx.DODOZoo.methods.removeDODO(ctx.DODO.options.address).send(ctx.sendParam(ctx.Deployer)) assert.equal(await ctx.DODOZoo.methods.getDODO(ctx.BASE.options.address, ctx.QUOTE.options.address).call(), "0x0000000000000000000000000000000000000000") + await assert.rejects( + ctx.DODOZoo.methods.removeDODO(ctx.DODO.options.address).send(ctx.sendParam(ctx.Deployer)), + /DODO_NOT_REGISTERED/ + ) + await ctx.DODOZoo.methods.addDODO(ctx.DODO.options.address).send(ctx.sendParam(ctx.Deployer)) + assert.equal(await ctx.DODOZoo.methods.getDODO(ctx.BASE.options.address, ctx.QUOTE.options.address).call(), ctx.DODO.options.address) + await assert.rejects( + ctx.DODOZoo.methods.addDODO(ctx.DODO.options.address).send(ctx.sendParam(ctx.Deployer)), + /DODO_REGISTERED/ + ) }) }) diff --git a/test/LiquidityProvider.test.ts b/test/LiquidityProvider.test.ts index 6a86353..fb149e2 100644 --- a/test/LiquidityProvider.test.ts +++ b/test/LiquidityProvider.test.ts @@ -90,7 +90,7 @@ describe("LiquidityProvider", () => { it("deposit", async () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "10010841132009222923") assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), decimalStr("1000")) @@ -113,7 +113,7 @@ describe("LiquidityProvider", () => { it("withdraw", async () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.DODO.methods.getWithdrawBasePenalty(decimalStr("4")).call(), "1065045389392391665") assert.equal(await ctx.DODO.methods.getWithdrawQuotePenalty(decimalStr("100")).call(), "0") @@ -134,7 +134,7 @@ describe("LiquidityProvider", () => { it("deposit", async () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("200")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("200"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), decimalStr("10")) assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), "1000978629616255276996") @@ -155,7 +155,7 @@ describe("LiquidityProvider", () => { it("withdraw", async () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("200")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("200"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.DODO.methods.getWithdrawBasePenalty(decimalStr("4")).call(), "0") assert.equal(await ctx.DODO.methods.getWithdrawQuotePenalty(decimalStr("100")).call(), "7389428846238900753") @@ -176,7 +176,7 @@ describe("LiquidityProvider", () => { it("base side lp don't has pnl when R is BELOW ONE", async () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("200")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("200"), "0x").send(ctx.sendParam(trader)) await ctx.setOraclePrice(decimalStr("80")); @@ -192,7 +192,7 @@ describe("LiquidityProvider", () => { it("quote side lp don't has pnl when R is ABOVE ONE", async () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("600")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("600"), "0x").send(ctx.sendParam(trader)) await ctx.setOraclePrice(decimalStr("80")); @@ -250,8 +250,8 @@ describe("LiquidityProvider", () => { describe("Corner cases", () => { it("single side deposit", async () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000")).send(ctx.sendParam(trader)) - await ctx.DODO.methods.sellBaseToken("5015841132009222923", decimalStr("0")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x").send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken("5015841132009222923", decimalStr("0"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0") assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "10010841132009222923") @@ -264,7 +264,7 @@ describe("LiquidityProvider", () => { it("single side deposit & lp deposit when R isn't equal to ONE", async () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x").send(ctx.sendParam(trader)) await ctx.DODO.methods.depositQuote("1").send(ctx.sendParam(lp2)) @@ -274,11 +274,11 @@ describe("LiquidityProvider", () => { it("single side deposit (base) & oracle change introduces loss", async () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x").send(ctx.sendParam(trader)) await ctx.setOraclePrice(decimalStr("120")) - await ctx.DODO.methods.sellBaseToken(decimalStr("4"), decimalStr("0")).send(ctx.sendParam(trader)) - await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("0")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("4"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "2") assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "9234731968726215603") @@ -292,11 +292,11 @@ describe("LiquidityProvider", () => { it("single side deposit (base) & oracle change introduces profit", async () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x").send(ctx.sendParam(trader)) await ctx.setOraclePrice(decimalStr("80")) - await ctx.DODO.methods.sellBaseToken(decimalStr("4"), decimalStr("0")).send(ctx.sendParam(trader)) - await ctx.DODO.methods.sellBaseToken(decimalStr("4"), decimalStr("0")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("4"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("4"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "2") assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "11138732839027528584") @@ -310,11 +310,11 @@ describe("LiquidityProvider", () => { it("single side deposit (quote) & oracle change introduces loss", async () => { await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("0")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) await ctx.setOraclePrice(decimalStr("80")) - await ctx.DODO.methods.buyBaseToken(decimalStr("4"), decimalStr("600")).send(ctx.sendParam(trader)) - await ctx.DODO.methods.buyBaseToken(decimalStr("0.99"), decimalStr("500")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("4"), decimalStr("600"), "0x").send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("0.99"), decimalStr("500"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "1") assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "9980000000000000") @@ -328,7 +328,7 @@ describe("LiquidityProvider", () => { it("deposit and withdraw immediately", async () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "10010841132009222923") @@ -347,7 +347,7 @@ describe("LiquidityProvider", () => { describe("Revert cases", () => { it("withdraw base amount exceeds DODO balance", async () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x").send(ctx.sendParam(trader)) await assert.rejects( ctx.DODO.methods.withdrawBase(decimalStr("6")).send(ctx.sendParam(lp1)), @@ -362,7 +362,7 @@ describe("LiquidityProvider", () => { it("withdraw quote amount exceeds DODO balance", async () => { await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("0")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) await assert.rejects( ctx.DODO.methods.withdrawQuote(decimalStr("600")).send(ctx.sendParam(lp1)), @@ -377,7 +377,7 @@ describe("LiquidityProvider", () => { it("withdraw base could not afford penalty", async () => { await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("9"), decimalStr("10000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("9"), decimalStr("10000"), "0x").send(ctx.sendParam(trader)) await assert.rejects( ctx.DODO.methods.withdrawBase(decimalStr("0.5")).send(ctx.sendParam(lp1)), @@ -392,7 +392,7 @@ describe("LiquidityProvider", () => { it("withdraw quote could not afford penalty", async () => { await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.sellBaseToken(decimalStr("10"), decimalStr("0")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("10"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) await assert.rejects( ctx.DODO.methods.withdrawQuote(decimalStr("200")).send(ctx.sendParam(lp1)), @@ -408,7 +408,7 @@ describe("LiquidityProvider", () => { it("withdraw all base could not afford penalty", async () => { await ctx.DODO.methods.depositBase(decimalStr("9.5")).send(ctx.sendParam(lp1)) await ctx.DODO.methods.depositBase(decimalStr("0.5")).send(ctx.sendParam(lp2)) - await ctx.DODO.methods.buyBaseToken(decimalStr("9"), decimalStr("10000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("9"), decimalStr("10000"), "0x").send(ctx.sendParam(trader)) await assert.rejects( ctx.DODO.methods.withdrawBase(decimalStr("0.5")).send(ctx.sendParam(lp2)), @@ -419,7 +419,7 @@ describe("LiquidityProvider", () => { it("withdraw all quote could not afford penalty", async () => { await ctx.DODO.methods.depositQuote(decimalStr("800")).send(ctx.sendParam(lp1)) await ctx.DODO.methods.depositQuote(decimalStr("200")).send(ctx.sendParam(lp2)) - await ctx.DODO.methods.sellBaseToken(decimalStr("10"), decimalStr("0")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("10"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) await assert.rejects( ctx.DODO.methods.withdrawQuote(decimalStr("200")).send(ctx.sendParam(lp2)), diff --git a/test/LongTailTokenlMode.test.ts b/test/LongTailTokenlMode.test.ts index cc2d19d..152b6dc 100644 --- a/test/LongTailTokenlMode.test.ts +++ b/test/LongTailTokenlMode.test.ts @@ -55,36 +55,36 @@ describe("Trader", () => { it("price discover", async () => { // 10% depth // avg price = 11.137 - await ctx.DODO.methods.buyBaseToken(decimalStr("1000"), decimalStr("100000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("1000"), decimalStr("100000"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("1000")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "9988900000000000000000000") // 20% depth // avg price = 12.475 - await ctx.DODO.methods.buyBaseToken(decimalStr("1000"), decimalStr("100000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("1000"), decimalStr("100000"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("2000")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "9975049999999999999970000") // 50% depth // avg price = 19.9 - await ctx.DODO.methods.buyBaseToken(decimalStr("3000"), decimalStr("300000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("3000"), decimalStr("300000"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("5000")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "9900499999999999999970000") // 80% depth // avg price = 49.6 - await ctx.DODO.methods.buyBaseToken(decimalStr("3000"), decimalStr("300000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("3000"), decimalStr("300000"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("8000")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "9603199999999999999970000") }) it("user has no pnl if buy and sell immediately", async () => { // lp buy - await ctx.DODO.methods.buyBaseToken(decimalStr("1000"), decimalStr("100000")).send(ctx.sendParam(lp)) + await ctx.DODO.methods.buyBaseToken(decimalStr("1000"), decimalStr("100000"), "0x").send(ctx.sendParam(lp)) // trader buy and sell - await ctx.DODO.methods.buyBaseToken(decimalStr("1000"), decimalStr("100000")).send(ctx.sendParam(trader)) - await ctx.DODO.methods.sellBaseToken(decimalStr("1000"), decimalStr("0")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("1000"), decimalStr("100000"), "0x").send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("1000"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) // no profit or loss (may have precision problems) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), "0") diff --git a/test/StableCoinMode.test.ts b/test/StableCoinMode.test.ts index b85a8ab..2373ec7 100644 --- a/test/StableCoinMode.test.ts +++ b/test/StableCoinMode.test.ts @@ -54,17 +54,17 @@ describe("Trader", () => { describe("Trade stable coin", () => { it("trade with tiny slippage", async () => { // 10% depth avg price 1.000100000111135 - await ctx.DODO.methods.buyBaseToken(decimalStr("1000"), decimalStr("1001")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("1000"), decimalStr("1001"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("11000")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "8999899999888865431655") // 99.9% depth avg price 1.00010109 - await ctx.DODO.methods.buyBaseToken(decimalStr("8990"), decimalStr("10000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("8990"), decimalStr("10000"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("19990")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "8990031967806921648") // sell to 99.9% depth avg price 0.9999 - await ctx.DODO.methods.sellBaseToken(decimalStr("19980"), decimalStr("19970")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("19980"), decimalStr("19970"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("10")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "19986992950440794518402") }) @@ -73,7 +73,7 @@ describe("Trader", () => { // trader could sell any number of base token // but the price will drop quickly await ctx.mintTestToken(trader, decimalStr("10000"), decimalStr("0")) - await ctx.DODO.methods.sellBaseToken(decimalStr("20000"), decimalStr("0")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("20000"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("0")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "19998999990001000029997") @@ -82,19 +82,19 @@ describe("Trader", () => { it("huge buy trading amount", async () => { // could not buy all base balance await assert.rejects( - ctx.DODO.methods.buyBaseToken(decimalStr("10000"), decimalStr("10010")).send(ctx.sendParam(trader)), + ctx.DODO.methods.buyBaseToken(decimalStr("10000"), decimalStr("10010"), "0x").send(ctx.sendParam(trader)), /DODO_BASE_BALANCE_NOT_ENOUGH/ ) // when buy amount close to base balance, price will increase quickly await ctx.mintTestToken(trader, decimalStr("0"), decimalStr("10000")) - await ctx.DODO.methods.buyBaseToken(decimalStr("9999"), decimalStr("20000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("9999"), decimalStr("20000"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("19999")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "9000000119999999900000") }) it("tiny withdraw penalty", async () => { - await ctx.DODO.methods.buyBaseToken(decimalStr("9990"), decimalStr("10000")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("9990"), decimalStr("10000"), "0x").send(ctx.sendParam(trader)) // penalty only 0.2% even if withdraw make pool utilization rate raise to 99.5% assert.equal(await ctx.DODO.methods.getWithdrawBasePenalty(decimalStr("5")).call(), "9981967500000000") diff --git a/test/Trader.test.ts b/test/Trader.test.ts index ae3b759..9046248 100644 --- a/test/Trader.test.ts +++ b/test/Trader.test.ts @@ -24,8 +24,8 @@ async function init(ctx: DODOContext): Promise { await ctx.mintTestToken(lp, decimalStr("10"), decimalStr("1000")) await ctx.mintTestToken(trader, decimalStr("10"), decimalStr("1000")) - await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp)) - await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp)) + await ctx.DODO.methods.depositBaseTo(lp, decimalStr("10")).send(ctx.sendParam(lp)) + await ctx.DODO.methods.depositQuoteTo(lp, decimalStr("1000")).send(ctx.sendParam(lp)) } describe("Trader", () => { @@ -48,7 +48,7 @@ describe("Trader", () => { describe("R goes above ONE", () => { it("buy when R equals ONE", async () => { - logGas(await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110")).send(ctx.sendParam(trader)), "buy base token when balanced") + logGas(await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110"), "0x").send(ctx.sendParam(trader)), "buy base token when balanced") // trader balances assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("11")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "898581839502056240973") @@ -63,8 +63,8 @@ describe("Trader", () => { }) it("buy when R is ABOVE ONE", async () => { - await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110")).send(ctx.sendParam(trader)) - logGas(await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("130")).send(ctx.sendParam(trader)), "buy when R is ABOVE ONE") + await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110"), "0x").send(ctx.sendParam(trader)) + logGas(await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("130"), "0x").send(ctx.sendParam(trader)), "buy when R is ABOVE ONE") // trader balances assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("12")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "794367183433412077653") @@ -77,8 +77,8 @@ describe("Trader", () => { }) it("sell when R is ABOVE ONE", async () => { - await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110")).send(ctx.sendParam(trader)) - logGas(await ctx.DODO.methods.sellBaseToken(decimalStr("0.5"), decimalStr("40")).send(ctx.sendParam(trader)), "sell when R is ABOVE ONE") + await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110"), "0x").send(ctx.sendParam(trader)) + logGas(await ctx.DODO.methods.sellBaseToken(decimalStr("0.5"), decimalStr("40"), "0x").send(ctx.sendParam(trader)), "sell when R is ABOVE ONE") // trader balances assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("10.5")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "949280846351657143136") @@ -91,8 +91,8 @@ describe("Trader", () => { }) it("sell when R is ABOVE ONE and RStatus back to ONE", async () => { - await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110")).send(ctx.sendParam(trader)) - logGas(await ctx.DODO.methods.sellBaseToken("1003002430889317763", decimalStr("90")).send(ctx.sendParam(trader)), "sell when R is ABOVE ONE and RStatus back to ONE") + await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110"), "0x").send(ctx.sendParam(trader)) + logGas(await ctx.DODO.methods.sellBaseToken("1003002430889317763", decimalStr("90"), "0x").send(ctx.sendParam(trader)), "sell when R is ABOVE ONE and RStatus back to ONE") // R status assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0") // trader balances @@ -110,8 +110,8 @@ describe("Trader", () => { }) it("sell when R is ABOVE ONE and RStatus becomes BELOW ONE", async () => { - await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110")).send(ctx.sendParam(trader)) - logGas(await ctx.DODO.methods.sellBaseToken(decimalStr("2"), decimalStr("90")).send(ctx.sendParam(trader)), "sell when R is ABOVE ONE and RStatus becomes BELOW ONE [gas cost worst case]") + await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110"), "0x").send(ctx.sendParam(trader)) + logGas(await ctx.DODO.methods.sellBaseToken(decimalStr("2"), decimalStr("90"), "0x").send(ctx.sendParam(trader)), "sell when R is ABOVE ONE and RStatus becomes BELOW ONE [gas cost worst case]") // R status assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "2") // trader balances @@ -131,7 +131,7 @@ describe("Trader", () => { describe("R goes below ONE", () => { it("sell when R equals ONE", async () => { - logGas(await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90")).send(ctx.sendParam(trader)), "sell base token when balanced") + logGas(await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90"), "0x").send(ctx.sendParam(trader)), "sell base token when balanced") // trader balances assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("9")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1098617454226610630663") @@ -146,8 +146,8 @@ describe("Trader", () => { }) it("sell when R is BELOW ONE", async () => { - await ctx.DODO.methods.sellBaseToken(decimalStr("3"), decimalStr("90")).send(ctx.sendParam(trader)) - logGas(await ctx.DODO.methods.sellBaseToken(decimalStr("3"), decimalStr("90")).send(ctx.sendParam(trader)), "sell when R is BELOW ONE") + await ctx.DODO.methods.sellBaseToken(decimalStr("3"), decimalStr("90"), "0x").send(ctx.sendParam(trader)) + logGas(await ctx.DODO.methods.sellBaseToken(decimalStr("3"), decimalStr("90"), "0x").send(ctx.sendParam(trader)), "sell when R is BELOW ONE") // trader balances assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("4")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1535961012052716726151") @@ -160,8 +160,8 @@ describe("Trader", () => { }) it("buy when R is BELOW ONE", async () => { - await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90")).send(ctx.sendParam(trader)) - logGas(await ctx.DODO.methods.buyBaseToken(decimalStr("0.5"), decimalStr("60")).send(ctx.sendParam(trader)), "buy when R is BELOW ONE") + await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90"), "0x").send(ctx.sendParam(trader)) + logGas(await ctx.DODO.methods.buyBaseToken(decimalStr("0.5"), decimalStr("60"), "0x").send(ctx.sendParam(trader)), "buy when R is BELOW ONE") // trader balances assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("9.5")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1049294316148665165453") @@ -174,8 +174,8 @@ describe("Trader", () => { }) it("buy when R is BELOW ONE and RStatus back to ONE", async () => { - await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90")).send(ctx.sendParam(trader)) - logGas(await ctx.DODO.methods.buyBaseToken("997008973080757728", decimalStr("110")).send(ctx.sendParam(trader)), "buy when R is BELOW ONE and RStatus back to ONE") + await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90"), "0x").send(ctx.sendParam(trader)) + logGas(await ctx.DODO.methods.buyBaseToken("997008973080757728", decimalStr("110"), "0x").send(ctx.sendParam(trader)), "buy when R is BELOW ONE and RStatus back to ONE") // R status assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0") // trader balances @@ -193,8 +193,8 @@ describe("Trader", () => { }) it("buy when R is BELOW ONE and RStatus becomes ABOVE ONE", async () => { - await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90")).send(ctx.sendParam(trader)) - logGas(await ctx.DODO.methods.buyBaseToken(decimalStr("2"), decimalStr("220")).send(ctx.sendParam(trader)), "buy when R is BELOW ONE and RStatus becomes ABOVE ONE [gas cost worst case]") + await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90"), "0x").send(ctx.sendParam(trader)) + logGas(await ctx.DODO.methods.buyBaseToken(decimalStr("2"), decimalStr("220"), "0x").send(ctx.sendParam(trader)), "buy when R is BELOW ONE and RStatus becomes ABOVE ONE [gas cost worst case]") // R status assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "1") // trader balances @@ -214,36 +214,36 @@ describe("Trader", () => { describe("Corner cases", () => { it("buy or sell 0", async () => { - await ctx.DODO.methods.sellBaseToken(decimalStr("0"), decimalStr("0")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("0"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("10")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), decimalStr("1000")) - await ctx.DODO.methods.buyBaseToken(decimalStr("0"), decimalStr("0")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("0"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("10")) assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), decimalStr("1000")) }) it("buy or sell a tiny amount", async () => { // no precision problem - await ctx.DODO.methods.sellBaseToken("1", decimalStr("0")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken("1", decimalStr("0"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), "9999999999999999999") assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1000000000000000000100") // have precision problem, charge 0 - await ctx.DODO.methods.buyBaseToken("1", decimalStr("1")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken("1", decimalStr("1"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), "10000000000000000000") assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1000000000000000000100") assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0") // no precision problem if trading amount is extremely small - await ctx.DODO.methods.buyBaseToken("10", decimalStr("1")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken("10", decimalStr("1"), "0x").send(ctx.sendParam(trader)) assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), "10000000000000000010") assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "999999999999999999100") }) it("sell a huge amount of base token", async () => { await ctx.mintTestToken(trader, decimalStr("10000"), "0") - await ctx.DODO.methods.sellBaseToken(decimalStr("10000"), "0").send(ctx.sendParam(trader)) + await ctx.DODO.methods.sellBaseToken(decimalStr("10000"), "0", "0x").send(ctx.sendParam(trader)) // nearly drain out quote pool // because the fee donated is greater than remaining quote pool // quote lp earn a considerable profit @@ -255,25 +255,25 @@ describe("Trader", () => { describe("Revert cases", () => { it("price limit", async () => { await assert.rejects( - ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("100")).send(ctx.sendParam(trader)), + ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("100"), "0x").send(ctx.sendParam(trader)), /BUY_BASE_COST_TOO_MUCH/ ) await assert.rejects( - ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("100")).send(ctx.sendParam(trader)), + ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("100"), "0x").send(ctx.sendParam(trader)), /SELL_BASE_RECEIVE_NOT_ENOUGH/ ) }) it("base balance limit", async () => { await assert.rejects( - ctx.DODO.methods.buyBaseToken(decimalStr("11"), decimalStr("10000")).send(ctx.sendParam(trader)), + ctx.DODO.methods.buyBaseToken(decimalStr("11"), decimalStr("10000"), "0x").send(ctx.sendParam(trader)), /DODO_BASE_BALANCE_NOT_ENOUGH/ ) - await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("200")).send(ctx.sendParam(trader)) + await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("200"), "0x").send(ctx.sendParam(trader)) await assert.rejects( - ctx.DODO.methods.buyBaseToken(decimalStr("11"), decimalStr("10000")).send(ctx.sendParam(trader)), + ctx.DODO.methods.buyBaseToken(decimalStr("11"), decimalStr("10000"), "0x").send(ctx.sendParam(trader)), /DODO_BASE_BALANCE_NOT_ENOUGH/ ) }) diff --git a/test/UniswapArbitrageur.test.ts b/test/UniswapArbitrageur.test.ts new file mode 100644 index 0000000..b7c53c8 --- /dev/null +++ b/test/UniswapArbitrageur.test.ts @@ -0,0 +1,120 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +import { DODOContext, getDODOContext } from './utils/Context'; +import { decimalStr } from './utils/Converter'; +import { logGas } from './utils/Log'; +import * as assert from "assert" +import { newContract, UNISWAP_CONTRACT_NAME, UNISWAP_ARBITRAGEUR_CONTRACT_NAME } from './utils/Contracts'; +import { Contract } from 'web3-eth-contract'; + +let lp: string +let keeper: string + +let Uniswap: Contract +let UniswapArbitrageur: Contract + +let UniswapReverse: Contract +let UniswapArbitrageurReverse: Contract + +async function init(ctx: DODOContext): Promise { + await ctx.setOraclePrice(decimalStr("100")) + + lp = ctx.spareAccounts[0] + keeper = ctx.spareAccounts[1] + await ctx.approveDODO(lp) + + await ctx.mintTestToken(lp, decimalStr("100"), decimalStr("10000")) + + await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp)) + await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp)) + + Uniswap = await newContract(UNISWAP_CONTRACT_NAME) + Uniswap.methods.initialize(ctx.BASE.options.address, ctx.QUOTE.options.address).send(ctx.sendParam(ctx.Deployer)) + ctx.BASE.methods.transfer(Uniswap.options.address, decimalStr("10")).send(ctx.sendParam(lp)) + ctx.QUOTE.methods.transfer(Uniswap.options.address, decimalStr("2000")).send(ctx.sendParam(lp)) + Uniswap.methods.sync().send(ctx.sendParam(lp)) + + UniswapArbitrageur = await newContract(UNISWAP_ARBITRAGEUR_CONTRACT_NAME, [Uniswap.options.address, ctx.DODO.options.address]) + + UniswapReverse = await newContract(UNISWAP_CONTRACT_NAME) + UniswapReverse.methods.initialize(ctx.BASE.options.address, ctx.QUOTE.options.address).send(ctx.sendParam(ctx.Deployer)) + ctx.BASE.methods.transfer(UniswapReverse.options.address, decimalStr("10")).send(ctx.sendParam(lp)) + ctx.QUOTE.methods.transfer(UniswapReverse.options.address, decimalStr("2000")).send(ctx.sendParam(lp)) + UniswapReverse.methods.sync().send(ctx.sendParam(lp)) + + UniswapArbitrageurReverse = await newContract(UNISWAP_ARBITRAGEUR_CONTRACT_NAME, [UniswapReverse.options.address, ctx.DODO.options.address]) +} + +describe("Uniswap Arbitrageur", () => { + + let snapshotId: string + let ctx: DODOContext + + before(async () => { + ctx = await getDODOContext() + await init(ctx); + }) + + beforeEach(async () => { + snapshotId = await ctx.EVM.snapshot(); + }); + + afterEach(async () => { + await ctx.EVM.reset(snapshotId) + }); + + describe("arbitrage with not reverse pair", () => { + it("buy at dodo", async () => { + await ctx.setOraclePrice(decimalStr("100")) + // dodo price 100 uniswap price 200 + // buy at dodo + logGas(await UniswapArbitrageur.methods.executeBuyArbitrage(decimalStr("1")).send(ctx.sendParam(keeper)), "arbitrage buy at dodo not reverse") + assert.equal(await ctx.QUOTE.methods.balanceOf(keeper).call(), "79836384956601695518") + }) + + it("sell at dodo", async () => { + await ctx.setOraclePrice(decimalStr("300")) + // dodo price 300 uniswap price 200 + // sell at dodo + logGas(await UniswapArbitrageur.methods.executeSellArbitrage(decimalStr("1")).send(ctx.sendParam(keeper)), "arbitrage sell at dodo not reverse") + assert.equal(await ctx.BASE.methods.balanceOf(keeper).call(), "252761069524143743") + }) + }) + + describe("arbitrage with reverse pair", () => { + it("buy at dodo", async () => { + await ctx.setOraclePrice(decimalStr("100")) + // dodo price 100 uniswap price 200 + // buy at dodo + logGas(await UniswapArbitrageurReverse.methods.executeBuyArbitrage(decimalStr("1")).send(ctx.sendParam(keeper)), "arbitrage buy at dodo reverse") + assert.equal(await ctx.QUOTE.methods.balanceOf(keeper).call(), "79836384956601695518") + }) + + it("sell at dodo", async () => { + await ctx.setOraclePrice(decimalStr("300")) + // dodo price 300 uniswap price 200 + // sell at dodo + logGas(await UniswapArbitrageurReverse.methods.executeSellArbitrage(decimalStr("1")).send(ctx.sendParam(keeper)), "arbitrage sell at dodo reverse") + assert.equal(await ctx.BASE.methods.balanceOf(keeper).call(), "252761069524143743") + }) + }) + + describe("revert cases", () => { + it("price not match", async () => { + await ctx.setOraclePrice(decimalStr("200")) + await assert.rejects( + UniswapArbitrageurReverse.methods.executeBuyArbitrage(decimalStr("1")).send(ctx.sendParam(keeper)), + /NOT_PROFITABLE/ + ) + await assert.rejects( + UniswapArbitrageurReverse.methods.executeSellArbitrage(decimalStr("1")).send(ctx.sendParam(keeper)), + /NOT_PROFITABLE/ + ) + }) + }) +}) \ No newline at end of file diff --git a/test/utils/Context.ts b/test/utils/Context.ts index d50f03c..451bd44 100644 --- a/test/utils/Context.ts +++ b/test/utils/Context.ts @@ -65,7 +65,8 @@ export class DODOContext { async init(config: DODOContextInitConfig) { this.EVM = new EVM this.Web3 = getDefaultWeb3() - this.DODOZoo = await contracts.newContract(contracts.DODO_ZOO_CONTRACT_NAME) + var cloneFactory = await contracts.newContract(contracts.CLONE_FACTORY_CONTRACT_NAME) + this.BASE = await contracts.newContract(contracts.TEST_ERC20_CONTRACT_NAME, ["TestBase", 18]) this.QUOTE = await contracts.newContract(contracts.TEST_ERC20_CONTRACT_NAME, ["TestQuote", 18]) this.ORACLE = await contracts.newContract(contracts.NAIVE_ORACLE_CONTRACT_NAME) @@ -76,8 +77,10 @@ export class DODOContext { this.Maintainer = allAccounts[2] this.spareAccounts = allAccounts.slice(3, 10) + var DODOTemplate = await contracts.newContract(contracts.DODO_CONTRACT_NAME) + this.DODOZoo = await contracts.newContract(contracts.DODO_ZOO_CONTRACT_NAME, [DODOTemplate.options.address, cloneFactory.options.address, this.Supervisor]) + await this.DODOZoo.methods.breedDODO( - this.Supervisor, this.Maintainer, this.BASE.options.address, this.QUOTE.options.address, @@ -93,8 +96,6 @@ export class DODOContext { this.BaseCapital = contracts.getContractWithAddress(contracts.DODO_LP_TOKEN_CONTRACT_NAME, await this.DODO.methods._BASE_CAPITAL_TOKEN_().call()) this.QuoteCapital = contracts.getContractWithAddress(contracts.DODO_LP_TOKEN_CONTRACT_NAME, await this.DODO.methods._QUOTE_CAPITAL_TOKEN_().call()) - this.DODO.methods.claimOwnership().send(this.sendParam(this.Deployer)) - console.log(log.blueText("[Init dodo context]")) } diff --git a/test/utils/Contracts.ts b/test/utils/Contracts.ts index 31a936c..b07b068 100644 --- a/test/utils/Contracts.ts +++ b/test/utils/Contracts.ts @@ -10,6 +10,7 @@ if (process.env["COVERAGE"]) { jsonPath = "../../.coverage_artifacts/contracts/" } +const CloneFactory = require(`${jsonPath}CloneFactory.json`) const DODO = require(`${jsonPath}DODO.json`) const DODOZoo = require(`${jsonPath}DODOZoo.json`) const DODOEthProxy = require(`${jsonPath}DODOEthProxy.json`) @@ -17,10 +18,13 @@ const WETH = require(`${jsonPath}WETH9.json`) const TestERC20 = require(`${jsonPath}TestERC20.json`) const NaiveOracle = require(`${jsonPath}NaiveOracle.json`) const DODOLpToken = require(`${jsonPath}DODOLpToken.json`) +const Uniswap = require(`${jsonPath}UniswapV2Pair.json`) +const UniswapArbitrageur = require(`${jsonPath}UniswapArbitrageur.json`) import { getDefaultWeb3 } from './EVM'; import { Contract } from 'web3-eth-contract'; +export const CLONE_FACTORY_CONTRACT_NAME = "CloneFactory" export const DODO_CONTRACT_NAME = "DODO" export const TEST_ERC20_CONTRACT_NAME = "TestERC20" export const NAIVE_ORACLE_CONTRACT_NAME = "NaiveOracle" @@ -28,6 +32,20 @@ export const DODO_LP_TOKEN_CONTRACT_NAME = "DODOLpToken" export const DODO_ZOO_CONTRACT_NAME = "DOOZoo" export const DODO_ETH_PROXY_CONTRACT_NAME = "DODOEthProxy" export const WETH_CONTRACT_NAME = "WETH" +export const UNISWAP_CONTRACT_NAME = "Uniswap" +export const UNISWAP_ARBITRAGEUR_CONTRACT_NAME = "UniswapArbitrageur" + +var contractMap: { [name: string]: any } = {} +contractMap[CLONE_FACTORY_CONTRACT_NAME] = CloneFactory +contractMap[DODO_CONTRACT_NAME] = DODO +contractMap[TEST_ERC20_CONTRACT_NAME] = TestERC20 +contractMap[NAIVE_ORACLE_CONTRACT_NAME] = NaiveOracle +contractMap[DODO_LP_TOKEN_CONTRACT_NAME] = DODOLpToken +contractMap[DODO_ZOO_CONTRACT_NAME] = DODOZoo +contractMap[DODO_ETH_PROXY_CONTRACT_NAME] = DODOEthProxy +contractMap[WETH_CONTRACT_NAME] = WETH +contractMap[UNISWAP_CONTRACT_NAME] = Uniswap +contractMap[UNISWAP_ARBITRAGEUR_CONTRACT_NAME] = UniswapArbitrageur interface ContractJson { abi: any; @@ -36,51 +54,11 @@ interface ContractJson { } export function getContractJSON(contractName: string): ContractJson { - switch (contractName) { - case DODO_CONTRACT_NAME: - return { - abi: DODO.abi, - networks: DODO.networks, - byteCode: DODO.bytecode - }; - case TEST_ERC20_CONTRACT_NAME: - return { - abi: TestERC20.abi, - networks: TestERC20.networks, - byteCode: TestERC20.bytecode - }; - case NAIVE_ORACLE_CONTRACT_NAME: - return { - abi: NaiveOracle.abi, - networks: NaiveOracle.networks, - byteCode: NaiveOracle.bytecode - }; - case DODO_LP_TOKEN_CONTRACT_NAME: - return { - abi: DODOLpToken.abi, - networks: DODOLpToken.networks, - byteCode: DODOLpToken.bytecode - }; - case DODO_ZOO_CONTRACT_NAME: - return { - abi: DODOZoo.abi, - networks: DODOZoo.networks, - byteCode: DODOZoo.bytecode - }; - case DODO_ETH_PROXY_CONTRACT_NAME: - return { - abi: DODOEthProxy.abi, - networks: DODOEthProxy.networks, - byteCode: DODOEthProxy.bytecode - }; - case WETH_CONTRACT_NAME: - return { - abi: WETH.abi, - networks: WETH.networks, - byteCode: WETH.bytecode - }; - default: - throw "CONTRACT_NAME_NOT_FOUND"; + var info = contractMap[contractName] + return { + abi: info.abi, + networks: info.networks, + byteCode: info.bytecode } } From 753a75e81682a9ac04b8d8638b8778982cc87d6e Mon Sep 17 00:00:00 2001 From: mingda Date: Sat, 1 Aug 2020 16:14:24 +0800 Subject: [PATCH 060/118] rename claim to claimAssets --- contracts/impl/Settlement.sol | 6 +++--- test/Admin.test.ts | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/contracts/impl/Settlement.sol b/contracts/impl/Settlement.sol index bb133d1..087a627 100644 --- a/contracts/impl/Settlement.sol +++ b/contracts/impl/Settlement.sol @@ -29,7 +29,7 @@ contract Settlement is Storage { event Donate(uint256 amount, bool isBaseToken); - event Claim(address indexed user, uint256 baseTokenAmount, uint256 quoteTokenAmount); + event ClaimAssets(address indexed user, uint256 baseTokenAmount, uint256 quoteTokenAmount); // ============ Assets IN/OUT Functions ============ @@ -104,7 +104,7 @@ contract Settlement is Storage { } // claim remaining assets after final settlement - function claim() external preventReentrant { + function claimAssets() external preventReentrant { require(_CLOSED_, "DODO_NOT_CLOSED"); require(!_CLAIMED_[msg.sender], "ALREADY_CLAIMED"); _CLAIMED_[msg.sender] = true; @@ -118,7 +118,7 @@ contract Settlement is Storage { ); _baseTokenTransferOut(msg.sender, baseAmount); _quoteTokenTransferOut(msg.sender, quoteAmount); - emit Claim(msg.sender, baseAmount, quoteAmount); + emit ClaimAssets(msg.sender, baseAmount, quoteAmount); return; } diff --git a/test/Admin.test.ts b/test/Admin.test.ts index 0375223..3b95c64 100644 --- a/test/Admin.test.ts +++ b/test/Admin.test.ts @@ -182,7 +182,7 @@ describe("Admin", () => { await ctx.DODO.methods.finalSettlement().send(ctx.sendParam(ctx.Deployer)) - await ctx.DODO.methods.claim().send(ctx.sendParam(lp1)) + await ctx.DODO.methods.claimAssets().send(ctx.sendParam(lp1)) await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp1)) await ctx.DODO.methods.withdrawAllQuote().send(ctx.sendParam(lp1)) @@ -198,7 +198,7 @@ describe("Admin", () => { await ctx.DODO.methods.finalSettlement().send(ctx.sendParam(ctx.Deployer)) assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0") - await ctx.DODO.methods.claim().send(ctx.sendParam(lp1)) + await ctx.DODO.methods.claimAssets().send(ctx.sendParam(lp1)) assert.equal(await ctx.BASE.methods.balanceOf(lp1).call(), decimalStr("90")) assert.equal(await ctx.QUOTE.methods.balanceOf(lp1).call(), "9551951805416248746110") await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp1)) @@ -215,7 +215,7 @@ describe("Admin", () => { await ctx.DODO.methods.finalSettlement().send(ctx.sendParam(ctx.Deployer)) assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0") - await ctx.DODO.methods.claim().send(ctx.sendParam(lp1)) + await ctx.DODO.methods.claimAssets().send(ctx.sendParam(lp1)) assert.equal(await ctx.BASE.methods.balanceOf(lp1).call(), decimalStr("95")) assert.equal(await ctx.QUOTE.methods.balanceOf(lp1).call(), decimalStr("9000")) await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp1)) @@ -226,7 +226,7 @@ describe("Admin", () => { it("final settlement revert cases", async () => { await assert.rejects( - ctx.DODO.methods.claim().send(ctx.sendParam(lp1)), + ctx.DODO.methods.claimAssets().send(ctx.sendParam(lp1)), /DODO_NOT_CLOSED/ ) await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) @@ -239,9 +239,9 @@ describe("Admin", () => { / DODO_CLOSED/ ) - await ctx.DODO.methods.claim().send(ctx.sendParam(lp2)) + await ctx.DODO.methods.claimAssets().send(ctx.sendParam(lp2)) await assert.rejects( - ctx.DODO.methods.claim().send(ctx.sendParam(lp2)), + ctx.DODO.methods.claimAssets().send(ctx.sendParam(lp2)), /ALREADY_CLAIMED/ ) From 95089263e194e1767f462d085a7e57b266d06801 Mon Sep 17 00:00:00 2001 From: mingda Date: Sun, 2 Aug 2020 11:02:20 +0800 Subject: [PATCH 061/118] use msg.sender instead of tx.origin --- contracts/helper/UniswapArbitrageur.sol | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/contracts/helper/UniswapArbitrageur.sol b/contracts/helper/UniswapArbitrageur.sol index b956084..a67433e 100644 --- a/contracts/helper/UniswapArbitrageur.sol +++ b/contracts/helper/UniswapArbitrageur.sol @@ -47,8 +47,6 @@ contract UniswapArbitrageur { bool public _REVERSE_; // true if dodo.baseToken=uniswap.token0 - uint256 public lastArbitrageProfit; - constructor(address _uniswap, address _dodo) public { _UNISWAP_ = _uniswap; _DODO_ = _dodo; @@ -73,12 +71,16 @@ contract UniswapArbitrageur { function executeBuyArbitrage(uint256 baseAmount) external returns (uint256 quoteProfit) { IDODO(_DODO_).buyBaseToken(baseAmount, uint256(-1), "0xd"); - return lastArbitrageProfit; + quoteProfit = IERC20(_QUOTE_).balanceOf(address(this)); + IERC20(_QUOTE_).transfer(msg.sender, quoteProfit); + return quoteProfit; } function executeSellArbitrage(uint256 baseAmount) external returns (uint256 baseProfit) { IDODO(_DODO_).sellBaseToken(baseAmount, 0, "0xd"); - return lastArbitrageProfit; + baseProfit = IERC20(_BASE_).balanceOf(address(this)); + IERC20(_BASE_).transfer(msg.sender, baseProfit); + return baseProfit; } function dodoCall( @@ -113,9 +115,7 @@ contract UniswapArbitrageur { ); token0Amount = token0Balance.sub(newToken0Balance).mul(9969).div(10000); // mul 0.9969 require(token0Amount > quoteAmount, "NOT_PROFITABLE"); - lastArbitrageProfit = token0Amount.sub(quoteAmount); IUniswapV2Pair(_UNISWAP_).swap(token0Amount, token1Amount, address(this), ""); - IERC20(_QUOTE_).transfer(tx.origin, lastArbitrageProfit); } else { IERC20(_QUOTE_).transfer(_UNISWAP_, quoteAmount); // transfer token0 into uniswap @@ -124,9 +124,7 @@ contract UniswapArbitrageur { ); token1Amount = token1Balance.sub(newToken1Balance).mul(9969).div(10000); // mul 0.9969 require(token1Amount > baseAmount, "NOT_PROFITABLE"); - lastArbitrageProfit = token1Amount.sub(baseAmount); IUniswapV2Pair(_UNISWAP_).swap(token0Amount, token1Amount, address(this), ""); - IERC20(_BASE_).transfer(tx.origin, lastArbitrageProfit); } } @@ -148,9 +146,7 @@ contract UniswapArbitrageur { ); token1Amount = token1Balance.sub(newToken1Balance).mul(9969).div(10000); // mul 0.9969 require(token1Amount > quoteAmount, "NOT_PROFITABLE"); - lastArbitrageProfit = token1Amount.sub(quoteAmount); IUniswapV2Pair(_UNISWAP_).swap(token0Amount, token1Amount, address(this), ""); - IERC20(_QUOTE_).transfer(tx.origin, lastArbitrageProfit); } else { IERC20(_QUOTE_).transfer(_UNISWAP_, quoteAmount); // transfer token1 into uniswap @@ -159,9 +155,7 @@ contract UniswapArbitrageur { ); token0Amount = token0Balance.sub(newToken0Balance).mul(9969).div(10000); // mul 0.9969 require(token0Amount > baseAmount, "NOT_PROFITABLE"); - lastArbitrageProfit = token0Amount.sub(baseAmount); IUniswapV2Pair(_UNISWAP_).swap(token0Amount, token1Amount, address(this), ""); - IERC20(_BASE_).transfer(tx.origin, lastArbitrageProfit); } } From b35f80858c2414d9cd37154e6303bf9f1fa06044 Mon Sep 17 00:00:00 2001 From: mingda Date: Tue, 4 Aug 2020 21:45:19 +0800 Subject: [PATCH 062/118] update git ignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 38880f7..e9a6cc6 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ node_modules/ coverage/ lint/ script/ +flattered/ # VIM *.swo From b1007bf2ecbfaa39ac2f5bb772feec781684f1b8 Mon Sep 17 00:00:00 2001 From: mingda Date: Tue, 4 Aug 2020 21:50:46 +0800 Subject: [PATCH 063/118] update reademe --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 226ad19..a247974 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,12 @@ [PeckShield Inc.](https://peckshield.cn/en) is a leading blockchain security company with the goal of elevating the security, privacy, and usability of current blockchain ecosystems by offering top-notch, industry-leading services and products. -You could find the audit report [here](https://raw.githubusercontent.com/radar-bear/dodo-smart-contract/master/audit/dodo_audit_report_2020_16_en_1.0.pdf) +You could find the audit report [here](https://raw.githubusercontent.com/DODOEX/dodo-smart-contract/master/audit/dodo_audit_report_2020_16_en_1.0.pdf) ## More details and deployment info -You could find all documents and info about DODO in [this repo](https://github.com/radar-bear/dodo-docs) +You could find all documents and info about DODO [here](https://dodoex.github.io/docs/docs) ## Contact Us -Send E-mail to dodo_breeder@dodoex.io \ No newline at end of file +Send E-mail to contact@dodoex.io \ No newline at end of file From 3384b5d6b53f1293cb2f1738ac14462a75e0dffd Mon Sep 17 00:00:00 2001 From: mingda Date: Wed, 5 Aug 2020 17:17:26 +0800 Subject: [PATCH 064/118] add bug bounty --- README.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/README.md b/README.md index a247974..d81057c 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,31 @@ You could find the audit report [here](https://raw.githubusercontent.com/DODOEX/ You could find all documents and info about DODO [here](https://dodoex.github.io/docs/docs) +## Bug Bounty 💰 + +### Rewards + +Severity of bugs will be assessed under the [CVSS Risk Rating](https://www.first.org/cvss/calculator/3.0) scale, as follows: + + - Critical (9.0-10.0): Up to $50,000 + - High (7.0-8.9): Up to $10,000 + - Medium (4.0-6.9): Up to $2,000 + - Low (0.1-3.9): Up to $1,000 + +In addition to assessing severity, rewards will be considered based on the impact of the discovered vulnerability as well as the level of difficulty in discovering such vulnerability. + +### Disclosure + +Any vulnerability or bug discovered must be reported only to the following email: contact@dodoex.io; must not be disclosed publicly; must not be disclosed to any other person, entity or email address prior to disclosure to the contact@dodoex.io email; and must not be disclosed in any way other than to the contact@dodoex.io email. In addition, disclosure to contact@dodoex.io must be made promptly following discovery of the vulnerability. Please include as much information about the vulnerability as possible, including: + + - The conditions on which reproducing the bug is contingent. + - The steps needed to reproduce the bug or, preferably, a proof of concept. + - The potential implications of the vulnerability being abused. + +A detailed report of a vulnerability increases the likelihood of a reward and may increase the reward amount. + +Anyone who reports a unique, previously-unreported vulnerability that results in a change to the code or a configuration change and who keeps such vulnerability confidential until it has been resolved by our engineers will be recognized publicly for their contribution, if agreed. + ## Contact Us Send E-mail to contact@dodoex.io \ No newline at end of file From 95f451b509b961c7e593df60f5ea9d6a7c31fc68 Mon Sep 17 00:00:00 2001 From: mingda Date: Thu, 6 Aug 2020 09:34:21 +0800 Subject: [PATCH 065/118] move docs to github page --- .gitignore | 2 - docs/DODO Smart Contract Instructions.html | 968 --------------------- docs/PMM Algorithm Specification.html | 686 --------------- 3 files changed, 1656 deletions(-) delete mode 100644 docs/DODO Smart Contract Instructions.html delete mode 100644 docs/PMM Algorithm Specification.html diff --git a/.gitignore b/.gitignore index e9a6cc6..06def01 100644 --- a/.gitignore +++ b/.gitignore @@ -5,8 +5,6 @@ build/ dist/ -docs/img -docs/src node_modules/ coverage/ lint/ diff --git a/docs/DODO Smart Contract Instructions.html b/docs/DODO Smart Contract Instructions.html deleted file mode 100644 index 7aac059..0000000 --- a/docs/DODO Smart Contract Instructions.html +++ /dev/null @@ -1,968 +0,0 @@ - - - - - - - -DODO Smart Contract Instructions - - - - - - - - - - - - - -

DODO Smart Contract Instructions

- -

This is an instructions for users who want to interact with dodo smart contract directly.

- -

Overview

- -

Each trading pair is an independent DODO smart contract, and all DODO contracts are registered in DODO ZOO.

- -

Users interact with each DODO smart contract directly. All external functions are divided into three sub-contracts according to the role of their users: Admin, Trader and LiquidityProvider.

- -

To simplify users' operations, we developed DODO ETH Proxy, a helper contract that helps user handle with WETH-ETH converting.

- -

- -

For Trader

- -

sellBaseToken(uint256 amount, uint256 minReceiveQuote) returns (uint256 receiveQuote)

- - - - - - - - - - - - - - - - - - - - - - - - - - - -
sellBaseTokenDesc
@devSell base token and receive quote token
@param amountThe amount of base token to sell
@param minReceiveQuoteThe minimum amount of quote token required. Transaction will be reverted if the trader receive quote token less than this value.
@returns receiveQuoteThe amount of quote token received
- -

buyBaseToken(uint256 amount, uint256 maxPayQuote) returns (uint256 payQuote)

- - - - - - - - - - - - - - - - - - - - - - - - - - - -
buyBaseTokenDesc
@devBuy base token and pay quote token
@param amountThe amount of base token to buy
@param maxPayQuoteThe maximum amount of quote token needs to pay. Transaction will be reverted if the trader pay quote token greater than this value.
@returns payQuoteThe amount of quote token paid
- -

For Liquidity Provider

- -

depositBase(uint256 amount)

- - - - - - - - - - - - - - - - - - - -
depositBaseDesc
@devDeposit base token to liquidity pool
@param amountThe amount of base token to deposit
- -

depositQuote(uint256 amount)

- - - - - - - - - - - - - - - - - - - -
depositQuoteDesc
@devDeposit quote token to liquidity pool
@param amountThe amount of quote token to deposit
- -

withdrawBase(uint256 amount) returns (uint256 receiveAmount)

- - - - - - - - - - - - - - - - - - - - - - - - - - - -
withdrawBaseDesc
@devWithdraw base token from liquidity pool
@param amountThe amount of base token to withdraw
@returns receiveAmountThe amount of base token sender received
@noticeDODO charges penalty fee from liquidity providers who withdraw assets and share the fee with all remaining liquidity providers. Normally the penalty would be 0 or nearly 0.
- -

withdrawQuote(uint256 amount) returns (uint256 receiveAmount)

- - - - - - - - - - - - - - - - - - - - - - - - - - - -
withdrawQuoteDesc
@devWithdraw quote token from liquidity pool
@param amountThe amount of quote token to withdraw
@returns receiveAmountThe amount of quote token sender received
@noticeDODO charges penalty fee from liquidity providers who withdraw assets and share the fee with all remaining liquidity providers. Normally the penalty would be 0 or nearly 0.
- -

For FrontEnd Developer

- -

Sendable functions

- -

withdrawAllBase() returns (uint256 receiveAmount)

- - - - - - - - - - - - - - - -
withdrawAllBaseDesc
@devWithdraw message sender’s all base token deposited in the pool.
- -

withdrawAllQuote() returns (uint256 receiveAmount)

- - - - - - - - - - - - - - - -
withdrawAllQuoteDesc
@devWithdraw message sender’s all quote token deposited in the pool.
- -

View functions

- -

_GAS_PRICE_LIMIT_

- - - - - - - - - - - - - - - -
_GASPRICELIMIT_Desc
@devA public variable. All transactions involving trading should be sent with gas price no greater than this value. Otherwise, DODO will revert the transactions.
- -

getLpBaseBalance(address lp) returns (uint256 lpBalance)

- - - - - - - - - - - - - - - -
getLpBaseBalanceDesc
@devGet liquidity provider’s base token balance in the pool
- -

getLpQuoteBalance(address lp) returns (uint256 lpBalance)

- - - - - - - - - - - - - - - -
getLpQuoteBalanceDesc
@devGet liquidity provider’s quote token balance in the pool
- -

getWithdrawQuotePenalty(uint256 amount) returns (uint256 penalty)

- - - - - - - - - - - - - - - -
getWithdrawQuotePenaltyDesc
@devGet the penalty fee will be charged if some liquidity provider withdraw a certain amount of quote token from pool.
- -

getWithdrawBasePenalty(uint256 amount) returns (uint256 penalty)

- - - - - - - - - - - - - - - -
getWithdrawBasePenaltyDesc
@devGet the penalty fee will be charged if some liquidity provider withdraw a certain amount of base token from pool.
- -

querySellBaseToken(uint256 amount) returns (uint256 receiveQuote)

- - - - - - - - - - - - - - - -
querySellBaseTokenDesc
@devA “view” version of sellBaseToken. This function can be really useful to query price because it doesn’t cost gas.
- -

queryBuyBaseToken(uint256 amount) returns (uint256 payQuote)

- - - - - - - - - - - - - - - -
queryBuyBaseTokenDesc
@devA “view” version of buyBaseToken. This function can be really useful to query price because it doesn’t cost gas.
- -

DODO Eth Proxy functions

- -

As DODO only works fine with ERC20 tokens, if you want to use Ether directly on DODO, we provide a proxy smart contract to help you access DODO. Basicly, the proxy contract convert Ether to Wrapped ETH, a kind of ERC20 token, and use it on DODO. The operation is totally transparent to user.

- -

sellEthTo(address quoteTokenAddress,uint256 ethAmount,uint256 minReceiveTokenAmount) returns (uint256 receiveTokenAmount)

- - - - - - - - - - - - - - - -
sellEthToDesc
@devSell ETH on WETH-quoteTokenAddress market
- -

buyEthWith(address quoteTokenAddress,uint256 ethAmount,uint256 maxPayTokenAmount) returns (uint256 payTokenAmount)

- - - - - - - - - - - - - - - -
buyEthToDesc
@devBuy ETH on WETH-quoteTokenAddress market
- -

depositEth(uint256 ethAmount, address quoteTokenAddress)

- - - - - - - - - - - - - - - -
depositEthDesc
@devDeposit ETH to WETH-quoteTokenAddress market
- -

For Quant

- -

withdrawBaseTo(address to, uint256 amount) returns (uint256)

- -

depositBaseTo(address to, uint256 amount)

- -

withdrawQuoteTo(address to, uint256 amount) returns (uint256)

- -

depositQuoteTo(address to, uint256 amount)

- -

withdrawAllBaseTo(address to) returns (uint256)

- -

withdrawAllQuoteTo(address to) returns (uint256)

- - - - - - - - - - - - - - - diff --git a/docs/PMM Algorithm Specification.html b/docs/PMM Algorithm Specification.html deleted file mode 100644 index 686e2c0..0000000 --- a/docs/PMM Algorithm Specification.html +++ /dev/null @@ -1,686 +0,0 @@ - - - - - - - -PMM Algorithm Specification - - - - - - - - - - - - - -

DODO PMM 算法详解

- -

DODO 是新一代由算法驱动的纯链上流动性提供方案。很多人误以为这是对 AMM(Auto Market Maker)算法的改进,事实上 DODO 提出了全新的算法,其运作机制与 AMM 截然不同,我们将其命名为 PMM(Proactive Market Maker)算法。

- -

本文将全面对算法进行解析,尤其是其链上实现版本。

- -

资金池回归模型

- -

PMM 的资金池由四个参数描述

- -
    -
  • \(B_0\) BaseToken 回归目标
  • -
  • \(Q_0\) QuoteToken 回归目标
  • -
  • \(B\) BaseToken 余额
  • -
  • \(Q\) QuoteToken 余额
  • -
- -
-

以ETH-USDT交易对为例,BaseToken指ETH,QuoteToken指USDT

-
- -

价格曲线由下面的公式给出

- -

\[P_{margin}=iR\] -\[if \ B<B_0, \ R=1-k+(\frac{B_0}{B})^2k\] -\[if \ Q<Q_0, \ R=1/(1-k+(\frac{Q_0}{Q})^2k)\] -\[else \ R=1\]

- -

可以发现PMM有三种工作场景:均衡、BaseToken匮乏、QuoteToken匮乏。

- -
    -
  • 没有用户交易时,资金池处于均衡状态,BaseToken和QuoteToken都处于其回归目标
  • -
  • 当用户卖出BaseToken时,资金池BaseToken余额高于回归目标,而QuoteToken余额小于回归目标。此时PMM算法会尝试卖出多余的BaseToken,以使QuoteToken余额回归均衡状态。
  • -
  • 当用户买入BaseToken时,资金池QuoteToken余额高于回归目标,而BaseToken余额小于回归目标。此时PMM算法会尝试卖出多余的QuoteToken,以使BaseToken余额回归均衡状态。
  • -
- -

- -

参数\(R\)在此过程中起到了促进回归的作用,资金池偏离均衡状态越多,\(R\)越偏离1,PMM算法给出的价格便越偏离市场价,吸引套利者帮助资金池回归均衡状态。

- -

至此我们介绍完毕了PMM算法的运作机制,下一节将进入合约实现环节。

- -

交易者

- -

对交易者来说,最重要的就是平均成交价。平均成交价是边际价格\(P_{margin}\)的积分

- -

单一工作场景下的价格

- -

BaseToken匮乏场景

- -

- -

\[\Delta Q =\int^{B_2}_{B_1}P_{margin}dB= \int^{B_2}_{B_1}(1-k)i+i(\frac{B_0}{B})^2kdB \] -\[= i(B_2-B_1)*(1-k+k\frac{B_0^2}{B_1B_2})\]

- -

平均成交价为:

- -

\[P=\frac{\Delta Q}{B_2-B_1}=i*(1-k+k\frac{B_0^2}{B_1B_2})\]

- -

我们发现,平均成交价只与成交前后系统的状态有关,所以买卖两种操作的价格计算方式是一样的——都是对\(P_{margin}\)进行积分。

- -

QuoteToken匮乏场景

- -

为了简化用户理解,我们只提供sellBaseToken和buyBaseToken两个接口,下面来推导quoteToken匮乏场景下,给出想要买卖的baseToken数量,如何计算价格。

- -

\[\Delta B = \frac{1}{i}(Q_2-Q_1)*(1-k+k\frac{Q_0^2}{Q_1Q_2})\]

- -

已知\(\Delta B, Q_0, Q_1\),求解\(Q_2\),这是一个二次方程,转化为标准形式后:

- -

\[(1-k)Q_2^2+(\frac{kQ_0^2}{Q_1}-Q_1+kQ_1-i\Delta B)Q_2-kQ_0^2=0\]

- -

\[let \ a=1-k, \ b=\frac{kQ_0^2}{Q_1}-Q_1+kQ_1-i\Delta B, \ c=-kQ_0^2\]

- -

因为\(Q_2>=0\),所以舍掉一个负数根,得到\(Q_2\)的公式为

- -

\[Q_2=\frac{-b+\sqrt{b^2-4ac}}{2a}\]

- -

在\(\Delta B>0\)时,\(Q_2>Q_1\); 在\(\Delta B<0\)时,\(Q_2<Q_1\); 在\(\Delta B=0\)时,\(Q_2=Q_1\)

- -

Oracle价格变化的影响

- -

当系统不处于均衡态时,Oracle变化将带来盈利或亏损。举例来讲,假设现在系统处于BaseToken匮乏场景,Oracle价格提高,将导致多余的QuoteToken无法买入足够的BaseToken,提供BaseToken的lp出现亏损。同理如果Oracle价格下降,多余的QuoteToken可以买入更多的BaseToken,使BaseToken余额超过回归目标,提供BaseToken的lp有盈余。

- -

为了计算新Oracle价格下的回归目标,我们进行如下推导:

- -

\[\Delta Q = i(B_2-B_1)*(1-k+k\frac{B_0^2}{B_1B_2})\]

- -

回归时,\(B_2=B_0\),整理出关于\(B_0\)的二次方程

- -

\[\frac{k}{B_1}B_0^2+(1-2k)B_0-[(1-k)B_1+\frac{\Delta Q}{i}] = 0\]

- -

舍弃掉负数解,得到\(B_0\)的解为

- -

\[B_0=B_1+B_1*\frac{\sqrt{1+\frac{4k\Delta Q}{B_1 i}}-1}{2k}\]

- -

这里\(\Delta Q=Q-Q_0\). 可以严格证明,在\(\Delta Q \ge 0\)时,\(B_0\ge B_1\). 这一性质非常重要,因为它保证了BaseToken余额和QuoteToken余额不会同时大于回归目标,或同时小于回归目标。这样一来,PMM只会在文章开头提到的三种状态中转换。

- -

同理我们直接给出\(Q_0\)的计算公式

- -

\[Q_0=Q_1+Q_1*\frac{\sqrt{1+\frac{4k\Delta B i}{Q_1}}-1}{2k}\]

- -

跨工作场景时的价格

- -

由于PMM给出的价格曲线是分段的,如果一笔交易跨越了工作场景(比如在BaseToken匮乏时用户卖出大量BaseToken,直接进入QuoteToken匮乏场景),就需要分段计算价格,并累计。

- -

这一累计要求精度很高,但计算机有精度损失,所以处理起来要非常小心。合约里提供了三种工作场景下的买卖函数,总计6个。其组合方式是关键。

- -

流动性提供商

- -

流动性提供商又称为lp(liquidity provider)。lp有两种操作,充值&提现。

- -

在BaseToken匮乏场景下充提BaseToken,或在QuoteToken匮乏场景下充提QuoteToken,都会使得改变价格曲线。这要求我们合理地处理充提操作,以使资金池保持健康和公平。

- -

充值

- -

我们以BaseToken匮乏场景为例,研究充值如何影响lp收益。

- -

根据上文推导出的\(B_0\)计算公式

- -

\[B_0=B_1+B_1*\frac{\sqrt{1+\frac{4k\Delta Q}{B_1 i}}-1}{2k}\]

- -

充值\(b\)后,\(B_1\)增加\(b\),而\(B_0\)的增量大于\(b\).就说明充值使得所有提供BaseToken的lp都获得了收益。这一收益的来源是,充值使价格曲线变得平缓,同样数量的\(\Delta Q\)可以购买更多BaseToken。

- -

在这种情况下,lp一旦充值就会获得收益,我们称之为“充值奖励”,因为充值使得系统更接近均衡状态了。这笔奖励的本质来源是交易者付出的滑点。

- -

但“充值奖励”并不是无风险套利机会,请继续阅读下一节。

- -

提现

- -

与上一节同理,提现\(b\)后,\(B_1\)减少\(b\),而\(B_0\)减少的量多于\(b\)。说明提现使所有BaseToken的lp都蒙受损失。这一损失的来源是,提现使价格曲线变得陡峭,同样数量的\(\Delta Q\)只能购买更少的BaseToken。

- -

PMM算法规定,这种情况下提现需要缴纳一笔“流动性罚金”。罚金数额等于提币后造成的lp损失,这笔罚金将直接充入资金池,分给所有未撤资的lp。

- -

回到上一节中的情况,如果lp充值后立刻提现,罚金将大于收益,所以不会有无风险套利的机会。这一设计倾向于未撤资lp,可以最大限度留存资金。

- -
-

值得注意的是,不论是充值奖励,还是流动性罚金,都只有在系统偏离均衡状态较远,且充提金额很大的时候才显著。 -普通用户往往感知不到这一收益(损失)的存在。当然也欢迎羊毛党,在系统偏离均衡时充值赚取充值奖励,在系统回归平衡时提现来避免流动性罚金

-
- - - - - - - - - - - - - - - From 2c6aaead0160eee36b421bfe36a84827ff288383 Mon Sep 17 00:00:00 2001 From: mingda Date: Thu, 6 Aug 2020 17:33:31 +0800 Subject: [PATCH 066/118] update mint event --- contracts/impl/DODOLpToken.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/impl/DODOLpToken.sol b/contracts/impl/DODOLpToken.sol index ece9f6d..33e47b7 100644 --- a/contracts/impl/DODOLpToken.sol +++ b/contracts/impl/DODOLpToken.sol @@ -121,7 +121,7 @@ contract DODOLpToken is Ownable { function mint(address user, uint256 value) external onlyOwner { balances[user] = balances[user].add(value); totalSupply = totalSupply.add(value); - emit Mint(address(0), value); + emit Mint(user, value); emit Transfer(address(0), user, value); } From 782ea8d9ab569616e01c159b8fc142d2f3b220d6 Mon Sep 17 00:00:00 2001 From: mingda Date: Fri, 7 Aug 2020 21:50:33 +0800 Subject: [PATCH 067/118] restruct dodozoo remove dodo --- contracts/DODOZoo.sol | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/contracts/DODOZoo.sol b/contracts/DODOZoo.sol index 882a30f..5ece610 100644 --- a/contracts/DODOZoo.sol +++ b/contracts/DODOZoo.sol @@ -62,12 +62,13 @@ contract DODOZoo is Ownable { address quoteToken = IDODO(dodo)._QUOTE_TOKEN_(); require(isDODORegistered(baseToken, quoteToken), "DODO_NOT_REGISTERED"); _DODO_REGISTER_[baseToken][quoteToken] = address(0); - for (uint256 i = 0; i < _DODOs.length - 1; i++) + for (uint256 i = 0; i < _DODOs.length - 1; i++) { if (_DODOs[i] == dodo) { _DODOs[i] = _DODOs[_DODOs.length - 1]; + _DODOs.pop(); break; } - _DODOs.pop(); + } } function addDODO(address dodo) public onlyOwner { From 020609b9b5e35d30c5b831b3a2f83ca0b96bc052 Mon Sep 17 00:00:00 2001 From: mingda Date: Mon, 10 Aug 2020 16:44:41 +0800 Subject: [PATCH 068/118] adjust multi sig wallet --- contracts/helper/MultiSigWalletWithTimeLock.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/helper/MultiSigWalletWithTimeLock.sol b/contracts/helper/MultiSigWalletWithTimeLock.sol index a921c43..a20186a 100644 --- a/contracts/helper/MultiSigWalletWithTimeLock.sol +++ b/contracts/helper/MultiSigWalletWithTimeLock.sol @@ -151,7 +151,7 @@ contract MultiSigWalletWithTimelock { } } - owners.pop; + owners.pop(); if (required > owners.length) { changeRequirement(owners.length); @@ -269,7 +269,7 @@ contract MultiSigWalletWithTimelock { require(block.timestamp >= unlockTimes[transactionId], "TRANSACTION_NEED_TO_UNLOCK"); if (isConfirmed(transactionId)) { - Transaction storage transaction = transactions[transactionId]; + Transaction memory transaction = transactions[transactionId]; transaction.executed = true; (bool success, ) = transaction.destination.call{value: transaction.value}( transaction.data From 2e3bff89f688323bf8bea30b8210bb6d5c6d1bf1 Mon Sep 17 00:00:00 2001 From: mingda Date: Thu, 13 Aug 2020 18:14:51 +0800 Subject: [PATCH 069/118] update multi sig --- .../helper/MultiSigWalletWithTimeLock.sol | 90 +++++++++++++++---- 1 file changed, 72 insertions(+), 18 deletions(-) diff --git a/contracts/helper/MultiSigWalletWithTimeLock.sol b/contracts/helper/MultiSigWalletWithTimeLock.sol index a20186a..28af423 100644 --- a/contracts/helper/MultiSigWalletWithTimeLock.sol +++ b/contracts/helper/MultiSigWalletWithTimeLock.sol @@ -1,11 +1,26 @@ +/** + *Submitted for verification at Etherscan.io on 2019-10-15 + */ + /* - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 + Copyright 2019 The Hydro Protocol Foundation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ -pragma solidity 0.6.9; +pragma solidity 0.5.8; pragma experimental ABIEncoderV2; contract MultiSigWalletWithTimelock { @@ -40,6 +55,14 @@ contract MultiSigWalletWithTimelock { bool executed; } + struct EmergencyCall { + bytes32 selector; + uint256 paramsBytesCount; + } + + // Functions bypass the time lock process + EmergencyCall[] public emergencyCalls; + modifier onlyWallet() { if (msg.sender != address(this)) revert("ONLY_WALLET_ERROR"); _; @@ -92,13 +115,7 @@ contract MultiSigWalletWithTimelock { } /** @dev Fallback function allows to deposit ether. */ - fallback() external payable { - if (msg.value > 0) { - emit Deposit(msg.sender, msg.value); - } - } - - receive() external payable { + function() external payable { if (msg.value > 0) { emit Deposit(msg.sender, msg.value); } @@ -122,6 +139,18 @@ contract MultiSigWalletWithTimelock { owners = _owners; required = _required; + + // initialzie Emergency calls + emergencyCalls.push( + EmergencyCall({ + selector: keccak256(abi.encodePacked("setMarketBorrowUsability(uint16,bool)")), + paramsBytesCount: 64 + }) + ); + } + + function getEmergencyCallsCount() external view returns (uint256 count) { + return emergencyCalls.length; } /** @dev Allows to add a new owner. Transaction has to be sent by wallet. @@ -151,7 +180,7 @@ contract MultiSigWalletWithTimelock { } } - owners.pop(); + owners.length -= 1; if (required > owners.length) { changeRequirement(owners.length); @@ -207,7 +236,7 @@ contract MultiSigWalletWithTimelock { * @param destination Transaction target address. * @param value Transaction ether value. * @param data Transaction data payload. - * @return transactionId Returns transaction ID. + * @return Returns transaction ID. */ function submitTransaction( address destination, @@ -238,13 +267,38 @@ contract MultiSigWalletWithTimelock { confirmations[transactionId][msg.sender] = true; emit Confirmation(msg.sender, transactionId); - if (isConfirmed(transactionId) && unlockTimes[transactionId] == 0) { + if ( + isConfirmed(transactionId) && + unlockTimes[transactionId] == 0 && + !isEmergencyCall(transactionId) + ) { uint256 unlockTime = block.timestamp + lockSeconds; unlockTimes[transactionId] = unlockTime; emit UnlockTimeSet(transactionId, unlockTime); } } + function isEmergencyCall(uint256 transactionId) internal view returns (bool) { + bytes memory data = transactions[transactionId].data; + + for (uint256 i = 0; i < emergencyCalls.length; i++) { + EmergencyCall memory emergencyCall = emergencyCalls[i]; + + if ( + data.length == emergencyCall.paramsBytesCount + 4 && + data.length >= 4 && + emergencyCall.selector[0] == data[0] && + emergencyCall.selector[1] == data[1] && + emergencyCall.selector[2] == data[2] && + emergencyCall.selector[3] == data[3] + ) { + return true; + } + } + + return false; + } + /** @dev Allows an owner to revoke a confirmation for a transaction. * @param transactionId Transaction ID. */ @@ -269,9 +323,9 @@ contract MultiSigWalletWithTimelock { require(block.timestamp >= unlockTimes[transactionId], "TRANSACTION_NEED_TO_UNLOCK"); if (isConfirmed(transactionId)) { - Transaction memory transaction = transactions[transactionId]; + Transaction storage transaction = transactions[transactionId]; transaction.executed = true; - (bool success, ) = transaction.destination.call{value: transaction.value}( + (bool success, ) = transaction.destination.call.value(transaction.value)( transaction.data ); if (success) emit Execution(transactionId); @@ -306,7 +360,7 @@ contract MultiSigWalletWithTimelock { /** @dev Returns number of confirmations of a transaction. * @param transactionId Transaction ID. - * @return count Number of confirmations. + * @return Number of confirmations. */ function getConfirmationCount(uint256 transactionId) external view returns (uint256 count) { for (uint256 i = 0; i < owners.length; i++) { @@ -319,7 +373,7 @@ contract MultiSigWalletWithTimelock { /** @dev Returns total number of transactions after filers are applied. * @param pending Include pending transactions. * @param executed Include executed transactions. - * @return count Total number of transactions after filters are applied. + * @return Total number of transactions after filters are applied. */ function getTransactionCount(bool pending, bool executed) external @@ -342,7 +396,7 @@ contract MultiSigWalletWithTimelock { /** @dev Returns array with owner addresses, which confirmed transaction. * @param transactionId Transaction ID. - * @return _confirmations Returns array of owner addresses. + * @return Returns array of owner addresses. */ function getConfirmations(uint256 transactionId) external From 61031b01f55011d47b86aa3f6dccb631af6272a2 Mon Sep 17 00:00:00 2001 From: mingda Date: Sat, 29 Aug 2020 18:31:23 +0800 Subject: [PATCH 070/118] fix remove DODO --- contracts/DODOZoo.sol | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contracts/DODOZoo.sol b/contracts/DODOZoo.sol index 5ece610..c47cc10 100644 --- a/contracts/DODOZoo.sol +++ b/contracts/DODOZoo.sol @@ -12,6 +12,7 @@ import {Ownable} from "./lib/Ownable.sol"; import {IDODO} from "./intf/IDODO.sol"; import {ICloneFactory} from "./helper/CloneFactory.sol"; + /** * @title DODOZoo * @author DODO Breeder @@ -62,7 +63,7 @@ contract DODOZoo is Ownable { address quoteToken = IDODO(dodo)._QUOTE_TOKEN_(); require(isDODORegistered(baseToken, quoteToken), "DODO_NOT_REGISTERED"); _DODO_REGISTER_[baseToken][quoteToken] = address(0); - for (uint256 i = 0; i < _DODOs.length - 1; i++) { + for (uint256 i = 0; i <= _DODOs.length - 1; i++) { if (_DODOs[i] == dodo) { _DODOs[i] = _DODOs[_DODOs.length - 1]; _DODOs.pop(); From b83b940c494dd5815cb42f229b80beba31292882 Mon Sep 17 00:00:00 2001 From: mingda Date: Mon, 31 Aug 2020 13:19:42 +0800 Subject: [PATCH 071/118] helper oracles --- .../ChainlinkCOMPUSDCPriceOracleProxy.sol | 25 ++ .../helper/ChainlinkEthPriceOracleProxy.sol | 4 +- .../ChainlinkLENDUSDCPriceOracleProxy.sol | 25 ++ .../ChainlinkLINKUSDPriceOracleProxy.sol | 25 ++ .../ChainlinkSNXUSDPriceOracleProxy.sol | 25 ++ .../ChainlinkWBTCUSDCPriceOracleProxy.sol | 25 ++ contracts/helper/MinimumOracle.sol | 56 +++ .../helper/MultiSigWalletWithTimeLock.sol | 423 ------------------ 8 files changed, 184 insertions(+), 424 deletions(-) create mode 100644 contracts/helper/ChainlinkCOMPUSDCPriceOracleProxy.sol create mode 100644 contracts/helper/ChainlinkLENDUSDCPriceOracleProxy.sol create mode 100644 contracts/helper/ChainlinkLINKUSDPriceOracleProxy.sol create mode 100644 contracts/helper/ChainlinkSNXUSDPriceOracleProxy.sol create mode 100644 contracts/helper/ChainlinkWBTCUSDCPriceOracleProxy.sol create mode 100644 contracts/helper/MinimumOracle.sol delete mode 100644 contracts/helper/MultiSigWalletWithTimeLock.sol diff --git a/contracts/helper/ChainlinkCOMPUSDCPriceOracleProxy.sol b/contracts/helper/ChainlinkCOMPUSDCPriceOracleProxy.sol new file mode 100644 index 0000000..6f9bce8 --- /dev/null +++ b/contracts/helper/ChainlinkCOMPUSDCPriceOracleProxy.sol @@ -0,0 +1,25 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + + +interface IChainlink { + function latestAnswer() external view returns (uint256); +} + + +// for COMP-USDC(decimals=6) price convert + +contract ChainlinkCOMPUSDCPriceOracleProxy { + address public chainlink = 0xdbd020CAeF83eFd542f4De03e3cF0C28A4428bd5; + + function getPrice() external view returns (uint256) { + return IChainlink(chainlink).latestAnswer() / 100; + } +} diff --git a/contracts/helper/ChainlinkEthPriceOracleProxy.sol b/contracts/helper/ChainlinkEthPriceOracleProxy.sol index 47a6852..53036a7 100644 --- a/contracts/helper/ChainlinkEthPriceOracleProxy.sol +++ b/contracts/helper/ChainlinkEthPriceOracleProxy.sol @@ -8,14 +8,16 @@ pragma solidity 0.6.9; pragma experimental ABIEncoderV2; + interface IChainlink { function latestAnswer() external view returns (uint256); } + // for WETH-USDC(decimals=6) price convert contract ChainlinkETHPriceOracleProxy { - address public chainlink = 0xF79D6aFBb6dA890132F9D7c355e3015f15F3406F; + address public chainlink = 0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419; function getPrice() external view returns (uint256) { return IChainlink(chainlink).latestAnswer() / 100; diff --git a/contracts/helper/ChainlinkLENDUSDCPriceOracleProxy.sol b/contracts/helper/ChainlinkLENDUSDCPriceOracleProxy.sol new file mode 100644 index 0000000..c338136 --- /dev/null +++ b/contracts/helper/ChainlinkLENDUSDCPriceOracleProxy.sol @@ -0,0 +1,25 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + + +interface IChainlink { + function latestAnswer() external view returns (uint256); +} + + +// for LEND-USDC(decimals=6) price convert + +contract ChainlinkLENDUSDCPriceOracleProxy { + address public chainlink = 0x4aB81192BB75474Cf203B56c36D6a13623270A67; + + function getPrice() external view returns (uint256) { + return IChainlink(chainlink).latestAnswer() / 100; + } +} diff --git a/contracts/helper/ChainlinkLINKUSDPriceOracleProxy.sol b/contracts/helper/ChainlinkLINKUSDPriceOracleProxy.sol new file mode 100644 index 0000000..fe6615d --- /dev/null +++ b/contracts/helper/ChainlinkLINKUSDPriceOracleProxy.sol @@ -0,0 +1,25 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + + +interface IChainlink { + function latestAnswer() external view returns (uint256); +} + + +// for LINK-USDC(decimals=6) price convert + +contract ChainlinkLINKUSDCPriceOracleProxy { + address public chainlink = 0x2c1d072e956AFFC0D435Cb7AC38EF18d24d9127c; + + function getPrice() external view returns (uint256) { + return IChainlink(chainlink).latestAnswer() / 100; + } +} diff --git a/contracts/helper/ChainlinkSNXUSDPriceOracleProxy.sol b/contracts/helper/ChainlinkSNXUSDPriceOracleProxy.sol new file mode 100644 index 0000000..e3d478c --- /dev/null +++ b/contracts/helper/ChainlinkSNXUSDPriceOracleProxy.sol @@ -0,0 +1,25 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + + +interface IChainlink { + function latestAnswer() external view returns (uint256); +} + + +// for SNX-USDC(decimals=6) price convert + +contract ChainlinkSNXUSDCPriceOracleProxy { + address public chainlink = 0xDC3EA94CD0AC27d9A86C180091e7f78C683d3699; + + function getPrice() external view returns (uint256) { + return IChainlink(chainlink).latestAnswer() / 100; + } +} diff --git a/contracts/helper/ChainlinkWBTCUSDCPriceOracleProxy.sol b/contracts/helper/ChainlinkWBTCUSDCPriceOracleProxy.sol new file mode 100644 index 0000000..ae78ebd --- /dev/null +++ b/contracts/helper/ChainlinkWBTCUSDCPriceOracleProxy.sol @@ -0,0 +1,25 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + + +interface IChainlink { + function latestAnswer() external view returns (uint256); +} + + +// for WBTC(decimals=8)-USDC(decimals=6) price convert + +contract ChainlinkWBTCUSDCPriceOracleProxy { + address public chainlink = 0xF4030086522a5bEEa4988F8cA5B36dbC97BeE88c; + + function getPrice() external view returns (uint256) { + return IChainlink(chainlink).latestAnswer() * (10**8); + } +} diff --git a/contracts/helper/MinimumOracle.sol b/contracts/helper/MinimumOracle.sol new file mode 100644 index 0000000..0056add --- /dev/null +++ b/contracts/helper/MinimumOracle.sol @@ -0,0 +1,56 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + + +interface IMinimumOracle { + function getPrice() external view returns (uint256); + + function setPrice(uint256 newPrice) external; + + function transferOwnership(address newOwner) external; +} + + +contract MinimumOracle { + address public _OWNER_; + uint256 public tokenPrice; + + // ============ Events ============ + + event OwnershipTransfer(address indexed previousOwner, address indexed newOwner); + + // ============ Modifiers ============ + + modifier onlyOwner() { + require(msg.sender == _OWNER_, "NOT_OWNER"); + _; + } + + // ============ Functions ============ + + constructor() public { + _OWNER_ = msg.sender; + emit OwnershipTransfer(address(0), _OWNER_); + } + + function transferOwnership(address newOwner) external onlyOwner { + require(newOwner != address(0), "INVALID_OWNER"); + emit OwnershipTransfer(_OWNER_, newOwner); + _OWNER_ = newOwner; + } + + function setPrice(uint256 newPrice) external onlyOwner { + tokenPrice = newPrice; + } + + function getPrice() external view returns (uint256) { + return tokenPrice; + } +} diff --git a/contracts/helper/MultiSigWalletWithTimeLock.sol b/contracts/helper/MultiSigWalletWithTimeLock.sol deleted file mode 100644 index 28af423..0000000 --- a/contracts/helper/MultiSigWalletWithTimeLock.sol +++ /dev/null @@ -1,423 +0,0 @@ -/** - *Submitted for verification at Etherscan.io on 2019-10-15 - */ - -/* - - Copyright 2019 The Hydro Protocol Foundation - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -*/ - -pragma solidity 0.5.8; -pragma experimental ABIEncoderV2; - -contract MultiSigWalletWithTimelock { - uint256 public constant MAX_OWNER_COUNT = 50; - uint256 public lockSeconds = 86400; - - event Confirmation(address indexed sender, uint256 indexed transactionId); - event Revocation(address indexed sender, uint256 indexed transactionId); - event Submission(uint256 indexed transactionId); - event Execution(uint256 indexed transactionId); - event ExecutionFailure(uint256 indexed transactionId); - event Deposit(address indexed sender, uint256 value); - event OwnerAddition(address indexed owner); - event OwnerRemoval(address indexed owner); - event RequirementChange(uint256 required); - event UnlockTimeSet(uint256 indexed transactionId, uint256 confirmationTime); - event LockSecondsChange(uint256 lockSeconds); - - mapping(uint256 => Transaction) public transactions; - mapping(uint256 => mapping(address => bool)) public confirmations; - mapping(address => bool) public isOwner; - mapping(uint256 => uint256) public unlockTimes; - - address[] public owners; - uint256 public required; - uint256 public transactionCount; - - struct Transaction { - address destination; - uint256 value; - bytes data; - bool executed; - } - - struct EmergencyCall { - bytes32 selector; - uint256 paramsBytesCount; - } - - // Functions bypass the time lock process - EmergencyCall[] public emergencyCalls; - - modifier onlyWallet() { - if (msg.sender != address(this)) revert("ONLY_WALLET_ERROR"); - _; - } - - modifier ownerDoesNotExist(address owner) { - if (isOwner[owner]) revert("OWNER_DOES_NOT_EXIST_ERROR"); - _; - } - - modifier ownerExists(address owner) { - if (!isOwner[owner]) revert("OWNER_EXISTS_ERROR"); - _; - } - - modifier transactionExists(uint256 transactionId) { - if (transactions[transactionId].destination == address(0)) - revert("TRANSACTION_EXISTS_ERROR"); - _; - } - - modifier confirmed(uint256 transactionId, address owner) { - if (!confirmations[transactionId][owner]) revert("CONFIRMED_ERROR"); - _; - } - - modifier notConfirmed(uint256 transactionId, address owner) { - if (confirmations[transactionId][owner]) revert("NOT_CONFIRMED_ERROR"); - _; - } - - modifier notExecuted(uint256 transactionId) { - if (transactions[transactionId].executed) revert("NOT_EXECUTED_ERROR"); - _; - } - - modifier notNull(address _address) { - if (_address == address(0)) revert("NOT_NULL_ERROR"); - _; - } - - modifier validRequirement(uint256 ownerCount, uint256 _required) { - if ( - ownerCount > MAX_OWNER_COUNT || - _required > ownerCount || - _required == 0 || - ownerCount == 0 - ) revert("VALID_REQUIREMENT_ERROR"); - _; - } - - /** @dev Fallback function allows to deposit ether. */ - function() external payable { - if (msg.value > 0) { - emit Deposit(msg.sender, msg.value); - } - } - - /** @dev Contract constructor sets initial owners and required number of confirmations. - * @param _owners List of initial owners. - * @param _required Number of required confirmations. - */ - constructor(address[] memory _owners, uint256 _required) - public - validRequirement(_owners.length, _required) - { - for (uint256 i = 0; i < _owners.length; i++) { - if (isOwner[_owners[i]] || _owners[i] == address(0)) { - revert("OWNER_ERROR"); - } - - isOwner[_owners[i]] = true; - } - - owners = _owners; - required = _required; - - // initialzie Emergency calls - emergencyCalls.push( - EmergencyCall({ - selector: keccak256(abi.encodePacked("setMarketBorrowUsability(uint16,bool)")), - paramsBytesCount: 64 - }) - ); - } - - function getEmergencyCallsCount() external view returns (uint256 count) { - return emergencyCalls.length; - } - - /** @dev Allows to add a new owner. Transaction has to be sent by wallet. - * @param owner Address of new owner. - */ - function addOwner(address owner) - external - onlyWallet - ownerDoesNotExist(owner) - notNull(owner) - validRequirement(owners.length + 1, required) - { - isOwner[owner] = true; - owners.push(owner); - emit OwnerAddition(owner); - } - - /** @dev Allows to remove an owner. Transaction has to be sent by wallet. - * @param owner Address of owner. - */ - function removeOwner(address owner) external onlyWallet ownerExists(owner) { - isOwner[owner] = false; - for (uint256 i = 0; i < owners.length - 1; i++) { - if (owners[i] == owner) { - owners[i] = owners[owners.length - 1]; - break; - } - } - - owners.length -= 1; - - if (required > owners.length) { - changeRequirement(owners.length); - } - - emit OwnerRemoval(owner); - } - - /** @dev Allows to replace an owner with a new owner. Transaction has to be sent by wallet. - * @param owner Address of owner to be replaced. - * @param owner Address of new owner. - */ - function replaceOwner(address owner, address newOwner) - external - onlyWallet - ownerExists(owner) - ownerDoesNotExist(newOwner) - { - for (uint256 i = 0; i < owners.length; i++) { - if (owners[i] == owner) { - owners[i] = newOwner; - break; - } - } - - isOwner[owner] = false; - isOwner[newOwner] = true; - emit OwnerRemoval(owner); - emit OwnerAddition(newOwner); - } - - /** @dev Allows to change the number of required confirmations. Transaction has to be sent by wallet. - * @param _required Number of required confirmations. - */ - function changeRequirement(uint256 _required) - public - onlyWallet - validRequirement(owners.length, _required) - { - required = _required; - emit RequirementChange(_required); - } - - /** @dev Changes the duration of the time lock for transactions. - * @param _lockSeconds Duration needed after a transaction is confirmed and before it becomes executable, in seconds. - */ - function changeLockSeconds(uint256 _lockSeconds) external onlyWallet { - lockSeconds = _lockSeconds; - emit LockSecondsChange(_lockSeconds); - } - - /** @dev Allows an owner to submit and confirm a transaction. - * @param destination Transaction target address. - * @param value Transaction ether value. - * @param data Transaction data payload. - * @return Returns transaction ID. - */ - function submitTransaction( - address destination, - uint256 value, - bytes calldata data - ) external ownerExists(msg.sender) notNull(destination) returns (uint256 transactionId) { - transactionId = transactionCount; - transactions[transactionId] = Transaction({ - destination: destination, - value: value, - data: data, - executed: false - }); - transactionCount += 1; - emit Submission(transactionId); - confirmTransaction(transactionId); - } - - /** @dev Allows an owner to confirm a transaction. - * @param transactionId Transaction ID. - */ - function confirmTransaction(uint256 transactionId) - public - ownerExists(msg.sender) - transactionExists(transactionId) - notConfirmed(transactionId, msg.sender) - { - confirmations[transactionId][msg.sender] = true; - emit Confirmation(msg.sender, transactionId); - - if ( - isConfirmed(transactionId) && - unlockTimes[transactionId] == 0 && - !isEmergencyCall(transactionId) - ) { - uint256 unlockTime = block.timestamp + lockSeconds; - unlockTimes[transactionId] = unlockTime; - emit UnlockTimeSet(transactionId, unlockTime); - } - } - - function isEmergencyCall(uint256 transactionId) internal view returns (bool) { - bytes memory data = transactions[transactionId].data; - - for (uint256 i = 0; i < emergencyCalls.length; i++) { - EmergencyCall memory emergencyCall = emergencyCalls[i]; - - if ( - data.length == emergencyCall.paramsBytesCount + 4 && - data.length >= 4 && - emergencyCall.selector[0] == data[0] && - emergencyCall.selector[1] == data[1] && - emergencyCall.selector[2] == data[2] && - emergencyCall.selector[3] == data[3] - ) { - return true; - } - } - - return false; - } - - /** @dev Allows an owner to revoke a confirmation for a transaction. - * @param transactionId Transaction ID. - */ - function revokeConfirmation(uint256 transactionId) - external - ownerExists(msg.sender) - confirmed(transactionId, msg.sender) - notExecuted(transactionId) - { - confirmations[transactionId][msg.sender] = false; - emit Revocation(msg.sender, transactionId); - } - - /** @dev Allows anyone to execute a confirmed transaction. - * @param transactionId Transaction ID. - */ - function executeTransaction(uint256 transactionId) - external - ownerExists(msg.sender) - notExecuted(transactionId) - { - require(block.timestamp >= unlockTimes[transactionId], "TRANSACTION_NEED_TO_UNLOCK"); - - if (isConfirmed(transactionId)) { - Transaction storage transaction = transactions[transactionId]; - transaction.executed = true; - (bool success, ) = transaction.destination.call.value(transaction.value)( - transaction.data - ); - if (success) emit Execution(transactionId); - else { - emit ExecutionFailure(transactionId); - transaction.executed = false; - } - } - } - - /** @dev Returns the confirmation status of a transaction. - * @param transactionId Transaction ID. - * @return Confirmation status. - */ - function isConfirmed(uint256 transactionId) public view returns (bool) { - uint256 count = 0; - - for (uint256 i = 0; i < owners.length; i++) { - if (confirmations[transactionId][owners[i]]) { - count += 1; - } - - if (count >= required) { - return true; - } - } - - return false; - } - - /* Web3 call functions */ - - /** @dev Returns number of confirmations of a transaction. - * @param transactionId Transaction ID. - * @return Number of confirmations. - */ - function getConfirmationCount(uint256 transactionId) external view returns (uint256 count) { - for (uint256 i = 0; i < owners.length; i++) { - if (confirmations[transactionId][owners[i]]) { - count += 1; - } - } - } - - /** @dev Returns total number of transactions after filers are applied. - * @param pending Include pending transactions. - * @param executed Include executed transactions. - * @return Total number of transactions after filters are applied. - */ - function getTransactionCount(bool pending, bool executed) - external - view - returns (uint256 count) - { - for (uint256 i = 0; i < transactionCount; i++) { - if ((pending && !transactions[i].executed) || (executed && transactions[i].executed)) { - count += 1; - } - } - } - - /** @dev Returns list of owners. - * @return List of owner addresses. - */ - function getOwners() external view returns (address[] memory) { - return owners; - } - - /** @dev Returns array with owner addresses, which confirmed transaction. - * @param transactionId Transaction ID. - * @return Returns array of owner addresses. - */ - function getConfirmations(uint256 transactionId) - external - view - returns (address[] memory _confirmations) - { - address[] memory confirmationsTemp = new address[](owners.length); - uint256 count = 0; - uint256 i; - - for (i = 0; i < owners.length; i++) { - if (confirmations[transactionId][owners[i]]) { - confirmationsTemp[count] = owners[i]; - count += 1; - } - } - - _confirmations = new address[](count); - - for (i = 0; i < count; i++) { - _confirmations[i] = confirmationsTemp[i]; - } - } -} From 4bebaa90579aac01b7307d7eebc5a2d6b9e418f6 Mon Sep 17 00:00:00 2001 From: Michael Zhou Date: Mon, 7 Sep 2020 18:08:27 +0800 Subject: [PATCH 072/118] Allow ETH as quote in DODOEthProxy --- contracts/DODOEthProxy.sol | 157 +++++++++++++++++--- test/DODOEthProxy.test.ts | 125 ---------------- test/DODOEthProxyAsBase.test.ts | 232 +++++++++++++++++++++++++++++ test/DODOEthProxyAsQuote.test.ts | 244 +++++++++++++++++++++++++++++++ 4 files changed, 616 insertions(+), 142 deletions(-) delete mode 100644 test/DODOEthProxy.test.ts create mode 100644 test/DODOEthProxyAsBase.test.ts create mode 100644 test/DODOEthProxyAsQuote.test.ts diff --git a/contracts/DODOEthProxy.sol b/contracts/DODOEthProxy.sol index cbabd87..a619be1 100644 --- a/contracts/DODOEthProxy.sol +++ b/contracts/DODOEthProxy.sol @@ -10,45 +10,67 @@ pragma experimental ABIEncoderV2; import {ReentrancyGuard} from "./lib/ReentrancyGuard.sol"; import {SafeERC20} from "./lib/SafeERC20.sol"; +import {SafeMath} from "./lib/SafeMath.sol"; import {IDODO} from "./intf/IDODO.sol"; import {IERC20} from "./intf/IERC20.sol"; import {IWETH} from "./intf/IWETH.sol"; + interface IDODOZoo { function getDODO(address baseToken, address quoteToken) external view returns (address); } + /** * @title DODO Eth Proxy * @author DODO Breeder * - * @notice Handle ETH-WETH converting for users. Use it only when WETH is base token + * @notice Handle ETH-WETH converting for users. */ contract DODOEthProxy is ReentrancyGuard { using SafeERC20 for IERC20; + using SafeMath for uint256; address public _DODO_ZOO_; address payable public _WETH_; // ============ Events ============ - event ProxySellEth( + event ProxySellEthToToken( address indexed seller, address indexed quoteToken, uint256 payEth, - uint256 receiveQuote + uint256 receiveToken ); - event ProxyBuyEth( + event ProxyBuyEthWithToken( address indexed buyer, address indexed quoteToken, uint256 receiveEth, - uint256 payQuote + uint256 payToken ); - event ProxyDepositEth(address indexed lp, address indexed DODO, uint256 ethAmount); + event ProxySellTokenToEth( + address indexed seller, + address indexed baseToken, + uint256 payToken, + uint256 receiveEth + ); - event ProxyWithdrawEth(address indexed lp, address indexed DODO, uint256 ethAmount); + event ProxyBuyTokenWithEth( + address indexed buyer, + address indexed baseToken, + uint256 receiveToken, + uint256 payEth + ); + + event ProxyDepositEthAsBase(address indexed lp, address indexed DODO, uint256 ethAmount); + + event ProxyWithdrawEthAsBase(address indexed lp, address indexed DODO, uint256 ethAmount); + + event ProxyDepositEthAsQuote(address indexed lp, address indexed DODO, uint256 ethAmount); + + event ProxyWithdrawEthAsQuote(address indexed lp, address indexed DODO, uint256 ethAmount); // ============ Functions ============ @@ -65,7 +87,7 @@ contract DODOEthProxy is ReentrancyGuard { require(msg.sender == _WETH_, "WE_SAVED_YOUR_ETH_:)"); } - function sellEthTo( + function sellEthToToken( address quoteTokenAddress, uint256 ethAmount, uint256 minReceiveTokenAmount @@ -77,11 +99,11 @@ contract DODOEthProxy is ReentrancyGuard { IWETH(_WETH_).approve(DODO, ethAmount); receiveTokenAmount = IDODO(DODO).sellBaseToken(ethAmount, minReceiveTokenAmount, ""); _transferOut(quoteTokenAddress, msg.sender, receiveTokenAmount); - emit ProxySellEth(msg.sender, quoteTokenAddress, ethAmount, receiveTokenAmount); + emit ProxySellEthToToken(msg.sender, quoteTokenAddress, ethAmount, receiveTokenAmount); return receiveTokenAmount; } - function buyEthWith( + function buyEthWithToken( address quoteTokenAddress, uint256 ethAmount, uint256 maxPayTokenAmount @@ -94,11 +116,48 @@ contract DODOEthProxy is ReentrancyGuard { IDODO(DODO).buyBaseToken(ethAmount, maxPayTokenAmount, ""); IWETH(_WETH_).withdraw(ethAmount); msg.sender.transfer(ethAmount); - emit ProxyBuyEth(msg.sender, quoteTokenAddress, ethAmount, payTokenAmount); + emit ProxyBuyEthWithToken(msg.sender, quoteTokenAddress, ethAmount, payTokenAmount); return payTokenAmount; } - function depositEth(uint256 ethAmount, address quoteTokenAddress) + function sellTokenToEth( + address baseTokenAddress, + uint256 tokenAmount, + uint256 minReceiveEthAmount + ) external preventReentrant returns (uint256 receiveEthAmount) { + address DODO = IDODOZoo(_DODO_ZOO_).getDODO(baseTokenAddress, _WETH_); + require(DODO != address(0), "DODO_NOT_EXIST"); + IERC20(baseTokenAddress).approve(DODO, tokenAmount); + _transferIn(baseTokenAddress, msg.sender, tokenAmount); + receiveEthAmount = IDODO(DODO).sellBaseToken(tokenAmount, minReceiveEthAmount, ""); + IWETH(_WETH_).withdraw(receiveEthAmount); + msg.sender.transfer(receiveEthAmount); + emit ProxySellTokenToEth(msg.sender, baseTokenAddress, tokenAmount, receiveEthAmount); + return receiveEthAmount; + } + + function buyTokenWithEth( + address baseTokenAddress, + uint256 tokenAmount, + uint256 maxPayEthAmount + ) external payable preventReentrant returns (uint256 payEthAmount) { + require(msg.value == maxPayEthAmount, "ETH_AMOUNT_NOT_MATCH"); + address DODO = IDODOZoo(_DODO_ZOO_).getDODO(baseTokenAddress, _WETH_); + require(DODO != address(0), "DODO_NOT_EXIST"); + payEthAmount = IDODO(DODO).queryBuyBaseToken(tokenAmount); + IWETH(_WETH_).deposit{value: payEthAmount}(); + IWETH(_WETH_).approve(DODO, payEthAmount); + IDODO(DODO).buyBaseToken(tokenAmount, maxPayEthAmount, ""); + _transferOut(baseTokenAddress, msg.sender, tokenAmount); + uint256 refund = maxPayEthAmount.sub(payEthAmount); + if (refund > 0) { + msg.sender.transfer(refund); + } + emit ProxyBuyTokenWithEth(msg.sender, baseTokenAddress, tokenAmount, payEthAmount); + return payEthAmount; + } + + function depositEthAsBase(uint256 ethAmount, address quoteTokenAddress) external payable preventReentrant @@ -109,10 +168,10 @@ contract DODOEthProxy is ReentrancyGuard { IWETH(_WETH_).deposit{value: ethAmount}(); IWETH(_WETH_).approve(DODO, ethAmount); IDODO(DODO).depositBaseTo(msg.sender, ethAmount); - emit ProxyDepositEth(msg.sender, DODO, ethAmount); + emit ProxyDepositEthAsBase(msg.sender, DODO, ethAmount); } - function withdrawEth(uint256 ethAmount, address quoteTokenAddress) + function withdrawEthAsBase(uint256 ethAmount, address quoteTokenAddress) external preventReentrant returns (uint256 withdrawAmount) @@ -135,11 +194,11 @@ contract DODOEthProxy is ReentrancyGuard { uint256 wethAmount = IERC20(_WETH_).balanceOf(address(this)); IWETH(_WETH_).withdraw(wethAmount); msg.sender.transfer(wethAmount); - emit ProxyWithdrawEth(msg.sender, DODO, wethAmount); + emit ProxyWithdrawEthAsBase(msg.sender, DODO, wethAmount); return wethAmount; } - function withdrawAllEth(address quoteTokenAddress) + function withdrawAllEthAsBase(address quoteTokenAddress) external preventReentrant returns (uint256 withdrawAmount) @@ -158,7 +217,71 @@ contract DODOEthProxy is ReentrancyGuard { uint256 wethAmount = IERC20(_WETH_).balanceOf(address(this)); IWETH(_WETH_).withdraw(wethAmount); msg.sender.transfer(wethAmount); - emit ProxyWithdrawEth(msg.sender, DODO, wethAmount); + emit ProxyWithdrawEthAsBase(msg.sender, DODO, wethAmount); + return wethAmount; + } + + function depositEthAsQuote(uint256 ethAmount, address baseTokenAddress) + external + payable + preventReentrant + { + require(msg.value == ethAmount, "ETH_AMOUNT_NOT_MATCH"); + address DODO = IDODOZoo(_DODO_ZOO_).getDODO(baseTokenAddress, _WETH_); + require(DODO != address(0), "DODO_NOT_EXIST"); + IWETH(_WETH_).deposit{value: ethAmount}(); + IWETH(_WETH_).approve(DODO, ethAmount); + IDODO(DODO).depositQuoteTo(msg.sender, ethAmount); + emit ProxyDepositEthAsQuote(msg.sender, DODO, ethAmount); + } + + function withdrawEthAsQuote(uint256 ethAmount, address baseTokenAddress) + external + preventReentrant + returns (uint256 withdrawAmount) + { + address DODO = IDODOZoo(_DODO_ZOO_).getDODO(baseTokenAddress, _WETH_); + require(DODO != address(0), "DODO_NOT_EXIST"); + address ethLpToken = IDODO(DODO)._QUOTE_CAPITAL_TOKEN_(); + + // transfer all pool shares to proxy + uint256 lpBalance = IERC20(ethLpToken).balanceOf(msg.sender); + IERC20(ethLpToken).transferFrom(msg.sender, address(this), lpBalance); + IDODO(DODO).withdrawQuote(ethAmount); + + // transfer remain shares back to msg.sender + lpBalance = IERC20(ethLpToken).balanceOf(address(this)); + IERC20(ethLpToken).transfer(msg.sender, lpBalance); + + // because of withdraw penalty, withdrawAmount may not equal to ethAmount + // query weth amount first and than transfer ETH to msg.sender + uint256 wethAmount = IERC20(_WETH_).balanceOf(address(this)); + IWETH(_WETH_).withdraw(wethAmount); + msg.sender.transfer(wethAmount); + emit ProxyWithdrawEthAsQuote(msg.sender, DODO, wethAmount); + return wethAmount; + } + + function withdrawAllEthAsQuote(address baseTokenAddress) + external + preventReentrant + returns (uint256 withdrawAmount) + { + address DODO = IDODOZoo(_DODO_ZOO_).getDODO(baseTokenAddress, _WETH_); + require(DODO != address(0), "DODO_NOT_EXIST"); + address ethLpToken = IDODO(DODO)._QUOTE_CAPITAL_TOKEN_(); + + // transfer all pool shares to proxy + uint256 lpBalance = IERC20(ethLpToken).balanceOf(msg.sender); + IERC20(ethLpToken).transferFrom(msg.sender, address(this), lpBalance); + IDODO(DODO).withdrawAllQuote(); + + // because of withdraw penalty, withdrawAmount may not equal to ethAmount + // query weth amount first and than transfer ETH to msg.sender + uint256 wethAmount = IERC20(_WETH_).balanceOf(address(this)); + IWETH(_WETH_).withdraw(wethAmount); + msg.sender.transfer(wethAmount); + emit ProxyWithdrawEthAsQuote(msg.sender, DODO, wethAmount); return wethAmount; } diff --git a/test/DODOEthProxy.test.ts b/test/DODOEthProxy.test.ts deleted file mode 100644 index 2bd6302..0000000 --- a/test/DODOEthProxy.test.ts +++ /dev/null @@ -1,125 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -import { DODOContext, getDODOContext, DefaultDODOContextInitConfig } from './utils/Context'; -import * as contracts from "./utils/Contracts"; -import * as assert from "assert" -import { decimalStr, MAX_UINT256 } from './utils/Converter'; -import { Contract } from "web3-eth-contract"; -import { logGas } from './utils/Log'; - -let lp: string -let trader: string -let DODOEthProxy: Contract - -async function init(ctx: DODOContext): Promise { - // switch ctx to eth proxy mode - let WETH = await contracts.newContract(contracts.WETH_CONTRACT_NAME) - await ctx.DODOZoo.methods.breedDODO( - ctx.Maintainer, - WETH.options.address, - ctx.QUOTE.options.address, - ctx.ORACLE.options.address, - DefaultDODOContextInitConfig.lpFeeRate, - DefaultDODOContextInitConfig.mtFeeRate, - DefaultDODOContextInitConfig.k, - DefaultDODOContextInitConfig.gasPriceLimit - ).send(ctx.sendParam(ctx.Deployer)) - - ctx.DODO = await contracts.getContractWithAddress(contracts.DODO_CONTRACT_NAME, await ctx.DODOZoo.methods.getDODO(WETH.options.address, ctx.QUOTE.options.address).call()) - - ctx.BASE = WETH - ctx.BaseCapital = await contracts.getContractWithAddress(contracts.DODO_LP_TOKEN_CONTRACT_NAME, await ctx.DODO.methods._BASE_CAPITAL_TOKEN_().call()) - - DODOEthProxy = await contracts.newContract(contracts.DODO_ETH_PROXY_CONTRACT_NAME, [ctx.DODOZoo.options.address, WETH.options.address]) - - // env - lp = ctx.spareAccounts[0] - trader = ctx.spareAccounts[1] - await ctx.setOraclePrice(decimalStr("100")) - await ctx.approveDODO(lp) - await ctx.approveDODO(trader) - - await ctx.QUOTE.methods.mint(lp, decimalStr("1000")).send(ctx.sendParam(ctx.Deployer)) - await ctx.QUOTE.methods.mint(trader, decimalStr("1000")).send(ctx.sendParam(ctx.Deployer)) - await ctx.QUOTE.methods.approve(DODOEthProxy.options.address, MAX_UINT256).send(ctx.sendParam(trader)) - - await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp)) -} - -describe("DODO ETH PROXY", () => { - - let snapshotId: string - let ctx: DODOContext - - before(async () => { - ctx = await getDODOContext() - await init(ctx) - await ctx.QUOTE.methods.approve(DODOEthProxy.options.address, MAX_UINT256).send(ctx.sendParam(trader)) - }) - - beforeEach(async () => { - snapshotId = await ctx.EVM.snapshot(); - let depositAmount = "10" - await DODOEthProxy.methods.depositEth(decimalStr(depositAmount), ctx.QUOTE.options.address).send(ctx.sendParam(lp, depositAmount)) - }); - - afterEach(async () => { - await ctx.EVM.reset(snapshotId) - }); - - describe("buy&sell eth directly", () => { - it("buy", async () => { - let buyAmount = "1" - logGas(await DODOEthProxy.methods.buyEthWith(ctx.QUOTE.options.address, decimalStr(buyAmount), decimalStr("200")).send(ctx.sendParam(trader)), "buy with eth directly") - assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("8.999")) - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "898581839502056240973") - ctx.Web3 - }) - it("sell", async () => { - let sellAmount = "1" - logGas(await DODOEthProxy.methods.sellEthTo(ctx.QUOTE.options.address, decimalStr(sellAmount), decimalStr("50")).send(ctx.sendParam(trader, sellAmount)), "sell to eth directly") - assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("11")) - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1098617454226610630663") - }) - }) - - describe("withdraw eth directly", () => { - it("withdraw", async () => { - let baseLpTokenAddress = await ctx.DODO.methods._BASE_CAPITAL_TOKEN_().call() - let baseLpToken = contracts.getContractWithAddress(contracts.TEST_ERC20_CONTRACT_NAME, baseLpTokenAddress) - await baseLpToken.methods.approve(DODOEthProxy.options.address, MAX_UINT256).send(ctx.sendParam(lp)) - await DODOEthProxy.methods.withdrawEth(decimalStr("5"), ctx.QUOTE.options.address).send(ctx.sendParam(lp)) - - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp).call(), decimalStr("5")) - // console.log(await ctx.Web3.eth.getBalance(lp)) eth balance confirmed - }) - - it("withdraw all", async () => { - let baseLpTokenAddress = await ctx.DODO.methods._BASE_CAPITAL_TOKEN_().call() - let baseLpToken = contracts.getContractWithAddress(contracts.TEST_ERC20_CONTRACT_NAME, baseLpTokenAddress) - await baseLpToken.methods.approve(DODOEthProxy.options.address, MAX_UINT256).send(ctx.sendParam(lp)) - await DODOEthProxy.methods.withdrawAllEth(ctx.QUOTE.options.address).send(ctx.sendParam(lp)) - - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp).call(), "0") - // console.log(await ctx.Web3.eth.getBalance(lp)) eth balance confirmed - }) - }) - - describe("revert cases", () => { - it("value not match", async () => { - await assert.rejects( - DODOEthProxy.methods.sellEthTo(ctx.QUOTE.options.address, decimalStr("1"), decimalStr("50")).send(ctx.sendParam(trader, "2")), - /ETH_AMOUNT_NOT_MATCH/ - ) - await assert.rejects( - DODOEthProxy.methods.depositEth(decimalStr("1"), ctx.QUOTE.options.address).send(ctx.sendParam(lp, "2")), - /ETH_AMOUNT_NOT_MATCH/ - ) - }) - }) -}) \ No newline at end of file diff --git a/test/DODOEthProxyAsBase.test.ts b/test/DODOEthProxyAsBase.test.ts new file mode 100644 index 0000000..010ed7b --- /dev/null +++ b/test/DODOEthProxyAsBase.test.ts @@ -0,0 +1,232 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ +import * as assert from 'assert'; +import { BigNumber } from 'bignumber.js'; +import { TransactionReceipt } from 'web3-core'; +import { Contract } from 'web3-eth-contract'; + +import { + DefaultDODOContextInitConfig, + DODOContext, + getDODOContext, +} from './utils/Context'; +import * as contracts from './utils/Contracts'; +import { decimalStr, MAX_UINT256 } from './utils/Converter'; +import { logGas } from './utils/Log'; + +let lp: string; +let trader: string; +let DODOEthProxy: Contract; + +async function init(ctx: DODOContext): Promise { + // switch ctx to eth proxy mode + const WETH = await contracts.newContract(contracts.WETH_CONTRACT_NAME); + await ctx.DODOZoo.methods + .breedDODO( + ctx.Maintainer, + WETH.options.address, + ctx.QUOTE.options.address, + ctx.ORACLE.options.address, + DefaultDODOContextInitConfig.lpFeeRate, + DefaultDODOContextInitConfig.mtFeeRate, + DefaultDODOContextInitConfig.k, + DefaultDODOContextInitConfig.gasPriceLimit + ) + .send(ctx.sendParam(ctx.Deployer)); + + ctx.DODO = contracts.getContractWithAddress( + contracts.DODO_CONTRACT_NAME, + await ctx.DODOZoo.methods + .getDODO(WETH.options.address, ctx.QUOTE.options.address) + .call() + ); + + ctx.BASE = WETH; + + DODOEthProxy = await contracts.newContract( + contracts.DODO_ETH_PROXY_CONTRACT_NAME, + [ctx.DODOZoo.options.address, WETH.options.address] + ); + + // env + lp = ctx.spareAccounts[0]; + trader = ctx.spareAccounts[1]; + await ctx.setOraclePrice(decimalStr("100")); + await ctx.approveDODO(lp); + await ctx.approveDODO(trader); + + await ctx.QUOTE.methods + .mint(lp, decimalStr("1000")) + .send(ctx.sendParam(ctx.Deployer)); + await ctx.QUOTE.methods + .mint(trader, decimalStr("1000")) + .send(ctx.sendParam(ctx.Deployer)); + await ctx.QUOTE.methods + .approve(DODOEthProxy.options.address, MAX_UINT256) + .send(ctx.sendParam(trader)); + + await ctx.DODO.methods + .depositQuote(decimalStr("1000")) + .send(ctx.sendParam(lp)); +} + +describe("DODO ETH PROXY", () => { + let snapshotId: string; + let ctx: DODOContext; + + before(async () => { + ctx = await getDODOContext(); + await init(ctx); + await ctx.QUOTE.methods + .approve(DODOEthProxy.options.address, MAX_UINT256) + .send(ctx.sendParam(trader)); + }); + + beforeEach(async () => { + snapshotId = await ctx.EVM.snapshot(); + const depositAmount = "10"; + await DODOEthProxy.methods + .depositEthAsBase(decimalStr(depositAmount), ctx.QUOTE.options.address) + .send(ctx.sendParam(lp, depositAmount)); + }); + + afterEach(async () => { + await ctx.EVM.reset(snapshotId); + }); + + describe("buy&sell eth directly", () => { + it("buy", async () => { + const buyAmount = "1"; + logGas( + await DODOEthProxy.methods + .buyEthWithToken( + ctx.QUOTE.options.address, + decimalStr(buyAmount), + decimalStr("200") + ) + .send(ctx.sendParam(trader)), + "buy ETH with token directly" + ); + assert.strictEqual( + await ctx.DODO.methods._BASE_BALANCE_().call(), + decimalStr("8.999") + ); + assert.strictEqual( + await ctx.QUOTE.methods.balanceOf(trader).call(), + "898581839502056240973" + ); + }); + it("sell", async () => { + const sellAmount = "1"; + logGas( + await DODOEthProxy.methods + .sellEthToToken( + ctx.QUOTE.options.address, + decimalStr(sellAmount), + decimalStr("50") + ) + .send(ctx.sendParam(trader, sellAmount)), + "sell ETH to token directly" + ); + assert.strictEqual( + await ctx.DODO.methods._BASE_BALANCE_().call(), + decimalStr("11") + ); + assert.strictEqual( + await ctx.QUOTE.methods.balanceOf(trader).call(), + "1098617454226610630663" + ); + }); + }); + + describe("withdraw eth directly", () => { + it("withdraw", async () => { + const withdrawAmount = decimalStr("5"); + const baseLpTokenAddress = await ctx.DODO.methods + ._BASE_CAPITAL_TOKEN_() + .call(); + const baseLpToken = contracts.getContractWithAddress( + contracts.TEST_ERC20_CONTRACT_NAME, + baseLpTokenAddress + ); + await baseLpToken.methods + .approve(DODOEthProxy.options.address, MAX_UINT256) + .send(ctx.sendParam(lp)); + const lpEthBalanceBefore = await ctx.Web3.eth.getBalance(lp); + const txReceipt: TransactionReceipt = await DODOEthProxy.methods + .withdrawEthAsBase(withdrawAmount, ctx.QUOTE.options.address) + .send(ctx.sendParam(lp)); + + assert.strictEqual( + await ctx.DODO.methods.getLpBaseBalance(lp).call(), + withdrawAmount + ); + const tx = await ctx.Web3.eth.getTransaction(txReceipt.transactionHash); + const ethSpentOnGas = new BigNumber(tx.gasPrice).times(txReceipt.gasUsed); + const lpEthBalanceAfter = await ctx.Web3.eth.getBalance(lp); + assert.ok( + new BigNumber(lpEthBalanceBefore) + .plus(withdrawAmount) + .minus(ethSpentOnGas) + .eq(lpEthBalanceAfter) + ); + }); + + it("withdraw all", async () => { + const withdrawAmount = decimalStr("10"); + const baseLpTokenAddress = await ctx.DODO.methods + ._BASE_CAPITAL_TOKEN_() + .call(); + const baseLpToken = contracts.getContractWithAddress( + contracts.TEST_ERC20_CONTRACT_NAME, + baseLpTokenAddress + ); + await baseLpToken.methods + .approve(DODOEthProxy.options.address, MAX_UINT256) + .send(ctx.sendParam(lp)); + const lpEthBalanceBefore = await ctx.Web3.eth.getBalance(lp); + const txReceipt: TransactionReceipt = await DODOEthProxy.methods + .withdrawAllEthAsBase(ctx.QUOTE.options.address) + .send(ctx.sendParam(lp)); + + assert.strictEqual( + await ctx.DODO.methods.getLpBaseBalance(lp).call(), + "0" + ); + const tx = await ctx.Web3.eth.getTransaction(txReceipt.transactionHash); + const ethSpentOnGas = new BigNumber(tx.gasPrice).times(txReceipt.gasUsed); + const lpEthBalanceAfter = await ctx.Web3.eth.getBalance(lp); + assert.ok( + new BigNumber(lpEthBalanceBefore) + .plus(withdrawAmount) + .minus(ethSpentOnGas) + .eq(lpEthBalanceAfter) + ); + }); + }); + + describe("revert cases", () => { + it("value not match", async () => { + await assert.rejects( + DODOEthProxy.methods + .sellEthToToken( + ctx.QUOTE.options.address, + decimalStr("1"), + decimalStr("50") + ) + .send(ctx.sendParam(trader, "2")), + /ETH_AMOUNT_NOT_MATCH/ + ); + await assert.rejects( + DODOEthProxy.methods + .depositEthAsBase(decimalStr("1"), ctx.QUOTE.options.address) + .send(ctx.sendParam(lp, "2")), + /ETH_AMOUNT_NOT_MATCH/ + ); + }); + }); +}); diff --git a/test/DODOEthProxyAsQuote.test.ts b/test/DODOEthProxyAsQuote.test.ts new file mode 100644 index 0000000..985a8b4 --- /dev/null +++ b/test/DODOEthProxyAsQuote.test.ts @@ -0,0 +1,244 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ +import * as assert from 'assert'; +import BigNumber from 'bignumber.js'; +import { TransactionReceipt } from 'web3-core'; +import { Contract } from 'web3-eth-contract'; + +import { + DefaultDODOContextInitConfig, + DODOContext, + getDODOContext, +} from './utils/Context'; +import * as contracts from './utils/Contracts'; +import { decimalStr, MAX_UINT256 } from './utils/Converter'; +import { logGas } from './utils/Log'; + +let lp: string; +let trader: string; +let DODOEthProxy: Contract; + +async function init(ctx: DODOContext): Promise { + // switch ctx to eth proxy mode + const WETH = await contracts.newContract(contracts.WETH_CONTRACT_NAME); + await ctx.DODOZoo.methods + .breedDODO( + ctx.Maintainer, + ctx.BASE.options.address, + WETH.options.address, + ctx.ORACLE.options.address, + DefaultDODOContextInitConfig.lpFeeRate, + DefaultDODOContextInitConfig.mtFeeRate, + DefaultDODOContextInitConfig.k, + DefaultDODOContextInitConfig.gasPriceLimit + ) + .send(ctx.sendParam(ctx.Deployer)); + + ctx.DODO = contracts.getContractWithAddress( + contracts.DODO_CONTRACT_NAME, + await ctx.DODOZoo.methods + .getDODO(ctx.BASE.options.address, WETH.options.address) + .call() + ); + + ctx.QUOTE = WETH; + + DODOEthProxy = await contracts.newContract( + contracts.DODO_ETH_PROXY_CONTRACT_NAME, + [ctx.DODOZoo.options.address, WETH.options.address] + ); + + // env + lp = ctx.spareAccounts[0]; + trader = ctx.spareAccounts[1]; + await ctx.setOraclePrice(decimalStr("0.01")); + await ctx.approveDODO(lp); + await ctx.approveDODO(trader); + + await ctx.BASE.methods + .mint(lp, decimalStr("1000")) + .send(ctx.sendParam(ctx.Deployer)); + await ctx.BASE.methods + .mint(trader, decimalStr("1000")) + .send(ctx.sendParam(ctx.Deployer)); + await ctx.BASE.methods + .approve(DODOEthProxy.options.address, MAX_UINT256) + .send(ctx.sendParam(trader)); + + await ctx.DODO.methods + .depositBase(decimalStr("1000")) + .send(ctx.sendParam(lp)); +} + +describe("DODO ETH PROXY", () => { + let snapshotId: string; + let ctx: DODOContext; + + before(async () => { + ctx = await getDODOContext(); + await init(ctx); + await ctx.BASE.methods + .approve(DODOEthProxy.options.address, MAX_UINT256) + .send(ctx.sendParam(trader)); + }); + + beforeEach(async () => { + snapshotId = await ctx.EVM.snapshot(); + let depositAmount = "10"; + await DODOEthProxy.methods + .depositEthAsQuote(decimalStr(depositAmount), ctx.BASE.options.address) + .send(ctx.sendParam(lp, depositAmount)); + }); + + afterEach(async () => { + await ctx.EVM.reset(snapshotId); + }); + + describe("buy&sell eth directly", () => { + it("buy", async () => { + const maxPayEthAmount = "2.1"; + const ethInPoolBefore = decimalStr("10"); + const traderEthBalanceBefore = await ctx.Web3.eth.getBalance(trader); + const txReceipt: TransactionReceipt = await DODOEthProxy.methods + .buyTokenWithEth( + ctx.BASE.options.address, + decimalStr("200"), + decimalStr(maxPayEthAmount) + ) + .send(ctx.sendParam(trader, maxPayEthAmount)); + logGas(txReceipt, "buy token with ETH directly"); + const ethInPoolAfter = "12056338203652739553"; + assert.strictEqual( + await ctx.DODO.methods._QUOTE_BALANCE_().call(), + ethInPoolAfter + ); + assert.strictEqual( + await ctx.BASE.methods.balanceOf(trader).call(), + decimalStr("1200") + ); + const tx = await ctx.Web3.eth.getTransaction(txReceipt.transactionHash); + const ethSpentOnGas = new BigNumber(tx.gasPrice).times(txReceipt.gasUsed); + const traderEthBalanceAfter = await ctx.Web3.eth.getBalance(trader); + + const totalEthBefore = new BigNumber(traderEthBalanceBefore).plus( + ethInPoolBefore + ); + const totalEthAfter = new BigNumber(traderEthBalanceAfter) + .plus(ethSpentOnGas) + .plus(ethInPoolAfter); + assert.ok(totalEthBefore.eq(totalEthAfter)); + }); + it("sell", async () => { + const minReceiveEthAmount = "0.45"; + logGas( + await DODOEthProxy.methods + .sellTokenToEth( + ctx.BASE.options.address, + decimalStr("50"), + decimalStr(minReceiveEthAmount) + ) + .send(ctx.sendParam(trader)), + "sell token to ETH directly" + ); + assert.strictEqual( + await ctx.DODO.methods._QUOTE_BALANCE_().call(), + "9503598324131652490" + ); + assert.strictEqual( + await ctx.BASE.methods.balanceOf(trader).call(), + decimalStr("950") + ); + }); + }); + + describe("withdraw eth directly", () => { + it("withdraw", async () => { + const withdrawAmount = decimalStr("5"); + const quoteLpTokenAddress = await ctx.DODO.methods + ._QUOTE_CAPITAL_TOKEN_() + .call(); + const quoteLpToken = contracts.getContractWithAddress( + contracts.TEST_ERC20_CONTRACT_NAME, + quoteLpTokenAddress + ); + await quoteLpToken.methods + .approve(DODOEthProxy.options.address, MAX_UINT256) + .send(ctx.sendParam(lp)); + const lpEthBalanceBefore = await ctx.Web3.eth.getBalance(lp); + const txReceipt: TransactionReceipt = await DODOEthProxy.methods + .withdrawEthAsQuote(withdrawAmount, ctx.BASE.options.address) + .send(ctx.sendParam(lp)); + + assert.strictEqual( + await ctx.DODO.methods.getLpQuoteBalance(lp).call(), + withdrawAmount + ); + const tx = await ctx.Web3.eth.getTransaction(txReceipt.transactionHash); + const ethSpentOnGas = new BigNumber(tx.gasPrice).times(txReceipt.gasUsed); + const lpEthBalanceAfter = await ctx.Web3.eth.getBalance(lp); + assert.ok( + new BigNumber(lpEthBalanceBefore) + .plus(withdrawAmount) + .minus(ethSpentOnGas) + .eq(lpEthBalanceAfter) + ); + }); + + it("withdraw all", async () => { + const withdrawAmount = decimalStr("10"); + const quoteLpTokenAddress = await ctx.DODO.methods + ._QUOTE_CAPITAL_TOKEN_() + .call(); + const quoteLpToken = contracts.getContractWithAddress( + contracts.TEST_ERC20_CONTRACT_NAME, + quoteLpTokenAddress + ); + await quoteLpToken.methods + .approve(DODOEthProxy.options.address, MAX_UINT256) + .send(ctx.sendParam(lp)); + const lpEthBalanceBefore = await ctx.Web3.eth.getBalance(lp); + const txReceipt: TransactionReceipt = await DODOEthProxy.methods + .withdrawAllEthAsQuote(ctx.BASE.options.address) + .send(ctx.sendParam(lp)); + + assert.strictEqual( + await ctx.DODO.methods.getLpQuoteBalance(lp).call(), + "0" + ); + const tx = await ctx.Web3.eth.getTransaction(txReceipt.transactionHash); + const ethSpentOnGas = new BigNumber(tx.gasPrice).times(txReceipt.gasUsed); + const lpEthBalanceAfter = await ctx.Web3.eth.getBalance(lp); + assert.ok( + new BigNumber(lpEthBalanceBefore) + .plus(withdrawAmount) + .minus(ethSpentOnGas) + .eq(lpEthBalanceAfter) + ); + }); + }); + + describe("revert cases", () => { + it("value not match", async () => { + await assert.rejects( + DODOEthProxy.methods + .buyTokenWithEth( + ctx.BASE.options.address, + decimalStr("50"), + decimalStr("1") + ) + .send(ctx.sendParam(trader, "2")), + /ETH_AMOUNT_NOT_MATCH/ + ); + await assert.rejects( + DODOEthProxy.methods + .depositEthAsQuote(decimalStr("1"), ctx.BASE.options.address) + .send(ctx.sendParam(lp, "2")), + /ETH_AMOUNT_NOT_MATCH/ + ); + }); + }); +}); From 2e637f0916198121ff776aa2fbeede64919624e2 Mon Sep 17 00:00:00 2001 From: mingda Date: Tue, 8 Sep 2020 20:09:31 +0800 Subject: [PATCH 073/118] use safe erc20 & new logGas --- contracts/DODOEthProxy.sol | 6 ++---- contracts/lib/SafeERC20.sol | 16 ++++++++++++++++ test/DODOEthProxyAsBase.test.ts | 16 ++++++++-------- test/DODOEthProxyAsQuote.test.ts | 14 ++++++-------- test/utils/Log.ts | 9 +++++---- 5 files changed, 37 insertions(+), 24 deletions(-) diff --git a/contracts/DODOEthProxy.sol b/contracts/DODOEthProxy.sol index a619be1..aebaa52 100644 --- a/contracts/DODOEthProxy.sol +++ b/contracts/DODOEthProxy.sol @@ -15,12 +15,10 @@ import {IDODO} from "./intf/IDODO.sol"; import {IERC20} from "./intf/IERC20.sol"; import {IWETH} from "./intf/IWETH.sol"; - interface IDODOZoo { function getDODO(address baseToken, address quoteToken) external view returns (address); } - /** * @title DODO Eth Proxy * @author DODO Breeder @@ -112,7 +110,7 @@ contract DODOEthProxy is ReentrancyGuard { require(DODO != address(0), "DODO_NOT_EXIST"); payTokenAmount = IDODO(DODO).queryBuyBaseToken(ethAmount); _transferIn(quoteTokenAddress, msg.sender, payTokenAmount); - IERC20(quoteTokenAddress).approve(DODO, payTokenAmount); + IERC20(quoteTokenAddress).safeApprove(DODO, payTokenAmount); IDODO(DODO).buyBaseToken(ethAmount, maxPayTokenAmount, ""); IWETH(_WETH_).withdraw(ethAmount); msg.sender.transfer(ethAmount); @@ -127,7 +125,7 @@ contract DODOEthProxy is ReentrancyGuard { ) external preventReentrant returns (uint256 receiveEthAmount) { address DODO = IDODOZoo(_DODO_ZOO_).getDODO(baseTokenAddress, _WETH_); require(DODO != address(0), "DODO_NOT_EXIST"); - IERC20(baseTokenAddress).approve(DODO, tokenAmount); + IERC20(baseTokenAddress).safeApprove(DODO, tokenAmount); _transferIn(baseTokenAddress, msg.sender, tokenAmount); receiveEthAmount = IDODO(DODO).sellBaseToken(tokenAmount, minReceiveEthAmount, ""); IWETH(_WETH_).withdraw(receiveEthAmount); diff --git a/contracts/lib/SafeERC20.sol b/contracts/lib/SafeERC20.sol index 09440bf..67a0188 100644 --- a/contracts/lib/SafeERC20.sol +++ b/contracts/lib/SafeERC20.sol @@ -45,6 +45,22 @@ library SafeERC20 { ); } + function safeApprove( + IERC20 token, + address spender, + uint256 value + ) internal { + // safeApprove should only be called when setting an initial allowance, + // or when resetting it to zero. To increase and decrease it, use + // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' + // solhint-disable-next-line max-line-length + require( + (value == 0) || (token.allowance(address(this), spender) == 0), + "SafeERC20: approve from non-zero to non-zero allowance" + ); + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); + } + /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). diff --git a/test/DODOEthProxyAsBase.test.ts b/test/DODOEthProxyAsBase.test.ts index 010ed7b..e72babc 100644 --- a/test/DODOEthProxyAsBase.test.ts +++ b/test/DODOEthProxyAsBase.test.ts @@ -101,14 +101,14 @@ describe("DODO ETH PROXY", () => { describe("buy&sell eth directly", () => { it("buy", async () => { const buyAmount = "1"; - logGas( - await DODOEthProxy.methods + await logGas( + DODOEthProxy.methods .buyEthWithToken( ctx.QUOTE.options.address, decimalStr(buyAmount), decimalStr("200") - ) - .send(ctx.sendParam(trader)), + ), + ctx.sendParam(trader), "buy ETH with token directly" ); assert.strictEqual( @@ -122,14 +122,14 @@ describe("DODO ETH PROXY", () => { }); it("sell", async () => { const sellAmount = "1"; - logGas( - await DODOEthProxy.methods + await logGas( + DODOEthProxy.methods .sellEthToToken( ctx.QUOTE.options.address, decimalStr(sellAmount), decimalStr("50") - ) - .send(ctx.sendParam(trader, sellAmount)), + ), + ctx.sendParam(trader, sellAmount), "sell ETH to token directly" ); assert.strictEqual( diff --git a/test/DODOEthProxyAsQuote.test.ts b/test/DODOEthProxyAsQuote.test.ts index 985a8b4..04b1932 100644 --- a/test/DODOEthProxyAsQuote.test.ts +++ b/test/DODOEthProxyAsQuote.test.ts @@ -103,14 +103,12 @@ describe("DODO ETH PROXY", () => { const maxPayEthAmount = "2.1"; const ethInPoolBefore = decimalStr("10"); const traderEthBalanceBefore = await ctx.Web3.eth.getBalance(trader); - const txReceipt: TransactionReceipt = await DODOEthProxy.methods + const txReceipt: TransactionReceipt = await logGas(DODOEthProxy.methods .buyTokenWithEth( ctx.BASE.options.address, decimalStr("200"), decimalStr(maxPayEthAmount) - ) - .send(ctx.sendParam(trader, maxPayEthAmount)); - logGas(txReceipt, "buy token with ETH directly"); + ), ctx.sendParam(trader, maxPayEthAmount), "buy token with ETH directly"); const ethInPoolAfter = "12056338203652739553"; assert.strictEqual( await ctx.DODO.methods._QUOTE_BALANCE_().call(), @@ -134,14 +132,14 @@ describe("DODO ETH PROXY", () => { }); it("sell", async () => { const minReceiveEthAmount = "0.45"; - logGas( - await DODOEthProxy.methods + await logGas( + DODOEthProxy.methods .sellTokenToEth( ctx.BASE.options.address, decimalStr("50"), decimalStr(minReceiveEthAmount) - ) - .send(ctx.sendParam(trader)), + ), + ctx.sendParam(trader), "sell token to ETH directly" ); assert.strictEqual( diff --git a/test/utils/Log.ts b/test/utils/Log.ts index c2bc65d..7e7c3b7 100644 --- a/test/utils/Log.ts +++ b/test/utils/Log.ts @@ -5,15 +5,15 @@ */ -import { TransactionReceipt } from "web3-core" - export const blueText = x => `\x1b[36m${x}\x1b[0m`; export const yellowText = x => `\x1b[33m${x}\x1b[0m`; export const greenText = x => `\x1b[32m${x}\x1b[0m`; export const redText = x => `\x1b[31m${x}\x1b[0m`; export const numberWithCommas = x => x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); -export function logGas(receipt: TransactionReceipt, desc: string) { +export async function logGas(funcCall: any, params: any, desc: string) { + const estimatedGas = await funcCall.estimateGas(params) + const receipt = await funcCall.send(params) const gasUsed = receipt.gasUsed; let colorFn; @@ -25,5 +25,6 @@ export function logGas(receipt: TransactionReceipt, desc: string) { colorFn = redText; } - console.log(("Gas used:").padEnd(60, '.'), blueText(desc) + " ", colorFn(numberWithCommas(gasUsed).padStart(5))); + console.log(("Gas estimated:" + numberWithCommas(estimatedGas)).padEnd(60, '.'), blueText(desc) + " ", colorFn(numberWithCommas(gasUsed).padStart(5))); + return receipt } \ No newline at end of file From 06e4f00c9b23d99039708488986ba7dd7e6815e6 Mon Sep 17 00:00:00 2001 From: mingda Date: Tue, 8 Sep 2020 20:17:18 +0800 Subject: [PATCH 074/118] oracles --- ...l => ChainlinkEthUSDCPriceOracleProxy.sol} | 0 .../ChainlinkEthUSDTPriceOracleProxy.sol | 25 +++++++++++++++ .../ChainlinkYFIUSDCPriceOracleProxy.sol | 32 +++++++++++++++++++ 3 files changed, 57 insertions(+) rename contracts/helper/{ChainlinkEthPriceOracleProxy.sol => ChainlinkEthUSDCPriceOracleProxy.sol} (100%) create mode 100644 contracts/helper/ChainlinkEthUSDTPriceOracleProxy.sol create mode 100644 contracts/helper/ChainlinkYFIUSDCPriceOracleProxy.sol diff --git a/contracts/helper/ChainlinkEthPriceOracleProxy.sol b/contracts/helper/ChainlinkEthUSDCPriceOracleProxy.sol similarity index 100% rename from contracts/helper/ChainlinkEthPriceOracleProxy.sol rename to contracts/helper/ChainlinkEthUSDCPriceOracleProxy.sol diff --git a/contracts/helper/ChainlinkEthUSDTPriceOracleProxy.sol b/contracts/helper/ChainlinkEthUSDTPriceOracleProxy.sol new file mode 100644 index 0000000..6d27f7a --- /dev/null +++ b/contracts/helper/ChainlinkEthUSDTPriceOracleProxy.sol @@ -0,0 +1,25 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + + +interface IChainlink { + function latestAnswer() external view returns (uint256); +} + + +// for WETH-USDT(decimals=6) price convert + +contract ChainlinkETHUSDTPriceOracleProxy { + address public chainlink = 0xEe9F2375b4bdF6387aa8265dD4FB8F16512A1d46; + + function getPrice() external view returns (uint256) { + return 10**24 / IChainlink(chainlink).latestAnswer(); + } +} diff --git a/contracts/helper/ChainlinkYFIUSDCPriceOracleProxy.sol b/contracts/helper/ChainlinkYFIUSDCPriceOracleProxy.sol new file mode 100644 index 0000000..b2d071d --- /dev/null +++ b/contracts/helper/ChainlinkYFIUSDCPriceOracleProxy.sol @@ -0,0 +1,32 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {SafeMath} from "../lib/SafeMath.sol"; + + +interface IChainlink { + function latestAnswer() external view returns (uint256); +} + + +// for YFI-USDC(decimals=6) price convert + +contract ChainlinkYFIUSDCPriceOracleProxy { + using SafeMath for uint256; + + address public yfiEth = 0x7c5d4F8345e66f68099581Db340cd65B078C41f4; + address public EthUsd = 0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419; + + function getPrice() external view returns (uint256) { + uint256 yfiEthPrice = IChainlink(yfiEth).latestAnswer(); + uint256 EthUsdPrice = IChainlink(EthUsd).latestAnswer(); + return yfiEthPrice.mul(EthUsdPrice).div(10**20); + } +} From e3ce9758e5201472235ecf9f3edcb587266ce92e Mon Sep 17 00:00:00 2001 From: Michael Zhou Date: Tue, 8 Sep 2020 20:25:59 +0800 Subject: [PATCH 075/118] Fix tests Use the new logGas. --- test/LiquidityProvider.test.ts | 1014 ++++++++++++++++++++++--------- test/Trader.test.ts | 662 +++++++++++++++----- test/UniswapArbitrageur.test.ts | 180 ++++-- 3 files changed, 1362 insertions(+), 494 deletions(-) diff --git a/test/LiquidityProvider.test.ts b/test/LiquidityProvider.test.ts index fb149e2..6ba239b 100644 --- a/test/LiquidityProvider.test.ts +++ b/test/LiquidityProvider.test.ts @@ -5,453 +5,921 @@ */ +import * as assert from 'assert'; + import { DODOContext, getDODOContext } from './utils/Context'; import { decimalStr } from './utils/Converter'; import { logGas } from './utils/Log'; -import * as assert from "assert" -let lp1: string -let lp2: string -let trader: string +let lp1: string; +let lp2: string; +let trader: string; async function init(ctx: DODOContext): Promise { - await ctx.setOraclePrice(decimalStr("100")) - lp1 = ctx.spareAccounts[0] - lp2 = ctx.spareAccounts[1] - trader = ctx.spareAccounts[2] - await ctx.mintTestToken(lp1, decimalStr("100"), decimalStr("10000")) - await ctx.mintTestToken(lp2, decimalStr("100"), decimalStr("10000")) - await ctx.mintTestToken(trader, decimalStr("100"), decimalStr("10000")) - await ctx.approveDODO(lp1) - await ctx.approveDODO(lp2) - await ctx.approveDODO(trader) + await ctx.setOraclePrice(decimalStr("100")); + lp1 = ctx.spareAccounts[0]; + lp2 = ctx.spareAccounts[1]; + trader = ctx.spareAccounts[2]; + await ctx.mintTestToken(lp1, decimalStr("100"), decimalStr("10000")); + await ctx.mintTestToken(lp2, decimalStr("100"), decimalStr("10000")); + await ctx.mintTestToken(trader, decimalStr("100"), decimalStr("10000")); + await ctx.approveDODO(lp1); + await ctx.approveDODO(lp2); + await ctx.approveDODO(trader); } describe("LiquidityProvider", () => { - - let snapshotId: string - let ctx: DODOContext + let snapshotId: string; + let ctx: DODOContext; before(async () => { - ctx = await getDODOContext() + ctx = await getDODOContext(); await init(ctx); - }) + }); beforeEach(async () => { snapshotId = await ctx.EVM.snapshot(); }); afterEach(async () => { - await ctx.EVM.reset(snapshotId) + await ctx.EVM.reset(snapshotId); }); describe("R equals to ONE", () => { it("multi lp deposit & withdraw", async () => { - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), decimalStr("0")) - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), decimalStr("0")) + assert.equal( + await ctx.DODO.methods.getLpBaseBalance(lp1).call(), + decimalStr("0") + ); + assert.equal( + await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), + decimalStr("0") + ); - logGas(await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)), "deposit base") - assert.equal(await ctx.BASE.methods.balanceOf(lp1).call(), decimalStr("90")) - logGas(await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)), "deposit quote") - assert.equal(await ctx.QUOTE.methods.balanceOf(lp1).call(), decimalStr("9000")) + await logGas( + ctx.DODO.methods.depositBase(decimalStr("10")), + ctx.sendParam(lp1), + "deposit base" + ); + assert.equal( + await ctx.BASE.methods.balanceOf(lp1).call(), + decimalStr("90") + ); + await logGas( + ctx.DODO.methods.depositQuote(decimalStr("1000")), + ctx.sendParam(lp1), + "deposit quote" + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(lp1).call(), + decimalStr("9000") + ); - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), decimalStr("10")) - assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("10")) - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), decimalStr("1000")) - assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), decimalStr("1000")) + assert.equal( + await ctx.DODO.methods.getLpBaseBalance(lp1).call(), + decimalStr("10") + ); + assert.equal( + await ctx.DODO.methods._BASE_BALANCE_().call(), + decimalStr("10") + ); + assert.equal( + await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), + decimalStr("1000") + ); + assert.equal( + await ctx.DODO.methods._QUOTE_BALANCE_().call(), + decimalStr("1000") + ); - await ctx.DODO.methods.depositBase(decimalStr("3")).send(ctx.sendParam(lp2)) - await ctx.DODO.methods.depositQuote(decimalStr("70")).send(ctx.sendParam(lp2)) + await ctx.DODO.methods + .depositBase(decimalStr("3")) + .send(ctx.sendParam(lp2)); + await ctx.DODO.methods + .depositQuote(decimalStr("70")) + .send(ctx.sendParam(lp2)); - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), decimalStr("10")) - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), decimalStr("1000")) - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp2).call(), decimalStr("3")) - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp2).call(), decimalStr("70")) - assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("13")) - assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), decimalStr("1070")) + assert.equal( + await ctx.DODO.methods.getLpBaseBalance(lp1).call(), + decimalStr("10") + ); + assert.equal( + await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), + decimalStr("1000") + ); + assert.equal( + await ctx.DODO.methods.getLpBaseBalance(lp2).call(), + decimalStr("3") + ); + assert.equal( + await ctx.DODO.methods.getLpQuoteBalance(lp2).call(), + decimalStr("70") + ); + assert.equal( + await ctx.DODO.methods._BASE_BALANCE_().call(), + decimalStr("13") + ); + assert.equal( + await ctx.DODO.methods._QUOTE_BALANCE_().call(), + decimalStr("1070") + ); - await ctx.DODO.methods.withdrawBase(decimalStr("5")).send(ctx.sendParam(lp1)) - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), decimalStr("5")) - assert.equal(await ctx.BASE.methods.balanceOf(lp1).call(), decimalStr("95")) - await ctx.DODO.methods.withdrawQuote(decimalStr("100")).send(ctx.sendParam(lp1)) - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), decimalStr("900")) - assert.equal(await ctx.QUOTE.methods.balanceOf(lp1).call(), decimalStr("9100")) + await ctx.DODO.methods + .withdrawBase(decimalStr("5")) + .send(ctx.sendParam(lp1)); + assert.equal( + await ctx.DODO.methods.getLpBaseBalance(lp1).call(), + decimalStr("5") + ); + assert.equal( + await ctx.BASE.methods.balanceOf(lp1).call(), + decimalStr("95") + ); + await ctx.DODO.methods + .withdrawQuote(decimalStr("100")) + .send(ctx.sendParam(lp1)); + assert.equal( + await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), + decimalStr("900") + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(lp1).call(), + decimalStr("9100") + ); - await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp1)) - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "0") - assert.equal(await ctx.BASE.methods.balanceOf(lp1).call(), decimalStr("100")) - await ctx.DODO.methods.withdrawAllQuote().send(ctx.sendParam(lp1)) - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), "0") - assert.equal(await ctx.QUOTE.methods.balanceOf(lp1).call(), decimalStr("10000")) - }) - }) + await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp1)); + assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "0"); + assert.equal( + await ctx.BASE.methods.balanceOf(lp1).call(), + decimalStr("100") + ); + await ctx.DODO.methods.withdrawAllQuote().send(ctx.sendParam(lp1)); + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), "0"); + assert.equal( + await ctx.QUOTE.methods.balanceOf(lp1).call(), + decimalStr("10000") + ); + }); + }); describe("R is ABOVE ONE", () => { it("deposit", async () => { - await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x").send(ctx.sendParam(trader)) + await ctx.DODO.methods + .depositBase(decimalStr("10")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .depositQuote(decimalStr("1000")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x") + .send(ctx.sendParam(trader)); - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "10010841132009222923") - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), decimalStr("1000")) + assert.equal( + await ctx.DODO.methods.getLpBaseBalance(lp1).call(), + "10010841132009222923" + ); + assert.equal( + await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), + decimalStr("1000") + ); - await ctx.DODO.methods.depositBase(decimalStr("5")).send(ctx.sendParam(lp2)) - await ctx.DODO.methods.depositQuote(decimalStr("100")).send(ctx.sendParam(lp2)) + await ctx.DODO.methods + .depositBase(decimalStr("5")) + .send(ctx.sendParam(lp2)); + await ctx.DODO.methods + .depositQuote(decimalStr("100")) + .send(ctx.sendParam(lp2)); // lp1 & lp2 would both have profit because the curve becomes flatter // but the withdraw penalty is greater than this free profit - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "10163234422929069723") - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), decimalStr("1000")) + assert.equal( + await ctx.DODO.methods.getLpBaseBalance(lp1).call(), + "10163234422929069723" + ); + assert.equal( + await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), + decimalStr("1000") + ); - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp2).call(), "5076114129127759292") - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp2).call(), decimalStr("100")) + assert.equal( + await ctx.DODO.methods.getLpBaseBalance(lp2).call(), + "5076114129127759292" + ); + assert.equal( + await ctx.DODO.methods.getLpQuoteBalance(lp2).call(), + decimalStr("100") + ); - assert.equal(await ctx.DODO.methods.getWithdrawBasePenalty(decimalStr("5")).call(), "228507420047606093") - assert.equal(await ctx.DODO.methods.getWithdrawQuotePenalty(decimalStr("100")).call(), "0") - }) + assert.equal( + await ctx.DODO.methods.getWithdrawBasePenalty(decimalStr("5")).call(), + "228507420047606093" + ); + assert.equal( + await ctx.DODO.methods + .getWithdrawQuotePenalty(decimalStr("100")) + .call(), + "0" + ); + }); it("withdraw", async () => { - await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x").send(ctx.sendParam(trader)) + await ctx.DODO.methods + .depositBase(decimalStr("10")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .depositQuote(decimalStr("1000")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x") + .send(ctx.sendParam(trader)); - assert.equal(await ctx.DODO.methods.getWithdrawBasePenalty(decimalStr("4")).call(), "1065045389392391665") - assert.equal(await ctx.DODO.methods.getWithdrawQuotePenalty(decimalStr("100")).call(), "0") + assert.equal( + await ctx.DODO.methods.getWithdrawBasePenalty(decimalStr("4")).call(), + "1065045389392391665" + ); + assert.equal( + await ctx.DODO.methods + .getWithdrawQuotePenalty(decimalStr("100")) + .call(), + "0" + ); - await ctx.DODO.methods.withdrawBase(decimalStr("4")).send(ctx.sendParam(lp1)) - assert.equal(await ctx.BASE.methods.balanceOf(lp1).call(), "92934954610607608335") - assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), "2060045389392391665") - assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "7075045389392391665") + await ctx.DODO.methods + .withdrawBase(decimalStr("4")) + .send(ctx.sendParam(lp1)); + assert.equal( + await ctx.BASE.methods.balanceOf(lp1).call(), + "92934954610607608335" + ); + assert.equal( + await ctx.DODO.methods._BASE_BALANCE_().call(), + "2060045389392391665" + ); + assert.equal( + await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), + "7075045389392391665" + ); - await ctx.DODO.methods.withdrawQuote(decimalStr("100")).send(ctx.sendParam(lp1)) - assert.equal(await ctx.QUOTE.methods.balanceOf(lp1).call(), decimalStr("9100")) - assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "1451951805416248746119") - assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), decimalStr("900")) - }) - }) + await ctx.DODO.methods + .withdrawQuote(decimalStr("100")) + .send(ctx.sendParam(lp1)); + assert.equal( + await ctx.QUOTE.methods.balanceOf(lp1).call(), + decimalStr("9100") + ); + assert.equal( + await ctx.DODO.methods._QUOTE_BALANCE_().call(), + "1451951805416248746119" + ); + assert.equal( + await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), + decimalStr("900") + ); + }); + }); describe("R is BELOW ONE", () => { it("deposit", async () => { - await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("200"), "0x").send(ctx.sendParam(trader)) + await ctx.DODO.methods + .depositBase(decimalStr("10")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .depositQuote(decimalStr("1000")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .sellBaseToken(decimalStr("5"), decimalStr("200"), "0x") + .send(ctx.sendParam(trader)); - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), decimalStr("10")) - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), "1000978629616255276996") + assert.equal( + await ctx.DODO.methods.getLpBaseBalance(lp1).call(), + decimalStr("10") + ); + assert.equal( + await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), + "1000978629616255276996" + ); - await ctx.DODO.methods.depositQuote(decimalStr("500")).send(ctx.sendParam(lp2)) - await ctx.DODO.methods.depositBase(decimalStr("5")).send(ctx.sendParam(lp2)) + await ctx.DODO.methods + .depositQuote(decimalStr("500")) + .send(ctx.sendParam(lp2)); + await ctx.DODO.methods + .depositBase(decimalStr("5")) + .send(ctx.sendParam(lp2)); - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), decimalStr("10")) - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), "1012529270910521756641") + assert.equal( + await ctx.DODO.methods.getLpBaseBalance(lp1).call(), + decimalStr("10") + ); + assert.equal( + await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), + "1012529270910521756641" + ); - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp2).call(), decimalStr("5")) - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp2).call(), "505769674273013522654") + assert.equal( + await ctx.DODO.methods.getLpBaseBalance(lp2).call(), + decimalStr("5") + ); + assert.equal( + await ctx.DODO.methods.getLpQuoteBalance(lp2).call(), + "505769674273013522654" + ); - assert.equal(await ctx.DODO.methods.getWithdrawBasePenalty(decimalStr("5")).call(), "0") - assert.equal(await ctx.DODO.methods.getWithdrawQuotePenalty(decimalStr("500")).call(), "17320315567280002300") - }) + assert.equal( + await ctx.DODO.methods.getWithdrawBasePenalty(decimalStr("5")).call(), + "0" + ); + assert.equal( + await ctx.DODO.methods + .getWithdrawQuotePenalty(decimalStr("500")) + .call(), + "17320315567280002300" + ); + }); it("withdraw", async () => { - await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("200"), "0x").send(ctx.sendParam(trader)) + await ctx.DODO.methods + .depositBase(decimalStr("10")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .depositQuote(decimalStr("1000")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .sellBaseToken(decimalStr("5"), decimalStr("200"), "0x") + .send(ctx.sendParam(trader)); - assert.equal(await ctx.DODO.methods.getWithdrawBasePenalty(decimalStr("4")).call(), "0") - assert.equal(await ctx.DODO.methods.getWithdrawQuotePenalty(decimalStr("100")).call(), "7389428846238900753") + assert.equal( + await ctx.DODO.methods.getWithdrawBasePenalty(decimalStr("4")).call(), + "0" + ); + assert.equal( + await ctx.DODO.methods + .getWithdrawQuotePenalty(decimalStr("100")) + .call(), + "7389428846238900753" + ); - await ctx.DODO.methods.withdrawQuote(decimalStr("100")).send(ctx.sendParam(lp1)) - assert.equal(await ctx.QUOTE.methods.balanceOf(lp1).call(), "9092610571153761099247") - assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "447655402437037253588") - assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), "908310739520405637520") + await ctx.DODO.methods + .withdrawQuote(decimalStr("100")) + .send(ctx.sendParam(lp1)); + assert.equal( + await ctx.QUOTE.methods.balanceOf(lp1).call(), + "9092610571153761099247" + ); + assert.equal( + await ctx.DODO.methods._QUOTE_BALANCE_().call(), + "447655402437037253588" + ); + assert.equal( + await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), + "908310739520405637520" + ); - await ctx.DODO.methods.withdrawBase(decimalStr("4")).send(ctx.sendParam(lp1)) - assert.equal(await ctx.BASE.methods.balanceOf(lp1).call(), decimalStr("94")) - assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("11")) - assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), decimalStr("6")) - }) - }) + await ctx.DODO.methods + .withdrawBase(decimalStr("4")) + .send(ctx.sendParam(lp1)); + assert.equal( + await ctx.BASE.methods.balanceOf(lp1).call(), + decimalStr("94") + ); + assert.equal( + await ctx.DODO.methods._BASE_BALANCE_().call(), + decimalStr("11") + ); + assert.equal( + await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), + decimalStr("6") + ); + }); + }); describe("Oracle changes", () => { it("base side lp don't has pnl when R is BELOW ONE", async () => { - await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("200"), "0x").send(ctx.sendParam(trader)) + await ctx.DODO.methods + .depositBase(decimalStr("10")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .depositQuote(decimalStr("1000")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .sellBaseToken(decimalStr("5"), decimalStr("200"), "0x") + .send(ctx.sendParam(trader)); await ctx.setOraclePrice(decimalStr("80")); - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), decimalStr("10")) - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), "914362409397559037208") + assert.equal( + await ctx.DODO.methods.getLpBaseBalance(lp1).call(), + decimalStr("10") + ); + assert.equal( + await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), + "914362409397559037208" + ); - await ctx.setOraclePrice(decimalStr("120")) + await ctx.setOraclePrice(decimalStr("120")); - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), decimalStr("10")) - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), "1085284653936129406317") - }) + assert.equal( + await ctx.DODO.methods.getLpBaseBalance(lp1).call(), + decimalStr("10") + ); + assert.equal( + await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), + "1085284653936129406317" + ); + }); it("quote side lp don't has pnl when R is ABOVE ONE", async () => { - await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("600"), "0x").send(ctx.sendParam(trader)) + await ctx.DODO.methods + .depositBase(decimalStr("10")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .depositQuote(decimalStr("1000")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .buyBaseToken(decimalStr("5"), decimalStr("600"), "0x") + .send(ctx.sendParam(trader)); await ctx.setOraclePrice(decimalStr("80")); - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "11138732839027528597") - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), decimalStr("1000")) + assert.equal( + await ctx.DODO.methods.getLpBaseBalance(lp1).call(), + "11138732839027528597" + ); + assert.equal( + await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), + decimalStr("1000") + ); - await ctx.setOraclePrice(decimalStr("120")) + await ctx.setOraclePrice(decimalStr("120")); - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "9234731968726215588") - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), decimalStr("1000")) - }) - - }) + assert.equal( + await ctx.DODO.methods.getLpBaseBalance(lp1).call(), + "9234731968726215588" + ); + assert.equal( + await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), + decimalStr("1000") + ); + }); + }); describe("Transfer lp token", () => { it("transfer", async () => { - await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods + .depositBase(decimalStr("10")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .depositQuote(decimalStr("1000")) + .send(ctx.sendParam(lp1)); - await ctx.BaseCapital.methods.transfer(lp2, decimalStr("5")).send(ctx.sendParam(lp1)) - await ctx.QuoteCapital.methods.transfer(lp2, decimalStr("5")).send(ctx.sendParam(lp1)) + await ctx.BaseCapital.methods + .transfer(lp2, decimalStr("5")) + .send(ctx.sendParam(lp1)); + await ctx.QuoteCapital.methods + .transfer(lp2, decimalStr("5")) + .send(ctx.sendParam(lp1)); - await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp2)) - await ctx.DODO.methods.withdrawAllQuote().send(ctx.sendParam(lp2)) + await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp2)); + await ctx.DODO.methods.withdrawAllQuote().send(ctx.sendParam(lp2)); - assert.equal(await ctx.BASE.methods.balanceOf(lp2).call(), decimalStr("105")) - assert.equal(await ctx.QUOTE.methods.balanceOf(lp2).call(), decimalStr("10005")) - }) - }) + assert.equal( + await ctx.BASE.methods.balanceOf(lp2).call(), + decimalStr("105") + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(lp2).call(), + decimalStr("10005") + ); + }); + }); describe("Deposit & transfer to other account", () => { it("base token", async () => { - await ctx.DODO.methods.depositBaseTo(lp2, decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.withdrawBaseTo(trader, decimalStr("5")).send(ctx.sendParam(lp2)) - await ctx.DODO.methods.withdrawAllBaseTo(ctx.Supervisor).send(ctx.sendParam(lp2)) + await ctx.DODO.methods + .depositBaseTo(lp2, decimalStr("10")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .withdrawBaseTo(trader, decimalStr("5")) + .send(ctx.sendParam(lp2)); + await ctx.DODO.methods + .withdrawAllBaseTo(ctx.Supervisor) + .send(ctx.sendParam(lp2)); - assert.equal(await ctx.BASE.methods.balanceOf(lp1).call(), decimalStr("90")) - assert.equal(await ctx.BASE.methods.balanceOf(lp2).call(), decimalStr("100")) - assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("105")) - assert.equal(await ctx.BASE.methods.balanceOf(ctx.Supervisor).call(), decimalStr("5")) - }) + assert.equal( + await ctx.BASE.methods.balanceOf(lp1).call(), + decimalStr("90") + ); + assert.equal( + await ctx.BASE.methods.balanceOf(lp2).call(), + decimalStr("100") + ); + assert.equal( + await ctx.BASE.methods.balanceOf(trader).call(), + decimalStr("105") + ); + assert.equal( + await ctx.BASE.methods.balanceOf(ctx.Supervisor).call(), + decimalStr("5") + ); + }); it("quote token", async () => { - await ctx.DODO.methods.depositQuoteTo(lp2, decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.withdrawQuoteTo(trader, decimalStr("500")).send(ctx.sendParam(lp2)) - await ctx.DODO.methods.withdrawAllQuoteTo(ctx.Supervisor).send(ctx.sendParam(lp2)) + await ctx.DODO.methods + .depositQuoteTo(lp2, decimalStr("1000")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .withdrawQuoteTo(trader, decimalStr("500")) + .send(ctx.sendParam(lp2)); + await ctx.DODO.methods + .withdrawAllQuoteTo(ctx.Supervisor) + .send(ctx.sendParam(lp2)); - assert.equal(await ctx.QUOTE.methods.balanceOf(lp1).call(), decimalStr("9000")) - assert.equal(await ctx.QUOTE.methods.balanceOf(lp2).call(), decimalStr("10000")) - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), decimalStr("10500")) - assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Supervisor).call(), decimalStr("500")) - }) - }) + assert.equal( + await ctx.QUOTE.methods.balanceOf(lp1).call(), + decimalStr("9000") + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(lp2).call(), + decimalStr("10000") + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(trader).call(), + decimalStr("10500") + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(ctx.Supervisor).call(), + decimalStr("500") + ); + }); + }); describe("Corner cases", () => { it("single side deposit", async () => { - await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x").send(ctx.sendParam(trader)) - await ctx.DODO.methods.sellBaseToken("5015841132009222923", decimalStr("0"), "0x").send(ctx.sendParam(trader)) + await ctx.DODO.methods + .depositBase(decimalStr("10")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x") + .send(ctx.sendParam(trader)); + await ctx.DODO.methods + .sellBaseToken("5015841132009222923", decimalStr("0"), "0x") + .send(ctx.sendParam(trader)); - assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0") - assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "10010841132009222923") - assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), "1103903610832497492") + assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0"); + assert.equal( + await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), + "10010841132009222923" + ); + assert.equal( + await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), + "1103903610832497492" + ); - await ctx.DODO.methods.depositQuote("1").send(ctx.sendParam(lp2)) + await ctx.DODO.methods.depositQuote("1").send(ctx.sendParam(lp2)); - assert.equal(await ctx.DODO.methods.getQuoteCapitalBalanceOf(lp2).call(), "1103903610832497493") - }) + assert.equal( + await ctx.DODO.methods.getQuoteCapitalBalanceOf(lp2).call(), + "1103903610832497493" + ); + }); it("single side deposit & lp deposit when R isn't equal to ONE", async () => { - await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x").send(ctx.sendParam(trader)) + await ctx.DODO.methods + .depositBase(decimalStr("10")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x") + .send(ctx.sendParam(trader)); - await ctx.DODO.methods.depositQuote("1").send(ctx.sendParam(lp2)) + await ctx.DODO.methods.depositQuote("1").send(ctx.sendParam(lp2)); - assert.equal(await ctx.DODO.methods.getQuoteCapitalBalanceOf(lp2).call(), "1") - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp2).call(), "1") - }) + assert.equal( + await ctx.DODO.methods.getQuoteCapitalBalanceOf(lp2).call(), + "1" + ); + assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp2).call(), "1"); + }); it("single side deposit (base) & oracle change introduces loss", async () => { - await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x").send(ctx.sendParam(trader)) + await ctx.DODO.methods + .depositBase(decimalStr("10")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x") + .send(ctx.sendParam(trader)); - await ctx.setOraclePrice(decimalStr("120")) - await ctx.DODO.methods.sellBaseToken(decimalStr("4"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) - await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) + await ctx.setOraclePrice(decimalStr("120")); + await ctx.DODO.methods + .sellBaseToken(decimalStr("4"), decimalStr("0"), "0x") + .send(ctx.sendParam(trader)); + await ctx.DODO.methods + .sellBaseToken(decimalStr("1"), decimalStr("0"), "0x") + .send(ctx.sendParam(trader)); - assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "2") - assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "9234731968726215603") - assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), "1105993618321025490") + assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "2"); + assert.equal( + await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), + "9234731968726215603" + ); + assert.equal( + await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), + "1105993618321025490" + ); - await ctx.DODO.methods.depositQuote("1").send(ctx.sendParam(lp2)) - assert.equal(await ctx.DODO.methods.getQuoteCapitalBalanceOf(lp2).call(), "7221653398290521828") - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp2).call(), "7221653398290521884") - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "9234731968726215603") - }) + await ctx.DODO.methods.depositQuote("1").send(ctx.sendParam(lp2)); + assert.equal( + await ctx.DODO.methods.getQuoteCapitalBalanceOf(lp2).call(), + "7221653398290521828" + ); + assert.equal( + await ctx.DODO.methods.getLpQuoteBalance(lp2).call(), + "7221653398290521884" + ); + assert.equal( + await ctx.DODO.methods.getLpBaseBalance(lp1).call(), + "9234731968726215603" + ); + }); it("single side deposit (base) & oracle change introduces profit", async () => { - await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x").send(ctx.sendParam(trader)) + await ctx.DODO.methods + .depositBase(decimalStr("10")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x") + .send(ctx.sendParam(trader)); - await ctx.setOraclePrice(decimalStr("80")) - await ctx.DODO.methods.sellBaseToken(decimalStr("4"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) - await ctx.DODO.methods.sellBaseToken(decimalStr("4"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) + await ctx.setOraclePrice(decimalStr("80")); + await ctx.DODO.methods + .sellBaseToken(decimalStr("4"), decimalStr("0"), "0x") + .send(ctx.sendParam(trader)); + await ctx.DODO.methods + .sellBaseToken(decimalStr("4"), decimalStr("0"), "0x") + .send(ctx.sendParam(trader)); - assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "2") - assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "11138732839027528584") - assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), "1105408308382702868") + assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "2"); + assert.equal( + await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), + "11138732839027528584" + ); + assert.equal( + await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), + "1105408308382702868" + ); - await ctx.DODO.methods.depositQuote("1").send(ctx.sendParam(lp2)) - assert.equal(await ctx.DODO.methods.getQuoteCapitalBalanceOf(lp2).call(), "21553269260529319669") - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp2).call(), "21553269260529319697") - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "11138732839027528584") - }) + await ctx.DODO.methods.depositQuote("1").send(ctx.sendParam(lp2)); + assert.equal( + await ctx.DODO.methods.getQuoteCapitalBalanceOf(lp2).call(), + "21553269260529319669" + ); + assert.equal( + await ctx.DODO.methods.getLpQuoteBalance(lp2).call(), + "21553269260529319697" + ); + assert.equal( + await ctx.DODO.methods.getLpBaseBalance(lp1).call(), + "11138732839027528584" + ); + }); it("single side deposit (quote) & oracle change introduces loss", async () => { - await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) + await ctx.DODO.methods + .depositQuote(decimalStr("1000")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .sellBaseToken(decimalStr("5"), decimalStr("0"), "0x") + .send(ctx.sendParam(trader)); - await ctx.setOraclePrice(decimalStr("80")) - await ctx.DODO.methods.buyBaseToken(decimalStr("4"), decimalStr("600"), "0x").send(ctx.sendParam(trader)) - await ctx.DODO.methods.buyBaseToken(decimalStr("0.99"), decimalStr("500"), "0x").send(ctx.sendParam(trader)) + await ctx.setOraclePrice(decimalStr("80")); + await ctx.DODO.methods + .buyBaseToken(decimalStr("4"), decimalStr("600"), "0x") + .send(ctx.sendParam(trader)); + await ctx.DODO.methods + .buyBaseToken(decimalStr("0.99"), decimalStr("500"), "0x") + .send(ctx.sendParam(trader)); - assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "1") - assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "9980000000000000") - assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), "914362409397559035414") + assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "1"); + assert.equal( + await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), + "9980000000000000" + ); + assert.equal( + await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), + "914362409397559035414" + ); - await ctx.DODO.methods.depositBase("1").send(ctx.sendParam(lp2)) - assert.equal(await ctx.DODO.methods.getBaseCapitalBalanceOf(lp2).call(), "10247647352975730") - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp2).call(), "10247647352975730") - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), "914362409397559035414") - }) + await ctx.DODO.methods.depositBase("1").send(ctx.sendParam(lp2)); + assert.equal( + await ctx.DODO.methods.getBaseCapitalBalanceOf(lp2).call(), + "10247647352975730" + ); + assert.equal( + await ctx.DODO.methods.getLpBaseBalance(lp2).call(), + "10247647352975730" + ); + assert.equal( + await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), + "914362409397559035414" + ); + }); it("deposit and withdraw immediately", async () => { - await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x").send(ctx.sendParam(trader)) + await ctx.DODO.methods + .depositBase(decimalStr("10")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x") + .send(ctx.sendParam(trader)); - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "10010841132009222923") + assert.equal( + await ctx.DODO.methods.getLpBaseBalance(lp1).call(), + "10010841132009222923" + ); - await ctx.DODO.methods.depositBase(decimalStr("5")).send(ctx.sendParam(lp2)) + await ctx.DODO.methods + .depositBase(decimalStr("5")) + .send(ctx.sendParam(lp2)); - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "10163234422929069723") - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp2).call(), "5076114129127759292") + assert.equal( + await ctx.DODO.methods.getLpBaseBalance(lp1).call(), + "10163234422929069723" + ); + assert.equal( + await ctx.DODO.methods.getLpBaseBalance(lp2).call(), + "5076114129127759292" + ); - await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp2)) + await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp2)); - assert.equal(await ctx.BASE.methods.balanceOf(lp2).call(), "99841132414635941792") - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "10182702153814588648") - }) - }) + assert.equal( + await ctx.BASE.methods.balanceOf(lp2).call(), + "99841132414635941792" + ); + assert.equal( + await ctx.DODO.methods.getLpBaseBalance(lp1).call(), + "10182702153814588648" + ); + }); + }); describe("Revert cases", () => { it("withdraw base amount exceeds DODO balance", async () => { - await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x").send(ctx.sendParam(trader)) + await ctx.DODO.methods + .depositBase(decimalStr("10")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x") + .send(ctx.sendParam(trader)); await assert.rejects( ctx.DODO.methods.withdrawBase(decimalStr("6")).send(ctx.sendParam(lp1)), /DODO_BASE_BALANCE_NOT_ENOUGH/ - ) + ); await assert.rejects( ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp1)), /DODO_BASE_BALANCE_NOT_ENOUGH/ - ) - }) + ); + }); it("withdraw quote amount exceeds DODO balance", async () => { - await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) + await ctx.DODO.methods + .depositQuote(decimalStr("1000")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .sellBaseToken(decimalStr("5"), decimalStr("0"), "0x") + .send(ctx.sendParam(trader)); await assert.rejects( - ctx.DODO.methods.withdrawQuote(decimalStr("600")).send(ctx.sendParam(lp1)), + ctx.DODO.methods + .withdrawQuote(decimalStr("600")) + .send(ctx.sendParam(lp1)), /DODO_QUOTE_BALANCE_NOT_ENOUGH/ - ) + ); await assert.rejects( ctx.DODO.methods.withdrawAllQuote().send(ctx.sendParam(lp1)), /DODO_QUOTE_BALANCE_NOT_ENOUGH/ - ) - }) + ); + }); it("withdraw base could not afford penalty", async () => { - await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.buyBaseToken(decimalStr("9"), decimalStr("10000"), "0x").send(ctx.sendParam(trader)) + await ctx.DODO.methods + .depositBase(decimalStr("10")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .buyBaseToken(decimalStr("9"), decimalStr("10000"), "0x") + .send(ctx.sendParam(trader)); await assert.rejects( - ctx.DODO.methods.withdrawBase(decimalStr("0.5")).send(ctx.sendParam(lp1)), + ctx.DODO.methods + .withdrawBase(decimalStr("0.5")) + .send(ctx.sendParam(lp1)), /PENALTY_EXCEED/ - ) + ); await assert.rejects( ctx.DODO.methods.getWithdrawBasePenalty(decimalStr("10")).call(), /DODO_BASE_BALANCE_NOT_ENOUGH/ - ) - }) + ); + }); it("withdraw quote could not afford penalty", async () => { - await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.sellBaseToken(decimalStr("10"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) + await ctx.DODO.methods + .depositQuote(decimalStr("1000")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .sellBaseToken(decimalStr("10"), decimalStr("0"), "0x") + .send(ctx.sendParam(trader)); await assert.rejects( - ctx.DODO.methods.withdrawQuote(decimalStr("200")).send(ctx.sendParam(lp1)), + ctx.DODO.methods + .withdrawQuote(decimalStr("200")) + .send(ctx.sendParam(lp1)), /PENALTY_EXCEED/ - ) + ); await assert.rejects( ctx.DODO.methods.getWithdrawQuotePenalty(decimalStr("1000")).call(), /DODO_QUOTE_BALANCE_NOT_ENOUGH/ - ) - }) + ); + }); it("withdraw all base could not afford penalty", async () => { - await ctx.DODO.methods.depositBase(decimalStr("9.5")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.depositBase(decimalStr("0.5")).send(ctx.sendParam(lp2)) - await ctx.DODO.methods.buyBaseToken(decimalStr("9"), decimalStr("10000"), "0x").send(ctx.sendParam(trader)) + await ctx.DODO.methods + .depositBase(decimalStr("9.5")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .depositBase(decimalStr("0.5")) + .send(ctx.sendParam(lp2)); + await ctx.DODO.methods + .buyBaseToken(decimalStr("9"), decimalStr("10000"), "0x") + .send(ctx.sendParam(trader)); await assert.rejects( - ctx.DODO.methods.withdrawBase(decimalStr("0.5")).send(ctx.sendParam(lp2)), + ctx.DODO.methods + .withdrawBase(decimalStr("0.5")) + .send(ctx.sendParam(lp2)), /PENALTY_EXCEED/ - ) - }) + ); + }); it("withdraw all quote could not afford penalty", async () => { - await ctx.DODO.methods.depositQuote(decimalStr("800")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.depositQuote(decimalStr("200")).send(ctx.sendParam(lp2)) - await ctx.DODO.methods.sellBaseToken(decimalStr("10"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) + await ctx.DODO.methods + .depositQuote(decimalStr("800")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .depositQuote(decimalStr("200")) + .send(ctx.sendParam(lp2)); + await ctx.DODO.methods + .sellBaseToken(decimalStr("10"), decimalStr("0"), "0x") + .send(ctx.sendParam(trader)); await assert.rejects( - ctx.DODO.methods.withdrawQuote(decimalStr("200")).send(ctx.sendParam(lp2)), + ctx.DODO.methods + .withdrawQuote(decimalStr("200")) + .send(ctx.sendParam(lp2)), /PENALTY_EXCEED/ - ) - }) + ); + }); it("withdraw amount exceeds lp balance", async () => { - await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp2)) - await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp2)) + await ctx.DODO.methods + .depositBase(decimalStr("10")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .depositBase(decimalStr("10")) + .send(ctx.sendParam(lp2)); + await ctx.DODO.methods + .depositQuote(decimalStr("1000")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .depositQuote(decimalStr("1000")) + .send(ctx.sendParam(lp2)); await assert.rejects( - ctx.DODO.methods.withdrawBase(decimalStr("11")).send(ctx.sendParam(lp1)), + ctx.DODO.methods + .withdrawBase(decimalStr("11")) + .send(ctx.sendParam(lp1)), /LP_BASE_CAPITAL_BALANCE_NOT_ENOUGH/ - ) + ); await assert.rejects( - ctx.DODO.methods.withdrawQuote(decimalStr("1100")).send(ctx.sendParam(lp1)), + ctx.DODO.methods + .withdrawQuote(decimalStr("1100")) + .send(ctx.sendParam(lp1)), /LP_QUOTE_CAPITAL_BALANCE_NOT_ENOUGH/ - ) - }) + ); + }); it("withdraw when there is no lp", async () => { await assert.rejects( ctx.DODO.methods.withdrawBase(decimalStr("1")).send(ctx.sendParam(lp1)), /NO_BASE_LP/ - ) + ); await assert.rejects( - ctx.DODO.methods.withdrawQuote(decimalStr("1")).send(ctx.sendParam(lp1)), + ctx.DODO.methods + .withdrawQuote(decimalStr("1")) + .send(ctx.sendParam(lp1)), /NO_QUOTE_LP/ - ) - }) - }) - -}) \ No newline at end of file + ); + }); + }); +}); diff --git a/test/Trader.test.ts b/test/Trader.test.ts index 9046248..506aef4 100644 --- a/test/Trader.test.ts +++ b/test/Trader.test.ts @@ -5,277 +5,621 @@ */ +import * as assert from 'assert'; + import { DODOContext, getDODOContext } from './utils/Context'; import { decimalStr } from './utils/Converter'; import { logGas } from './utils/Log'; -import * as assert from "assert" -let lp: string -let trader: string +let lp: string; +let trader: string; async function init(ctx: DODOContext): Promise { - await ctx.setOraclePrice(decimalStr("100")) + await ctx.setOraclePrice(decimalStr("100")); - lp = ctx.spareAccounts[0] - trader = ctx.spareAccounts[1] - await ctx.approveDODO(lp) - await ctx.approveDODO(trader) + lp = ctx.spareAccounts[0]; + trader = ctx.spareAccounts[1]; + await ctx.approveDODO(lp); + await ctx.approveDODO(trader); - await ctx.mintTestToken(lp, decimalStr("10"), decimalStr("1000")) - await ctx.mintTestToken(trader, decimalStr("10"), decimalStr("1000")) + await ctx.mintTestToken(lp, decimalStr("10"), decimalStr("1000")); + await ctx.mintTestToken(trader, decimalStr("10"), decimalStr("1000")); - await ctx.DODO.methods.depositBaseTo(lp, decimalStr("10")).send(ctx.sendParam(lp)) - await ctx.DODO.methods.depositQuoteTo(lp, decimalStr("1000")).send(ctx.sendParam(lp)) + await ctx.DODO.methods + .depositBaseTo(lp, decimalStr("10")) + .send(ctx.sendParam(lp)); + await ctx.DODO.methods + .depositQuoteTo(lp, decimalStr("1000")) + .send(ctx.sendParam(lp)); } describe("Trader", () => { - - let snapshotId: string - let ctx: DODOContext + let snapshotId: string; + let ctx: DODOContext; before(async () => { - ctx = await getDODOContext() + ctx = await getDODOContext(); await init(ctx); - }) + }); beforeEach(async () => { snapshotId = await ctx.EVM.snapshot(); }); afterEach(async () => { - await ctx.EVM.reset(snapshotId) + await ctx.EVM.reset(snapshotId); }); describe("R goes above ONE", () => { it("buy when R equals ONE", async () => { - logGas(await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110"), "0x").send(ctx.sendParam(trader)), "buy base token when balanced") + await logGas( + ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110"), "0x"), + ctx.sendParam(trader), + "buy base token when balanced" + ); // trader balances - assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("11")) - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "898581839502056240973") + assert.equal( + await ctx.BASE.methods.balanceOf(trader).call(), + decimalStr("11") + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(trader).call(), + "898581839502056240973" + ); // maintainer balances - assert.equal(await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), decimalStr("0.001")) - assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), decimalStr("0")) + assert.equal( + await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), + decimalStr("0.001") + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), + decimalStr("0") + ); // dodo balances - assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("8.999")) - assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "1101418160497943759027") + assert.equal( + await ctx.DODO.methods._BASE_BALANCE_().call(), + decimalStr("8.999") + ); + assert.equal( + await ctx.DODO.methods._QUOTE_BALANCE_().call(), + "1101418160497943759027" + ); // price update - assert.equal(await ctx.DODO.methods.getMidPrice().call(), "102353368821735563400") - }) + assert.equal( + await ctx.DODO.methods.getMidPrice().call(), + "102353368821735563400" + ); + }); it("buy when R is ABOVE ONE", async () => { - await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110"), "0x").send(ctx.sendParam(trader)) - logGas(await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("130"), "0x").send(ctx.sendParam(trader)), "buy when R is ABOVE ONE") + await ctx.DODO.methods + .buyBaseToken(decimalStr("1"), decimalStr("110"), "0x") + .send(ctx.sendParam(trader)); + await logGas( + ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("130"), "0x"), + ctx.sendParam(trader), + "buy when R is ABOVE ONE" + ); // trader balances - assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("12")) - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "794367183433412077653") + assert.equal( + await ctx.BASE.methods.balanceOf(trader).call(), + decimalStr("12") + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(trader).call(), + "794367183433412077653" + ); // maintainer balances - assert.equal(await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), decimalStr("0.002")) - assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), decimalStr("0")) + assert.equal( + await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), + decimalStr("0.002") + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), + decimalStr("0") + ); // dodo balances - assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("7.998")) - assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "1205632816566587922347") - }) + assert.equal( + await ctx.DODO.methods._BASE_BALANCE_().call(), + decimalStr("7.998") + ); + assert.equal( + await ctx.DODO.methods._QUOTE_BALANCE_().call(), + "1205632816566587922347" + ); + }); it("sell when R is ABOVE ONE", async () => { - await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110"), "0x").send(ctx.sendParam(trader)) - logGas(await ctx.DODO.methods.sellBaseToken(decimalStr("0.5"), decimalStr("40"), "0x").send(ctx.sendParam(trader)), "sell when R is ABOVE ONE") + await ctx.DODO.methods + .buyBaseToken(decimalStr("1"), decimalStr("110"), "0x") + .send(ctx.sendParam(trader)); + await logGas( + ctx.DODO.methods.sellBaseToken( + decimalStr("0.5"), + decimalStr("40"), + "0x" + ), + ctx.sendParam(trader), + "sell when R is ABOVE ONE" + ); // trader balances - assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("10.5")) - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "949280846351657143136") + assert.equal( + await ctx.BASE.methods.balanceOf(trader).call(), + decimalStr("10.5") + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(trader).call(), + "949280846351657143136" + ); // maintainer balances - assert.equal(await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), decimalStr("0.001")) - assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), "50851561534203512") + assert.equal( + await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), + decimalStr("0.001") + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), + "50851561534203512" + ); // dodo balances - assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("9.499")) - assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "1050668302086808653352") - }) + assert.equal( + await ctx.DODO.methods._BASE_BALANCE_().call(), + decimalStr("9.499") + ); + assert.equal( + await ctx.DODO.methods._QUOTE_BALANCE_().call(), + "1050668302086808653352" + ); + }); it("sell when R is ABOVE ONE and RStatus back to ONE", async () => { - await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110"), "0x").send(ctx.sendParam(trader)) - logGas(await ctx.DODO.methods.sellBaseToken("1003002430889317763", decimalStr("90"), "0x").send(ctx.sendParam(trader)), "sell when R is ABOVE ONE and RStatus back to ONE") + await ctx.DODO.methods + .buyBaseToken(decimalStr("1"), decimalStr("110"), "0x") + .send(ctx.sendParam(trader)); + await logGas( + ctx.DODO.methods.sellBaseToken( + "1003002430889317763", + decimalStr("90"), + "0x" + ), + ctx.sendParam(trader), + "sell when R is ABOVE ONE and RStatus back to ONE" + ); // R status - assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0") + assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0"); // trader balances - assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), "9996997569110682237") - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "999695745518506168723") + assert.equal( + await ctx.BASE.methods.balanceOf(trader).call(), + "9996997569110682237" + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(trader).call(), + "999695745518506168723" + ); // maintainer balances - assert.equal(await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), decimalStr("0.001")) - assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), "101418160497943759") + assert.equal( + await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), + decimalStr("0.001") + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), + "101418160497943759" + ); // dodo balances - assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), "10002002430889317763") - assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "1000202836320995887518") + assert.equal( + await ctx.DODO.methods._BASE_BALANCE_().call(), + "10002002430889317763" + ); + assert.equal( + await ctx.DODO.methods._QUOTE_BALANCE_().call(), + "1000202836320995887518" + ); // target status - assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "10002002430889317763") - assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), "1000202836320995887518") - }) + assert.equal( + await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), + "10002002430889317763" + ); + assert.equal( + await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), + "1000202836320995887518" + ); + }); it("sell when R is ABOVE ONE and RStatus becomes BELOW ONE", async () => { - await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110"), "0x").send(ctx.sendParam(trader)) - logGas(await ctx.DODO.methods.sellBaseToken(decimalStr("2"), decimalStr("90"), "0x").send(ctx.sendParam(trader)), "sell when R is ABOVE ONE and RStatus becomes BELOW ONE [gas cost worst case]") + await ctx.DODO.methods + .buyBaseToken(decimalStr("1"), decimalStr("110"), "0x") + .send(ctx.sendParam(trader)); + await logGas( + ctx.DODO.methods.sellBaseToken(decimalStr("2"), decimalStr("90"), "0x"), + ctx.sendParam(trader), + "sell when R is ABOVE ONE and RStatus becomes BELOW ONE [gas cost worst case]" + ); // R status - assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "2") + assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "2"); // trader balances - assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("9")) - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1098020621600061709144") + assert.equal( + await ctx.BASE.methods.balanceOf(trader).call(), + decimalStr("9") + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(trader).call(), + "1098020621600061709144" + ); // maintainer balances - assert.equal(await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), decimalStr("0.001")) - assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), "200038898794388634") + assert.equal( + await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), + decimalStr("0.001") + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), + "200038898794388634" + ); // dodo balances - assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("10.999")) - assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "901779339501143902222") + assert.equal( + await ctx.DODO.methods._BASE_BALANCE_().call(), + decimalStr("10.999") + ); + assert.equal( + await ctx.DODO.methods._QUOTE_BALANCE_().call(), + "901779339501143902222" + ); // target status - assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "10002002430889317763") - assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), "1000400077797588777268") - }) - }) + assert.equal( + await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), + "10002002430889317763" + ); + assert.equal( + await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), + "1000400077797588777268" + ); + }); + }); describe("R goes below ONE", () => { it("sell when R equals ONE", async () => { - logGas(await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90"), "0x").send(ctx.sendParam(trader)), "sell base token when balanced") + await logGas( + ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90"), "0x"), + ctx.sendParam(trader), + "sell base token when balanced" + ); // trader balances - assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("9")) - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1098617454226610630663") + assert.equal( + await ctx.BASE.methods.balanceOf(trader).call(), + decimalStr("9") + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(trader).call(), + "1098617454226610630663" + ); // maintainer balances - assert.equal(await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), "0") - assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), "98914196817061816") + assert.equal( + await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), + "0" + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), + "98914196817061816" + ); // dodo balances - assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("11")) - assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "901283631576572307521") + assert.equal( + await ctx.DODO.methods._BASE_BALANCE_().call(), + decimalStr("11") + ); + assert.equal( + await ctx.DODO.methods._QUOTE_BALANCE_().call(), + "901283631576572307521" + ); // price update - assert.equal(await ctx.DODO.methods.getMidPrice().call(), "97736983274307939149") - }) + assert.equal( + await ctx.DODO.methods.getMidPrice().call(), + "97736983274307939149" + ); + }); it("sell when R is BELOW ONE", async () => { - await ctx.DODO.methods.sellBaseToken(decimalStr("3"), decimalStr("90"), "0x").send(ctx.sendParam(trader)) - logGas(await ctx.DODO.methods.sellBaseToken(decimalStr("3"), decimalStr("90"), "0x").send(ctx.sendParam(trader)), "sell when R is BELOW ONE") + await ctx.DODO.methods + .sellBaseToken(decimalStr("3"), decimalStr("90"), "0x") + .send(ctx.sendParam(trader)); + await logGas( + ctx.DODO.methods.sellBaseToken(decimalStr("3"), decimalStr("90"), "0x"), + ctx.sendParam(trader), + "sell when R is BELOW ONE" + ); // trader balances - assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("4")) - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1535961012052716726151") + assert.equal( + await ctx.BASE.methods.balanceOf(trader).call(), + decimalStr("4") + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(trader).call(), + "1535961012052716726151" + ); // maintainer balances - assert.equal(await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), "0") - assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), "537573733252474148") + assert.equal( + await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), + "0" + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), + "537573733252474148" + ); // dodo balances - assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("16")) - assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "463501414214030799701") - }) + assert.equal( + await ctx.DODO.methods._BASE_BALANCE_().call(), + decimalStr("16") + ); + assert.equal( + await ctx.DODO.methods._QUOTE_BALANCE_().call(), + "463501414214030799701" + ); + }); it("buy when R is BELOW ONE", async () => { - await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90"), "0x").send(ctx.sendParam(trader)) - logGas(await ctx.DODO.methods.buyBaseToken(decimalStr("0.5"), decimalStr("60"), "0x").send(ctx.sendParam(trader)), "buy when R is BELOW ONE") + await ctx.DODO.methods + .sellBaseToken(decimalStr("1"), decimalStr("90"), "0x") + .send(ctx.sendParam(trader)); + await logGas( + ctx.DODO.methods.buyBaseToken( + decimalStr("0.5"), + decimalStr("60"), + "0x" + ), + ctx.sendParam(trader), + "buy when R is BELOW ONE" + ); // trader balances - assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("9.5")) - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1049294316148665165453") + assert.equal( + await ctx.BASE.methods.balanceOf(trader).call(), + decimalStr("9.5") + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(trader).call(), + "1049294316148665165453" + ); // maintainer balances - assert.equal(await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), decimalStr("0.0005")) - assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), "98914196817061816") + assert.equal( + await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), + decimalStr("0.0005") + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), + "98914196817061816" + ); // dodo balances - assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("10.4995")) - assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "950606769654517772731") - }) + assert.equal( + await ctx.DODO.methods._BASE_BALANCE_().call(), + decimalStr("10.4995") + ); + assert.equal( + await ctx.DODO.methods._QUOTE_BALANCE_().call(), + "950606769654517772731" + ); + }); it("buy when R is BELOW ONE and RStatus back to ONE", async () => { - await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90"), "0x").send(ctx.sendParam(trader)) - logGas(await ctx.DODO.methods.buyBaseToken("997008973080757728", decimalStr("110"), "0x").send(ctx.sendParam(trader)), "buy when R is BELOW ONE and RStatus back to ONE") + await ctx.DODO.methods + .sellBaseToken(decimalStr("1"), decimalStr("90"), "0x") + .send(ctx.sendParam(trader)); + await logGas( + ctx.DODO.methods.buyBaseToken( + "997008973080757728", + decimalStr("110"), + "0x" + ), + ctx.sendParam(trader), + "buy when R is BELOW ONE and RStatus back to ONE" + ); // R status - assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0") + assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0"); // trader balances - assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), "9997008973080757728") - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "999703024198699411500") + assert.equal( + await ctx.BASE.methods.balanceOf(trader).call(), + "9997008973080757728" + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(trader).call(), + "999703024198699411500" + ); // maintainer balances - assert.equal(await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), "997008973080757") - assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), "98914196817061816") + assert.equal( + await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), + "997008973080757" + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), + "98914196817061816" + ); // dodo balances - assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), "10001994017946161515") - assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "1000198061604483526684") + assert.equal( + await ctx.DODO.methods._BASE_BALANCE_().call(), + "10001994017946161515" + ); + assert.equal( + await ctx.DODO.methods._QUOTE_BALANCE_().call(), + "1000198061604483526684" + ); // target status - assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "10001994017946161515") - assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), "1000198061604483526684") - }) + assert.equal( + await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), + "10001994017946161515" + ); + assert.equal( + await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), + "1000198061604483526684" + ); + }); it("buy when R is BELOW ONE and RStatus becomes ABOVE ONE", async () => { - await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90"), "0x").send(ctx.sendParam(trader)) - logGas(await ctx.DODO.methods.buyBaseToken(decimalStr("2"), decimalStr("220"), "0x").send(ctx.sendParam(trader)), "buy when R is BELOW ONE and RStatus becomes ABOVE ONE [gas cost worst case]") + await ctx.DODO.methods + .sellBaseToken(decimalStr("1"), decimalStr("90"), "0x") + .send(ctx.sendParam(trader)); + await logGas( + ctx.DODO.methods.buyBaseToken(decimalStr("2"), decimalStr("220"), "0x"), + ctx.sendParam(trader), + "buy when R is BELOW ONE and RStatus becomes ABOVE ONE [gas cost worst case]" + ); // R status - assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "1") + assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "1"); // trader balances - assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("11")) - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "897977789597854403796") + assert.equal( + await ctx.BASE.methods.balanceOf(trader).call(), + decimalStr("11") + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(trader).call(), + "897977789597854403796" + ); // maintainer balances - assert.equal(await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), decimalStr("0.002")) - assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), "98914196817061816") + assert.equal( + await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), + decimalStr("0.002") + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), + "98914196817061816" + ); // dodo balances - assert.equal(await ctx.DODO.methods._BASE_BALANCE_().call(), decimalStr("8.998")) - assert.equal(await ctx.DODO.methods._QUOTE_BALANCE_().call(), "1101923296205328534388") + assert.equal( + await ctx.DODO.methods._BASE_BALANCE_().call(), + decimalStr("8.998") + ); + assert.equal( + await ctx.DODO.methods._QUOTE_BALANCE_().call(), + "1101923296205328534388" + ); // target status - assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), "10004000000000000000") - assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), "1000198061604483526684") - }) - }) + assert.equal( + await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), + "10004000000000000000" + ); + assert.equal( + await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), + "1000198061604483526684" + ); + }); + }); describe("Corner cases", () => { it("buy or sell 0", async () => { - await ctx.DODO.methods.sellBaseToken(decimalStr("0"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) - assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("10")) - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), decimalStr("1000")) + await ctx.DODO.methods + .sellBaseToken(decimalStr("0"), decimalStr("0"), "0x") + .send(ctx.sendParam(trader)); + assert.equal( + await ctx.BASE.methods.balanceOf(trader).call(), + decimalStr("10") + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(trader).call(), + decimalStr("1000") + ); - await ctx.DODO.methods.buyBaseToken(decimalStr("0"), decimalStr("0"), "0x").send(ctx.sendParam(trader)) - assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("10")) - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), decimalStr("1000")) - }) + await ctx.DODO.methods + .buyBaseToken(decimalStr("0"), decimalStr("0"), "0x") + .send(ctx.sendParam(trader)); + assert.equal( + await ctx.BASE.methods.balanceOf(trader).call(), + decimalStr("10") + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(trader).call(), + decimalStr("1000") + ); + }); it("buy or sell a tiny amount", async () => { // no precision problem - await ctx.DODO.methods.sellBaseToken("1", decimalStr("0"), "0x").send(ctx.sendParam(trader)) - assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), "9999999999999999999") - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1000000000000000000100") + await ctx.DODO.methods + .sellBaseToken("1", decimalStr("0"), "0x") + .send(ctx.sendParam(trader)); + assert.equal( + await ctx.BASE.methods.balanceOf(trader).call(), + "9999999999999999999" + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(trader).call(), + "1000000000000000000100" + ); // have precision problem, charge 0 - await ctx.DODO.methods.buyBaseToken("1", decimalStr("1"), "0x").send(ctx.sendParam(trader)) - assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), "10000000000000000000") - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1000000000000000000100") - assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0") + await ctx.DODO.methods + .buyBaseToken("1", decimalStr("1"), "0x") + .send(ctx.sendParam(trader)); + assert.equal( + await ctx.BASE.methods.balanceOf(trader).call(), + "10000000000000000000" + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(trader).call(), + "1000000000000000000100" + ); + assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0"); // no precision problem if trading amount is extremely small - await ctx.DODO.methods.buyBaseToken("10", decimalStr("1"), "0x").send(ctx.sendParam(trader)) - assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), "10000000000000000010") - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "999999999999999999100") - }) + await ctx.DODO.methods + .buyBaseToken("10", decimalStr("1"), "0x") + .send(ctx.sendParam(trader)); + assert.equal( + await ctx.BASE.methods.balanceOf(trader).call(), + "10000000000000000010" + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(trader).call(), + "999999999999999999100" + ); + }); it("sell a huge amount of base token", async () => { - await ctx.mintTestToken(trader, decimalStr("10000"), "0") - await ctx.DODO.methods.sellBaseToken(decimalStr("10000"), "0", "0x").send(ctx.sendParam(trader)) + await ctx.mintTestToken(trader, decimalStr("10000"), "0"); + await ctx.DODO.methods + .sellBaseToken(decimalStr("10000"), "0", "0x") + .send(ctx.sendParam(trader)); // nearly drain out quote pool // because the fee donated is greater than remaining quote pool // quote lp earn a considerable profit - assert.equal(await ctx.QUOTE.methods.balanceOf(trader).call(), "1996900220185135480813") - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp).call(), "4574057156329524019750") - }) - }) + assert.equal( + await ctx.QUOTE.methods.balanceOf(trader).call(), + "1996900220185135480813" + ); + assert.equal( + await ctx.DODO.methods.getLpQuoteBalance(lp).call(), + "4574057156329524019750" + ); + }); + }); describe("Revert cases", () => { it("price limit", async () => { await assert.rejects( - ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("100"), "0x").send(ctx.sendParam(trader)), + ctx.DODO.methods + .buyBaseToken(decimalStr("1"), decimalStr("100"), "0x") + .send(ctx.sendParam(trader)), /BUY_BASE_COST_TOO_MUCH/ - ) + ); await assert.rejects( - ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("100"), "0x").send(ctx.sendParam(trader)), + ctx.DODO.methods + .sellBaseToken(decimalStr("1"), decimalStr("100"), "0x") + .send(ctx.sendParam(trader)), /SELL_BASE_RECEIVE_NOT_ENOUGH/ - ) - }) + ); + }); it("base balance limit", async () => { await assert.rejects( - ctx.DODO.methods.buyBaseToken(decimalStr("11"), decimalStr("10000"), "0x").send(ctx.sendParam(trader)), + ctx.DODO.methods + .buyBaseToken(decimalStr("11"), decimalStr("10000"), "0x") + .send(ctx.sendParam(trader)), /DODO_BASE_BALANCE_NOT_ENOUGH/ - ) + ); - await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("200"), "0x").send(ctx.sendParam(trader)) + await ctx.DODO.methods + .buyBaseToken(decimalStr("1"), decimalStr("200"), "0x") + .send(ctx.sendParam(trader)); await assert.rejects( - ctx.DODO.methods.buyBaseToken(decimalStr("11"), decimalStr("10000"), "0x").send(ctx.sendParam(trader)), + ctx.DODO.methods + .buyBaseToken(decimalStr("11"), decimalStr("10000"), "0x") + .send(ctx.sendParam(trader)), /DODO_BASE_BALANCE_NOT_ENOUGH/ - ) - }) - }) -}) \ No newline at end of file + ); + }); + }); +}); diff --git a/test/UniswapArbitrageur.test.ts b/test/UniswapArbitrageur.test.ts index b7c53c8..1df1df3 100644 --- a/test/UniswapArbitrageur.test.ts +++ b/test/UniswapArbitrageur.test.ts @@ -5,116 +5,172 @@ */ -import { DODOContext, getDODOContext } from './utils/Context'; -import { decimalStr } from './utils/Converter'; -import { logGas } from './utils/Log'; -import * as assert from "assert" -import { newContract, UNISWAP_CONTRACT_NAME, UNISWAP_ARBITRAGEUR_CONTRACT_NAME } from './utils/Contracts'; +import * as assert from 'assert'; import { Contract } from 'web3-eth-contract'; -let lp: string -let keeper: string +import { DODOContext, getDODOContext } from './utils/Context'; +import { + newContract, + UNISWAP_ARBITRAGEUR_CONTRACT_NAME, + UNISWAP_CONTRACT_NAME, +} from './utils/Contracts'; +import { decimalStr } from './utils/Converter'; +import { logGas } from './utils/Log'; -let Uniswap: Contract -let UniswapArbitrageur: Contract +let lp: string; +let keeper: string; -let UniswapReverse: Contract -let UniswapArbitrageurReverse: Contract +let Uniswap: Contract; +let UniswapArbitrageur: Contract; + +let UniswapReverse: Contract; +let UniswapArbitrageurReverse: Contract; async function init(ctx: DODOContext): Promise { - await ctx.setOraclePrice(decimalStr("100")) + await ctx.setOraclePrice(decimalStr("100")); - lp = ctx.spareAccounts[0] - keeper = ctx.spareAccounts[1] - await ctx.approveDODO(lp) + lp = ctx.spareAccounts[0]; + keeper = ctx.spareAccounts[1]; + await ctx.approveDODO(lp); - await ctx.mintTestToken(lp, decimalStr("100"), decimalStr("10000")) + await ctx.mintTestToken(lp, decimalStr("100"), decimalStr("10000")); - await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp)) - await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp)) + await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp)); + await ctx.DODO.methods + .depositQuote(decimalStr("1000")) + .send(ctx.sendParam(lp)); - Uniswap = await newContract(UNISWAP_CONTRACT_NAME) - Uniswap.methods.initialize(ctx.BASE.options.address, ctx.QUOTE.options.address).send(ctx.sendParam(ctx.Deployer)) - ctx.BASE.methods.transfer(Uniswap.options.address, decimalStr("10")).send(ctx.sendParam(lp)) - ctx.QUOTE.methods.transfer(Uniswap.options.address, decimalStr("2000")).send(ctx.sendParam(lp)) - Uniswap.methods.sync().send(ctx.sendParam(lp)) + Uniswap = await newContract(UNISWAP_CONTRACT_NAME); + Uniswap.methods + .initialize(ctx.BASE.options.address, ctx.QUOTE.options.address) + .send(ctx.sendParam(ctx.Deployer)); + ctx.BASE.methods + .transfer(Uniswap.options.address, decimalStr("10")) + .send(ctx.sendParam(lp)); + ctx.QUOTE.methods + .transfer(Uniswap.options.address, decimalStr("2000")) + .send(ctx.sendParam(lp)); + Uniswap.methods.sync().send(ctx.sendParam(lp)); - UniswapArbitrageur = await newContract(UNISWAP_ARBITRAGEUR_CONTRACT_NAME, [Uniswap.options.address, ctx.DODO.options.address]) + UniswapArbitrageur = await newContract(UNISWAP_ARBITRAGEUR_CONTRACT_NAME, [ + Uniswap.options.address, + ctx.DODO.options.address, + ]); - UniswapReverse = await newContract(UNISWAP_CONTRACT_NAME) - UniswapReverse.methods.initialize(ctx.BASE.options.address, ctx.QUOTE.options.address).send(ctx.sendParam(ctx.Deployer)) - ctx.BASE.methods.transfer(UniswapReverse.options.address, decimalStr("10")).send(ctx.sendParam(lp)) - ctx.QUOTE.methods.transfer(UniswapReverse.options.address, decimalStr("2000")).send(ctx.sendParam(lp)) - UniswapReverse.methods.sync().send(ctx.sendParam(lp)) + UniswapReverse = await newContract(UNISWAP_CONTRACT_NAME); + UniswapReverse.methods + .initialize(ctx.BASE.options.address, ctx.QUOTE.options.address) + .send(ctx.sendParam(ctx.Deployer)); + ctx.BASE.methods + .transfer(UniswapReverse.options.address, decimalStr("10")) + .send(ctx.sendParam(lp)); + ctx.QUOTE.methods + .transfer(UniswapReverse.options.address, decimalStr("2000")) + .send(ctx.sendParam(lp)); + UniswapReverse.methods.sync().send(ctx.sendParam(lp)); - UniswapArbitrageurReverse = await newContract(UNISWAP_ARBITRAGEUR_CONTRACT_NAME, [UniswapReverse.options.address, ctx.DODO.options.address]) + UniswapArbitrageurReverse = await newContract( + UNISWAP_ARBITRAGEUR_CONTRACT_NAME, + [UniswapReverse.options.address, ctx.DODO.options.address] + ); } describe("Uniswap Arbitrageur", () => { - - let snapshotId: string - let ctx: DODOContext + let snapshotId: string; + let ctx: DODOContext; before(async () => { - ctx = await getDODOContext() + ctx = await getDODOContext(); await init(ctx); - }) + }); beforeEach(async () => { snapshotId = await ctx.EVM.snapshot(); }); afterEach(async () => { - await ctx.EVM.reset(snapshotId) + await ctx.EVM.reset(snapshotId); }); describe("arbitrage with not reverse pair", () => { it("buy at dodo", async () => { - await ctx.setOraclePrice(decimalStr("100")) + await ctx.setOraclePrice(decimalStr("100")); // dodo price 100 uniswap price 200 // buy at dodo - logGas(await UniswapArbitrageur.methods.executeBuyArbitrage(decimalStr("1")).send(ctx.sendParam(keeper)), "arbitrage buy at dodo not reverse") - assert.equal(await ctx.QUOTE.methods.balanceOf(keeper).call(), "79836384956601695518") - }) + await logGas( + UniswapArbitrageur.methods.executeBuyArbitrage(decimalStr("1")), + ctx.sendParam(keeper), + "arbitrage buy at dodo not reverse" + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(keeper).call(), + "79836384956601695518" + ); + }); it("sell at dodo", async () => { - await ctx.setOraclePrice(decimalStr("300")) + await ctx.setOraclePrice(decimalStr("300")); // dodo price 300 uniswap price 200 // sell at dodo - logGas(await UniswapArbitrageur.methods.executeSellArbitrage(decimalStr("1")).send(ctx.sendParam(keeper)), "arbitrage sell at dodo not reverse") - assert.equal(await ctx.BASE.methods.balanceOf(keeper).call(), "252761069524143743") - }) - }) + await logGas( + UniswapArbitrageur.methods.executeSellArbitrage(decimalStr("1")), + ctx.sendParam(keeper), + "arbitrage sell at dodo not reverse" + ); + assert.equal( + await ctx.BASE.methods.balanceOf(keeper).call(), + "252761069524143743" + ); + }); + }); describe("arbitrage with reverse pair", () => { it("buy at dodo", async () => { - await ctx.setOraclePrice(decimalStr("100")) + await ctx.setOraclePrice(decimalStr("100")); // dodo price 100 uniswap price 200 // buy at dodo - logGas(await UniswapArbitrageurReverse.methods.executeBuyArbitrage(decimalStr("1")).send(ctx.sendParam(keeper)), "arbitrage buy at dodo reverse") - assert.equal(await ctx.QUOTE.methods.balanceOf(keeper).call(), "79836384956601695518") - }) + await logGas( + UniswapArbitrageurReverse.methods.executeBuyArbitrage(decimalStr("1")), + ctx.sendParam(keeper), + "arbitrage buy at dodo reverse" + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(keeper).call(), + "79836384956601695518" + ); + }); it("sell at dodo", async () => { - await ctx.setOraclePrice(decimalStr("300")) + await ctx.setOraclePrice(decimalStr("300")); // dodo price 300 uniswap price 200 // sell at dodo - logGas(await UniswapArbitrageurReverse.methods.executeSellArbitrage(decimalStr("1")).send(ctx.sendParam(keeper)), "arbitrage sell at dodo reverse") - assert.equal(await ctx.BASE.methods.balanceOf(keeper).call(), "252761069524143743") - }) - }) + await logGas( + UniswapArbitrageurReverse.methods.executeSellArbitrage(decimalStr("1")), + ctx.sendParam(keeper), + "arbitrage sell at dodo reverse" + ); + assert.equal( + await ctx.BASE.methods.balanceOf(keeper).call(), + "252761069524143743" + ); + }); + }); describe("revert cases", () => { it("price not match", async () => { - await ctx.setOraclePrice(decimalStr("200")) + await ctx.setOraclePrice(decimalStr("200")); await assert.rejects( - UniswapArbitrageurReverse.methods.executeBuyArbitrage(decimalStr("1")).send(ctx.sendParam(keeper)), + UniswapArbitrageurReverse.methods + .executeBuyArbitrage(decimalStr("1")) + .send(ctx.sendParam(keeper)), /NOT_PROFITABLE/ - ) + ); await assert.rejects( - UniswapArbitrageurReverse.methods.executeSellArbitrage(decimalStr("1")).send(ctx.sendParam(keeper)), + UniswapArbitrageurReverse.methods + .executeSellArbitrage(decimalStr("1")) + .send(ctx.sendParam(keeper)), /NOT_PROFITABLE/ - ) - }) - }) -}) \ No newline at end of file + ); + }); + }); +}); From 46460db8cbe2528683243da1f5b5c38b559189e0 Mon Sep 17 00:00:00 2001 From: Michael Zhou Date: Tue, 8 Sep 2020 19:45:17 +0800 Subject: [PATCH 076/118] Add buying, selling and capital limit controls These advanced controls are disabled by default. Also disable depositing and trading when creating a new DODO. --- contracts/dodo.sol | 14 +- contracts/impl/Admin.sol | 27 ++ contracts/impl/Settlement.sol | 6 + contracts/impl/Storage.sol | 9 +- contracts/impl/Trader.sol | 15 +- test/Admin.test.ts | 620 ++++++++++++++++++++++--------- test/DODOEthProxyAsBase.test.ts | 25 +- test/DODOEthProxyAsQuote.test.ts | 23 +- test/utils/Context.ts | 178 +++++---- 9 files changed, 651 insertions(+), 266 deletions(-) diff --git a/contracts/dodo.sol b/contracts/dodo.sol index 81be5dd..8e63036 100644 --- a/contracts/dodo.sol +++ b/contracts/dodo.sol @@ -16,6 +16,7 @@ import {LiquidityProvider} from "./impl/LiquidityProvider.sol"; import {Admin} from "./impl/Admin.sol"; import {DODOLpToken} from "./impl/DODOLpToken.sol"; + /** * @title DODO * @author DODO Breeder @@ -48,11 +49,18 @@ contract DODO is Admin, Trader, LiquidityProvider { _QUOTE_TOKEN_ = quoteToken; _ORACLE_ = oracle; - _DEPOSIT_BASE_ALLOWED_ = true; - _DEPOSIT_QUOTE_ALLOWED_ = true; - _TRADE_ALLOWED_ = true; + _DEPOSIT_BASE_ALLOWED_ = false; + _DEPOSIT_QUOTE_ALLOWED_ = false; + _TRADE_ALLOWED_ = false; _GAS_PRICE_LIMIT_ = gasPriceLimit; + // Advanced controls are disabled by default + _BUYING_ALLOWED_ = true; + _SELLING_ALLOWED_ = true; + uint256 MAX_INT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; + _BASE_BALANCE_LIMIT_ = MAX_INT; + _QUOTE_BALANCE_LIMIT_ = MAX_INT; + _LP_FEE_RATE_ = lpFeeRate; _MT_FEE_RATE_ = mtFeeRate; _K_ = k; diff --git a/contracts/impl/Admin.sol b/contracts/impl/Admin.sol index fd89052..2e5edf7 100644 --- a/contracts/impl/Admin.sol +++ b/contracts/impl/Admin.sol @@ -10,6 +10,7 @@ pragma experimental ABIEncoderV2; import {Storage} from "./Storage.sol"; + /** * @title Admin * @author DODO Breeder @@ -92,4 +93,30 @@ contract Admin is Storage { function enableBaseDeposit() external onlyOwner notClosed { _DEPOSIT_BASE_ALLOWED_ = true; } + + // ============ Advanced Control Functions ============ + + function disableBuying() external onlySupervisorOrOwner { + _BUYING_ALLOWED_ = false; + } + + function enableBuying() external onlyOwner notClosed { + _BUYING_ALLOWED_ = true; + } + + function disableSelling() external onlySupervisorOrOwner { + _SELLING_ALLOWED_ = false; + } + + function enableSelling() external onlyOwner notClosed { + _SELLING_ALLOWED_ = true; + } + + function setBaseBalanceLimit(uint256 newBaseBalanceLimit) external onlyOwner notClosed { + _BASE_BALANCE_LIMIT_ = newBaseBalanceLimit; + } + + function setQuoteBalanceLimit(uint256 newQuoteBalanceLimit) external onlyOwner notClosed { + _QUOTE_BALANCE_LIMIT_ = newQuoteBalanceLimit; + } } diff --git a/contracts/impl/Settlement.sol b/contracts/impl/Settlement.sol index 087a627..d301a5b 100644 --- a/contracts/impl/Settlement.sol +++ b/contracts/impl/Settlement.sol @@ -15,6 +15,7 @@ import {Types} from "../lib/Types.sol"; import {IERC20} from "../intf/IERC20.sol"; import {Storage} from "./Storage.sol"; + /** * @title Settlement * @author DODO Breeder @@ -34,11 +35,16 @@ contract Settlement is Storage { // ============ Assets IN/OUT Functions ============ function _baseTokenTransferIn(address from, uint256 amount) internal { + require(_BASE_BALANCE_.add(amount) <= _BASE_BALANCE_LIMIT_, "BASE_BALANCE_LIMIT_EXCEEDED"); IERC20(_BASE_TOKEN_).safeTransferFrom(from, address(this), amount); _BASE_BALANCE_ = _BASE_BALANCE_.add(amount); } function _quoteTokenTransferIn(address from, uint256 amount) internal { + require( + _QUOTE_BALANCE_.add(amount) <= _QUOTE_BALANCE_LIMIT_, + "QUOTE_BALANCE_LIMIT_EXCEEDED" + ); IERC20(_QUOTE_TOKEN_).safeTransferFrom(from, address(this), amount); _QUOTE_BALANCE_ = _QUOTE_BALANCE_.add(amount); } diff --git a/contracts/impl/Storage.sol b/contracts/impl/Storage.sol index dd34d3e..7828bde 100644 --- a/contracts/impl/Storage.sol +++ b/contracts/impl/Storage.sol @@ -16,6 +16,7 @@ import {IOracle} from "../intf/IOracle.sol"; import {IDODOLpToken} from "../intf/IDODOLpToken.sol"; import {Types} from "../lib/Types.sol"; + /** * @title Storage * @author DODO Breeder @@ -34,6 +35,12 @@ contract Storage is InitializableOwnable, ReentrancyGuard { bool public _TRADE_ALLOWED_; uint256 public _GAS_PRICE_LIMIT_; + // ============ Advanced Controls ============ + bool public _BUYING_ALLOWED_; + bool public _SELLING_ALLOWED_; + uint256 public _BASE_BALANCE_LIMIT_; + uint256 public _QUOTE_BALANCE_LIMIT_; + // ============ Core Address ============ address public _SUPERVISOR_; // could freeze system in emergency @@ -106,6 +113,6 @@ contract Storage is InitializableOwnable, ReentrancyGuard { // ============ Version Control ============ function version() external pure returns (uint256) { - return 100; // 1.0.0 + return 101; // 1.0.1 } } diff --git a/contracts/impl/Trader.sol b/contracts/impl/Trader.sol index c18d4cf..36d00d9 100644 --- a/contracts/impl/Trader.sol +++ b/contracts/impl/Trader.sol @@ -16,6 +16,7 @@ import {Storage} from "./Storage.sol"; import {Pricing} from "./Pricing.sol"; import {Settlement} from "./Settlement.sol"; + /** * @title Trader * @author DODO Breeder @@ -40,6 +41,16 @@ contract Trader is Storage, Pricing, Settlement { _; } + modifier buyingAllowed() { + require(_BUYING_ALLOWED_, "BUYING_NOT_ALLOWED"); + _; + } + + modifier sellingAllowed() { + require(_SELLING_ALLOWED_, "SELLING_NOT_ALLOWED"); + _; + } + modifier gasPriceLimit() { require(tx.gasprice <= _GAS_PRICE_LIMIT_, "GAS_PRICE_EXCEED"); _; @@ -51,7 +62,7 @@ contract Trader is Storage, Pricing, Settlement { uint256 amount, uint256 minReceiveQuote, bytes calldata data - ) external tradeAllowed gasPriceLimit preventReentrant returns (uint256) { + ) external tradeAllowed sellingAllowed gasPriceLimit preventReentrant returns (uint256) { // query price ( uint256 receiveQuote, @@ -95,7 +106,7 @@ contract Trader is Storage, Pricing, Settlement { uint256 amount, uint256 maxPayQuote, bytes calldata data - ) external tradeAllowed gasPriceLimit preventReentrant returns (uint256) { + ) external tradeAllowed buyingAllowed gasPriceLimit preventReentrant returns (uint256) { // query price ( uint256 payQuote, diff --git a/test/Admin.test.ts b/test/Admin.test.ts index 3b95c64..49fda32 100644 --- a/test/Admin.test.ts +++ b/test/Admin.test.ts @@ -5,336 +5,606 @@ */ +import * as assert from 'assert'; + import { DODOContext, getDODOContext } from './utils/Context'; import { decimalStr } from './utils/Converter'; -// import BigNumber from "bignumber.js"; -import * as assert from "assert" -let lp1: string -let lp2: string -let trader: string -let tempAccount: string +let lp1: string; +let lp2: string; +let trader: string; +let tempAccount: string; async function init(ctx: DODOContext): Promise { - await ctx.setOraclePrice(decimalStr("100")) - tempAccount = ctx.spareAccounts[5] - lp1 = ctx.spareAccounts[0] - lp2 = ctx.spareAccounts[1] - trader = ctx.spareAccounts[2] - await ctx.mintTestToken(lp1, decimalStr("100"), decimalStr("10000")) - await ctx.mintTestToken(lp2, decimalStr("100"), decimalStr("10000")) - await ctx.mintTestToken(trader, decimalStr("100"), decimalStr("10000")) - await ctx.approveDODO(lp1) - await ctx.approveDODO(lp2) - await ctx.approveDODO(trader) + await ctx.setOraclePrice(decimalStr("100")); + tempAccount = ctx.spareAccounts[5]; + lp1 = ctx.spareAccounts[0]; + lp2 = ctx.spareAccounts[1]; + trader = ctx.spareAccounts[2]; + await ctx.mintTestToken(lp1, decimalStr("100"), decimalStr("10000")); + await ctx.mintTestToken(lp2, decimalStr("100"), decimalStr("10000")); + await ctx.mintTestToken(trader, decimalStr("100"), decimalStr("10000")); + await ctx.approveDODO(lp1); + await ctx.approveDODO(lp2); + await ctx.approveDODO(trader); } describe("Admin", () => { - - let snapshotId: string - let ctx: DODOContext + let snapshotId: string; + let ctx: DODOContext; before(async () => { - ctx = await getDODOContext() + ctx = await getDODOContext(); await init(ctx); - }) + }); beforeEach(async () => { snapshotId = await ctx.EVM.snapshot(); }); afterEach(async () => { - await ctx.EVM.reset(snapshotId) + await ctx.EVM.reset(snapshotId); }); describe("Settings", () => { it("set oracle", async () => { - await ctx.DODO.methods.setOracle(tempAccount).send(ctx.sendParam(ctx.Deployer)) - assert.equal(await ctx.DODO.methods._ORACLE_().call(), tempAccount) - }) + await ctx.DODO.methods + .setOracle(tempAccount) + .send(ctx.sendParam(ctx.Deployer)); + assert.equal(await ctx.DODO.methods._ORACLE_().call(), tempAccount); + }); it("set suprevisor", async () => { - await ctx.DODO.methods.setSupervisor(tempAccount).send(ctx.sendParam(ctx.Deployer)) - assert.equal(await ctx.DODO.methods._SUPERVISOR_().call(), tempAccount) - }) + await ctx.DODO.methods + .setSupervisor(tempAccount) + .send(ctx.sendParam(ctx.Deployer)); + assert.equal(await ctx.DODO.methods._SUPERVISOR_().call(), tempAccount); + }); it("set maintainer", async () => { - await ctx.DODO.methods.setMaintainer(tempAccount).send(ctx.sendParam(ctx.Deployer)) - assert.equal(await ctx.DODO.methods._MAINTAINER_().call(), tempAccount) - }) + await ctx.DODO.methods + .setMaintainer(tempAccount) + .send(ctx.sendParam(ctx.Deployer)); + assert.equal(await ctx.DODO.methods._MAINTAINER_().call(), tempAccount); + }); it("set liquidity provider fee rate", async () => { - await ctx.DODO.methods.setLiquidityProviderFeeRate(decimalStr("0.01")).send(ctx.sendParam(ctx.Deployer)) - assert.equal(await ctx.DODO.methods._LP_FEE_RATE_().call(), decimalStr("0.01")) - }) + await ctx.DODO.methods + .setLiquidityProviderFeeRate(decimalStr("0.01")) + .send(ctx.sendParam(ctx.Deployer)); + assert.equal( + await ctx.DODO.methods._LP_FEE_RATE_().call(), + decimalStr("0.01") + ); + }); it("set maintainer fee rate", async () => { - await ctx.DODO.methods.setMaintainerFeeRate(decimalStr("0.01")).send(ctx.sendParam(ctx.Deployer)) - assert.equal(await ctx.DODO.methods._MT_FEE_RATE_().call(), decimalStr("0.01")) - }) + await ctx.DODO.methods + .setMaintainerFeeRate(decimalStr("0.01")) + .send(ctx.sendParam(ctx.Deployer)); + assert.equal( + await ctx.DODO.methods._MT_FEE_RATE_().call(), + decimalStr("0.01") + ); + }); it("set k", async () => { - await ctx.DODO.methods.setK(decimalStr("0.2")).send(ctx.sendParam(ctx.Deployer)) - assert.equal(await ctx.DODO.methods._K_().call(), decimalStr("0.2")) - }) + await ctx.DODO.methods + .setK(decimalStr("0.2")) + .send(ctx.sendParam(ctx.Deployer)); + assert.equal(await ctx.DODO.methods._K_().call(), decimalStr("0.2")); + }); it("set gas price limit", async () => { - await ctx.DODO.methods.setGasPriceLimit(decimalStr("100")).send(ctx.sendParam(ctx.Deployer)) - assert.equal(await ctx.DODO.methods._GAS_PRICE_LIMIT_().call(), decimalStr("100")) - }) - }) + await ctx.DODO.methods + .setGasPriceLimit(decimalStr("100")) + .send(ctx.sendParam(ctx.Deployer)); + assert.equal( + await ctx.DODO.methods._GAS_PRICE_LIMIT_().call(), + decimalStr("100") + ); + }); + }); describe("Controls", () => { it("control flow", async () => { - await ctx.DODO.methods.disableBaseDeposit().send(ctx.sendParam(ctx.Supervisor)) + await ctx.DODO.methods + .disableBaseDeposit() + .send(ctx.sendParam(ctx.Supervisor)); await assert.rejects( ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)), /DEPOSIT_BASE_NOT_ALLOWED/ - ) + ); - await ctx.DODO.methods.enableBaseDeposit().send(ctx.sendParam(ctx.Deployer)) - await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - assert.equal(await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), decimalStr("10")) + await ctx.DODO.methods + .enableBaseDeposit() + .send(ctx.sendParam(ctx.Deployer)); + await ctx.DODO.methods + .depositBase(decimalStr("10")) + .send(ctx.sendParam(lp1)); + assert.equal( + await ctx.DODO.methods._TARGET_BASE_TOKEN_AMOUNT_().call(), + decimalStr("10") + ); - await ctx.DODO.methods.disableQuoteDeposit().send(ctx.sendParam(ctx.Supervisor)) + await ctx.DODO.methods + .disableQuoteDeposit() + .send(ctx.sendParam(ctx.Supervisor)); await assert.rejects( - ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)), + ctx.DODO.methods + .depositQuote(decimalStr("1000")) + .send(ctx.sendParam(lp1)), /DEPOSIT_QUOTE_NOT_ALLOWED/ - ) + ); - await ctx.DODO.methods.enableQuoteDeposit().send(ctx.sendParam(ctx.Deployer)) - await ctx.DODO.methods.depositQuote(decimalStr("10")).send(ctx.sendParam(lp1)) - assert.equal(await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), decimalStr("10")) + await ctx.DODO.methods + .enableQuoteDeposit() + .send(ctx.sendParam(ctx.Deployer)); + await ctx.DODO.methods + .depositQuote(decimalStr("10")) + .send(ctx.sendParam(lp1)); + assert.equal( + await ctx.DODO.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call(), + decimalStr("10") + ); - await ctx.DODO.methods.disableTrading().send(ctx.sendParam(ctx.Supervisor)) + await ctx.DODO.methods + .disableTrading() + .send(ctx.sendParam(ctx.Supervisor)); await assert.rejects( - ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("200"), "0x").send(ctx.sendParam(trader)), + ctx.DODO.methods + .buyBaseToken(decimalStr("1"), decimalStr("200"), "0x") + .send(ctx.sendParam(trader)), /TRADE_NOT_ALLOWED/ - ) + ); - await ctx.DODO.methods.enableTrading().send(ctx.sendParam(ctx.Deployer)) - await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("200"), "0x").send(ctx.sendParam(trader)) - assert.equal(await ctx.BASE.methods.balanceOf(trader).call(), decimalStr("101")) - }) + await ctx.DODO.methods.enableTrading().send(ctx.sendParam(ctx.Deployer)); + await ctx.DODO.methods + .buyBaseToken(decimalStr("1"), decimalStr("200"), "0x") + .send(ctx.sendParam(trader)); + assert.equal( + await ctx.BASE.methods.balanceOf(trader).call(), + decimalStr("101") + ); + }); it("control flow premission", async () => { await assert.rejects( ctx.DODO.methods.setGasPriceLimit("1").send(ctx.sendParam(trader)), /NOT_SUPERVISOR_OR_OWNER/ - ) + ); await assert.rejects( ctx.DODO.methods.disableTrading().send(ctx.sendParam(trader)), /NOT_SUPERVISOR_OR_OWNER/ - ) + ); await assert.rejects( ctx.DODO.methods.disableQuoteDeposit().send(ctx.sendParam(trader)), /NOT_SUPERVISOR_OR_OWNER/ - ) + ); await assert.rejects( ctx.DODO.methods.disableBaseDeposit().send(ctx.sendParam(trader)), /NOT_SUPERVISOR_OR_OWNER/ - ) + ); + await assert.rejects( + ctx.DODO.methods.disableBuying().send(ctx.sendParam(trader)), + /NOT_SUPERVISOR_OR_OWNER/ + ); + await assert.rejects( + ctx.DODO.methods.disableSelling().send(ctx.sendParam(trader)), + /NOT_SUPERVISOR_OR_OWNER/ + ); await assert.rejects( ctx.DODO.methods.setOracle(trader).send(ctx.sendParam(trader)), /NOT_OWNER/ - ) + ); await assert.rejects( ctx.DODO.methods.setSupervisor(trader).send(ctx.sendParam(trader)), /NOT_OWNER/ - ) + ); await assert.rejects( ctx.DODO.methods.setMaintainer(trader).send(ctx.sendParam(trader)), /NOT_OWNER/ - ) + ); await assert.rejects( - ctx.DODO.methods.setLiquidityProviderFeeRate(decimalStr("0.1")).send(ctx.sendParam(trader)), + ctx.DODO.methods + .setLiquidityProviderFeeRate(decimalStr("0.1")) + .send(ctx.sendParam(trader)), /NOT_OWNER/ - ) + ); await assert.rejects( - ctx.DODO.methods.setMaintainerFeeRate(decimalStr("0.1")).send(ctx.sendParam(trader)), + ctx.DODO.methods + .setMaintainerFeeRate(decimalStr("0.1")) + .send(ctx.sendParam(trader)), /NOT_OWNER/ - ) + ); await assert.rejects( ctx.DODO.methods.setK(decimalStr("0.1")).send(ctx.sendParam(trader)), /NOT_OWNER/ - ) + ); await assert.rejects( ctx.DODO.methods.enableTrading().send(ctx.sendParam(trader)), /NOT_OWNER/ - ) + ); await assert.rejects( ctx.DODO.methods.enableQuoteDeposit().send(ctx.sendParam(trader)), /NOT_OWNER/ - ) + ); await assert.rejects( ctx.DODO.methods.enableBaseDeposit().send(ctx.sendParam(trader)), /NOT_OWNER/ - ) - }) - }) + ); + await assert.rejects( + ctx.DODO.methods.enableBuying().send(ctx.sendParam(trader)), + /NOT_OWNER/ + ); + await assert.rejects( + ctx.DODO.methods.enableSelling().send(ctx.sendParam(trader)), + /NOT_OWNER/ + ); + await assert.rejects( + ctx.DODO.methods + .setBaseBalanceLimit(decimalStr("0")) + .send(ctx.sendParam(trader)), + /NOT_OWNER/ + ); + await assert.rejects( + ctx.DODO.methods + .setQuoteBalanceLimit(decimalStr("0")) + .send(ctx.sendParam(trader)), + /NOT_OWNER/ + ); + await assert.rejects( + ctx.DODO.methods.enableTrading().send(ctx.sendParam(trader)), + /NOT_OWNER/ + ); + }); + + it("advanced controls", async () => { + await ctx.DODO.methods + .depositBase(decimalStr("10")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .depositQuote(decimalStr("10")) + .send(ctx.sendParam(lp1)); + + await ctx.DODO.methods + .disableBuying() + .send(ctx.sendParam(ctx.Supervisor)); + await assert.rejects( + ctx.DODO.methods + .buyBaseToken(decimalStr("1"), decimalStr("200"), "0x") + .send(ctx.sendParam(trader)), + /BUYING_NOT_ALLOWED/ + ); + await ctx.DODO.methods.enableBuying().send(ctx.sendParam(ctx.Deployer)); + + await ctx.DODO.methods + .disableSelling() + .send(ctx.sendParam(ctx.Supervisor)); + await assert.rejects( + ctx.DODO.methods + .sellBaseToken(decimalStr("1"), decimalStr("200"), "0x") + .send(ctx.sendParam(trader)), + /SELLING_NOT_ALLOWED/ + ); + await ctx.DODO.methods.enableSelling().send(ctx.sendParam(ctx.Deployer)); + + await ctx.DODO.methods + .setBaseBalanceLimit(decimalStr("0")) + .send(ctx.sendParam(ctx.Deployer)); + await assert.rejects( + ctx.DODO.methods + .depositBase(decimalStr("1000")) + .send(ctx.sendParam(lp1)), + /BASE_BALANCE_LIMIT_EXCEEDED/ + ); + + await ctx.DODO.methods + .setQuoteBalanceLimit(decimalStr("0")) + .send(ctx.sendParam(ctx.Deployer)); + await assert.rejects( + ctx.DODO.methods + .depositQuote(decimalStr("1000")) + .send(ctx.sendParam(lp1)), + /QUOTE_BALANCE_LIMIT_EXCEEDED/ + ); + }); + }); describe("Final settlement", () => { it("final settlement when R is ONE", async () => { - await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods + .depositBase(decimalStr("10")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .depositQuote(decimalStr("1000")) + .send(ctx.sendParam(lp1)); - await ctx.DODO.methods.finalSettlement().send(ctx.sendParam(ctx.Deployer)) + await ctx.DODO.methods + .finalSettlement() + .send(ctx.sendParam(ctx.Deployer)); - await ctx.DODO.methods.claimAssets().send(ctx.sendParam(lp1)) - await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp1)) - await ctx.DODO.methods.withdrawAllQuote().send(ctx.sendParam(lp1)) + await ctx.DODO.methods.claimAssets().send(ctx.sendParam(lp1)); + await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp1)); + await ctx.DODO.methods.withdrawAllQuote().send(ctx.sendParam(lp1)); - assert.equal(await ctx.BASE.methods.balanceOf(lp1).call(), decimalStr("100")) - assert.equal(await ctx.QUOTE.methods.balanceOf(lp1).call(), decimalStr("10000")) - }) + assert.equal( + await ctx.BASE.methods.balanceOf(lp1).call(), + decimalStr("100") + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(lp1).call(), + decimalStr("10000") + ); + }); it("final settlement when R is ABOVE ONE", async () => { - await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods + .depositBase(decimalStr("10")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .depositQuote(decimalStr("1000")) + .send(ctx.sendParam(lp1)); - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x").send(ctx.sendParam(trader)) - await ctx.DODO.methods.finalSettlement().send(ctx.sendParam(ctx.Deployer)) - assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0") + await ctx.DODO.methods + .buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x") + .send(ctx.sendParam(trader)); + await ctx.DODO.methods + .finalSettlement() + .send(ctx.sendParam(ctx.Deployer)); + assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0"); - await ctx.DODO.methods.claimAssets().send(ctx.sendParam(lp1)) - assert.equal(await ctx.BASE.methods.balanceOf(lp1).call(), decimalStr("90")) - assert.equal(await ctx.QUOTE.methods.balanceOf(lp1).call(), "9551951805416248746110") - await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp1)) - await ctx.DODO.methods.withdrawAllQuote().send(ctx.sendParam(lp1)) - assert.equal(await ctx.BASE.methods.balanceOf(lp1).call(), decimalStr("94.995")) - assert.equal(await ctx.QUOTE.methods.balanceOf(lp1).call(), "10551951805416248746110") - }) + await ctx.DODO.methods.claimAssets().send(ctx.sendParam(lp1)); + assert.equal( + await ctx.BASE.methods.balanceOf(lp1).call(), + decimalStr("90") + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(lp1).call(), + "9551951805416248746110" + ); + await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp1)); + await ctx.DODO.methods.withdrawAllQuote().send(ctx.sendParam(lp1)); + assert.equal( + await ctx.BASE.methods.balanceOf(lp1).call(), + decimalStr("94.995") + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(lp1).call(), + "10551951805416248746110" + ); + }); it("final settlement when R is BELOW ONE", async () => { - await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods + .depositBase(decimalStr("10")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .depositQuote(decimalStr("1000")) + .send(ctx.sendParam(lp1)); - await ctx.DODO.methods.sellBaseToken(decimalStr("5"), decimalStr("100"), "0x").send(ctx.sendParam(trader)) - await ctx.DODO.methods.finalSettlement().send(ctx.sendParam(ctx.Deployer)) - assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0") + await ctx.DODO.methods + .sellBaseToken(decimalStr("5"), decimalStr("100"), "0x") + .send(ctx.sendParam(trader)); + await ctx.DODO.methods + .finalSettlement() + .send(ctx.sendParam(ctx.Deployer)); + assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0"); - await ctx.DODO.methods.claimAssets().send(ctx.sendParam(lp1)) - assert.equal(await ctx.BASE.methods.balanceOf(lp1).call(), decimalStr("95")) - assert.equal(await ctx.QUOTE.methods.balanceOf(lp1).call(), decimalStr("9000")) - await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp1)) - await ctx.DODO.methods.withdrawAllQuote().send(ctx.sendParam(lp1)) - assert.equal(await ctx.BASE.methods.balanceOf(lp1).call(), decimalStr("105")) - assert.equal(await ctx.QUOTE.methods.balanceOf(lp1).call(), "9540265973590798352835") - }) + await ctx.DODO.methods.claimAssets().send(ctx.sendParam(lp1)); + assert.equal( + await ctx.BASE.methods.balanceOf(lp1).call(), + decimalStr("95") + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(lp1).call(), + decimalStr("9000") + ); + await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp1)); + await ctx.DODO.methods.withdrawAllQuote().send(ctx.sendParam(lp1)); + assert.equal( + await ctx.BASE.methods.balanceOf(lp1).call(), + decimalStr("105") + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(lp1).call(), + "9540265973590798352835" + ); + }); it("final settlement revert cases", async () => { await assert.rejects( ctx.DODO.methods.claimAssets().send(ctx.sendParam(lp1)), /DODO_NOT_CLOSED/ - ) - await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.depositQuote(decimalStr("500")).send(ctx.sendParam(lp2)) + ); + await ctx.DODO.methods + .depositBase(decimalStr("10")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .depositQuote(decimalStr("500")) + .send(ctx.sendParam(lp2)); - await ctx.DODO.methods.buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x").send(ctx.sendParam(trader)) - await ctx.DODO.methods.finalSettlement().send(ctx.sendParam(ctx.Deployer)) + await ctx.DODO.methods + .buyBaseToken(decimalStr("5"), decimalStr("1000"), "0x") + .send(ctx.sendParam(trader)); + await ctx.DODO.methods + .finalSettlement() + .send(ctx.sendParam(ctx.Deployer)); await assert.rejects( ctx.DODO.methods.finalSettlement().send(ctx.sendParam(ctx.Deployer)), / DODO_CLOSED/ - ) + ); - await ctx.DODO.methods.claimAssets().send(ctx.sendParam(lp2)) + await ctx.DODO.methods.claimAssets().send(ctx.sendParam(lp2)); await assert.rejects( ctx.DODO.methods.claimAssets().send(ctx.sendParam(lp2)), /ALREADY_CLAIMED/ - ) + ); await assert.rejects( ctx.DODO.methods.enableQuoteDeposit().send(ctx.sendParam(ctx.Deployer)), /DODO_CLOSED/ - ) + ); await assert.rejects( ctx.DODO.methods.enableBaseDeposit().send(ctx.sendParam(ctx.Deployer)), /DODO_CLOSED/ - ) + ); await assert.rejects( ctx.DODO.methods.enableTrading().send(ctx.sendParam(ctx.Deployer)), /DODO_CLOSED/ - ) - }) - }) + ); + await assert.rejects( + ctx.DODO.methods.enableBuying().send(ctx.sendParam(ctx.Deployer)), + /DODO_CLOSED/ + ); + await assert.rejects( + ctx.DODO.methods.enableSelling().send(ctx.sendParam(ctx.Deployer)), + /DODO_CLOSED/ + ); + }); + }); describe("donate", () => { it("donate quote & base token", async () => { - await ctx.DODO.methods.depositBase(decimalStr("10")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.depositBase(decimalStr("20")).send(ctx.sendParam(lp2)) - await ctx.DODO.methods.depositQuote(decimalStr("1000")).send(ctx.sendParam(lp1)) - await ctx.DODO.methods.depositQuote(decimalStr("2000")).send(ctx.sendParam(lp2)) + await ctx.DODO.methods + .depositBase(decimalStr("10")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .depositBase(decimalStr("20")) + .send(ctx.sendParam(lp2)); + await ctx.DODO.methods + .depositQuote(decimalStr("1000")) + .send(ctx.sendParam(lp1)); + await ctx.DODO.methods + .depositQuote(decimalStr("2000")) + .send(ctx.sendParam(lp2)); - await ctx.DODO.methods.donateBaseToken(decimalStr("2")).send(ctx.sendParam(trader)) - await ctx.DODO.methods.donateQuoteToken(decimalStr("500")).send(ctx.sendParam(trader)) + await ctx.DODO.methods + .donateBaseToken(decimalStr("2")) + .send(ctx.sendParam(trader)); + await ctx.DODO.methods + .donateQuoteToken(decimalStr("500")) + .send(ctx.sendParam(trader)); - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp1).call(), "10666666666666666666") - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), "1166666666666666666666") - assert.equal(await ctx.DODO.methods.getLpBaseBalance(lp2).call(), "21333333333333333333") - assert.equal(await ctx.DODO.methods.getLpQuoteBalance(lp2).call(), "2333333333333333333333") + assert.equal( + await ctx.DODO.methods.getLpBaseBalance(lp1).call(), + "10666666666666666666" + ); + assert.equal( + await ctx.DODO.methods.getLpQuoteBalance(lp1).call(), + "1166666666666666666666" + ); + assert.equal( + await ctx.DODO.methods.getLpBaseBalance(lp2).call(), + "21333333333333333333" + ); + assert.equal( + await ctx.DODO.methods.getLpQuoteBalance(lp2).call(), + "2333333333333333333333" + ); - await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp1)) - await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp2)) + await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp1)); + await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp2)); - await ctx.DODO.methods.withdrawAllQuote().send(ctx.sendParam(lp1)) - await ctx.DODO.methods.withdrawAllQuote().send(ctx.sendParam(lp2)) + await ctx.DODO.methods.withdrawAllQuote().send(ctx.sendParam(lp1)); + await ctx.DODO.methods.withdrawAllQuote().send(ctx.sendParam(lp2)); - assert.equal(await ctx.BASE.methods.balanceOf(lp1).call(), "100666666666666666666") - assert.equal(await ctx.BASE.methods.balanceOf(lp2).call(), "101333333333333333334") - assert.equal(await ctx.QUOTE.methods.balanceOf(lp1).call(), "10166666666666666666666") - assert.equal(await ctx.QUOTE.methods.balanceOf(lp2).call(), "10333333333333333333334") - }) - }) + assert.equal( + await ctx.BASE.methods.balanceOf(lp1).call(), + "100666666666666666666" + ); + assert.equal( + await ctx.BASE.methods.balanceOf(lp2).call(), + "101333333333333333334" + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(lp1).call(), + "10166666666666666666666" + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(lp2).call(), + "10333333333333333333334" + ); + }); + }); describe("retrieve", () => { it("retrieve base token", async () => { - await ctx.BASE.methods.transfer(ctx.DODO.options.address, decimalStr("1")).send(ctx.sendParam(trader)) + await ctx.BASE.methods + .transfer(ctx.DODO.options.address, decimalStr("1")) + .send(ctx.sendParam(trader)); await assert.rejects( - ctx.DODO.methods.retrieve(ctx.BASE.options.address, decimalStr("1")).send(ctx.sendParam(trader)), + ctx.DODO.methods + .retrieve(ctx.BASE.options.address, decimalStr("1")) + .send(ctx.sendParam(trader)), /NOT_OWNER/ - ) + ); await assert.rejects( - ctx.DODO.methods.retrieve(ctx.BASE.options.address, decimalStr("2")).send(ctx.sendParam(ctx.Deployer)), + ctx.DODO.methods + .retrieve(ctx.BASE.options.address, decimalStr("2")) + .send(ctx.sendParam(ctx.Deployer)), /DODO_BASE_BALANCE_NOT_ENOUGH/ - ) - await ctx.DODO.methods.retrieve(ctx.BASE.options.address, decimalStr("1")).send(ctx.sendParam(ctx.Deployer)) - assert.equal(await ctx.BASE.methods.balanceOf(ctx.Deployer).call(), decimalStr("1")) - }) + ); + await ctx.DODO.methods + .retrieve(ctx.BASE.options.address, decimalStr("1")) + .send(ctx.sendParam(ctx.Deployer)); + assert.equal( + await ctx.BASE.methods.balanceOf(ctx.Deployer).call(), + decimalStr("1") + ); + }); it("retrieve quote token", async () => { - await ctx.QUOTE.methods.transfer(ctx.DODO.options.address, decimalStr("1")).send(ctx.sendParam(trader)) + await ctx.QUOTE.methods + .transfer(ctx.DODO.options.address, decimalStr("1")) + .send(ctx.sendParam(trader)); await assert.rejects( - ctx.DODO.methods.retrieve(ctx.QUOTE.options.address, decimalStr("2")).send(ctx.sendParam(ctx.Deployer)), + ctx.DODO.methods + .retrieve(ctx.QUOTE.options.address, decimalStr("2")) + .send(ctx.sendParam(ctx.Deployer)), /DODO_QUOTE_BALANCE_NOT_ENOUGH/ - ) - await ctx.DODO.methods.retrieve(ctx.QUOTE.options.address, decimalStr("1")).send(ctx.sendParam(ctx.Deployer)) - assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Deployer).call(), decimalStr("1")) - }) - }) + ); + await ctx.DODO.methods + .retrieve(ctx.QUOTE.options.address, decimalStr("1")) + .send(ctx.sendParam(ctx.Deployer)); + assert.equal( + await ctx.QUOTE.methods.balanceOf(ctx.Deployer).call(), + decimalStr("1") + ); + }); + }); describe("revert cases", () => { it("k revert cases", async () => { await assert.rejects( - ctx.DODO.methods.setK(decimalStr("1")).send(ctx.sendParam(ctx.Deployer)), + ctx.DODO.methods + .setK(decimalStr("1")) + .send(ctx.sendParam(ctx.Deployer)), /K>=1/ - ) + ); await assert.rejects( - ctx.DODO.methods.setK(decimalStr("0")).send(ctx.sendParam(ctx.Deployer)), + ctx.DODO.methods + .setK(decimalStr("0")) + .send(ctx.sendParam(ctx.Deployer)), /K=0/ - ) - }) + ); + }); it("fee revert cases", async () => { await assert.rejects( - ctx.DODO.methods.setLiquidityProviderFeeRate(decimalStr("0.999")).send(ctx.sendParam(ctx.Deployer)), + ctx.DODO.methods + .setLiquidityProviderFeeRate(decimalStr("0.999")) + .send(ctx.sendParam(ctx.Deployer)), /FEE_RATE>=1/ - ) + ); await assert.rejects( - ctx.DODO.methods.setMaintainerFeeRate(decimalStr("0.998")).send(ctx.sendParam(ctx.Deployer)), + ctx.DODO.methods + .setMaintainerFeeRate(decimalStr("0.998")) + .send(ctx.sendParam(ctx.Deployer)), /FEE_RATE>=1/ - ) - }) - }) -}) \ No newline at end of file + ); + }); + }); +}); diff --git a/test/DODOEthProxyAsBase.test.ts b/test/DODOEthProxyAsBase.test.ts index e72babc..85d674b 100644 --- a/test/DODOEthProxyAsBase.test.ts +++ b/test/DODOEthProxyAsBase.test.ts @@ -44,6 +44,9 @@ async function init(ctx: DODOContext): Promise { .getDODO(WETH.options.address, ctx.QUOTE.options.address) .call() ); + await ctx.DODO.methods.enableBaseDeposit().send(ctx.sendParam(ctx.Deployer)); + await ctx.DODO.methods.enableQuoteDeposit().send(ctx.sendParam(ctx.Deployer)); + await ctx.DODO.methods.enableTrading().send(ctx.sendParam(ctx.Deployer)); ctx.BASE = WETH; @@ -102,12 +105,11 @@ describe("DODO ETH PROXY", () => { it("buy", async () => { const buyAmount = "1"; await logGas( - DODOEthProxy.methods - .buyEthWithToken( - ctx.QUOTE.options.address, - decimalStr(buyAmount), - decimalStr("200") - ), + DODOEthProxy.methods.buyEthWithToken( + ctx.QUOTE.options.address, + decimalStr(buyAmount), + decimalStr("200") + ), ctx.sendParam(trader), "buy ETH with token directly" ); @@ -123,12 +125,11 @@ describe("DODO ETH PROXY", () => { it("sell", async () => { const sellAmount = "1"; await logGas( - DODOEthProxy.methods - .sellEthToToken( - ctx.QUOTE.options.address, - decimalStr(sellAmount), - decimalStr("50") - ), + DODOEthProxy.methods.sellEthToToken( + ctx.QUOTE.options.address, + decimalStr(sellAmount), + decimalStr("50") + ), ctx.sendParam(trader, sellAmount), "sell ETH to token directly" ); diff --git a/test/DODOEthProxyAsQuote.test.ts b/test/DODOEthProxyAsQuote.test.ts index 04b1932..1941803 100644 --- a/test/DODOEthProxyAsQuote.test.ts +++ b/test/DODOEthProxyAsQuote.test.ts @@ -44,6 +44,9 @@ async function init(ctx: DODOContext): Promise { .getDODO(ctx.BASE.options.address, WETH.options.address) .call() ); + await ctx.DODO.methods.enableBaseDeposit().send(ctx.sendParam(ctx.Deployer)); + await ctx.DODO.methods.enableQuoteDeposit().send(ctx.sendParam(ctx.Deployer)); + await ctx.DODO.methods.enableTrading().send(ctx.sendParam(ctx.Deployer)); ctx.QUOTE = WETH; @@ -103,12 +106,15 @@ describe("DODO ETH PROXY", () => { const maxPayEthAmount = "2.1"; const ethInPoolBefore = decimalStr("10"); const traderEthBalanceBefore = await ctx.Web3.eth.getBalance(trader); - const txReceipt: TransactionReceipt = await logGas(DODOEthProxy.methods - .buyTokenWithEth( + const txReceipt: TransactionReceipt = await logGas( + DODOEthProxy.methods.buyTokenWithEth( ctx.BASE.options.address, decimalStr("200"), decimalStr(maxPayEthAmount) - ), ctx.sendParam(trader, maxPayEthAmount), "buy token with ETH directly"); + ), + ctx.sendParam(trader, maxPayEthAmount), + "buy token with ETH directly" + ); const ethInPoolAfter = "12056338203652739553"; assert.strictEqual( await ctx.DODO.methods._QUOTE_BALANCE_().call(), @@ -133,12 +139,11 @@ describe("DODO ETH PROXY", () => { it("sell", async () => { const minReceiveEthAmount = "0.45"; await logGas( - DODOEthProxy.methods - .sellTokenToEth( - ctx.BASE.options.address, - decimalStr("50"), - decimalStr(minReceiveEthAmount) - ), + DODOEthProxy.methods.sellTokenToEth( + ctx.BASE.options.address, + decimalStr("50"), + decimalStr(minReceiveEthAmount) + ), ctx.sendParam(trader), "sell token to ETH directly" ); diff --git a/test/utils/Context.ts b/test/utils/Context.ts index 451bd44..2bf61ae 100644 --- a/test/utils/Context.ts +++ b/test/utils/Context.ts @@ -5,13 +5,14 @@ */ -import { EVM, getDefaultWeb3 } from "./EVM"; -import Web3 from "web3"; -import { Contract } from "web3-eth-contract"; -import BigNumber from "bignumber.js"; -import * as contracts from "./Contracts"; -import { decimalStr, gweiStr, MAX_UINT256 } from "./Converter"; -import * as log from "./Log"; +import BigNumber from 'bignumber.js'; +import Web3 from 'web3'; +import { Contract } from 'web3-eth-contract'; + +import * as contracts from './Contracts'; +import { decimalStr, gweiStr, MAX_UINT256 } from './Converter'; +import { EVM, getDefaultWeb3 } from './EVM'; +import * as log from './Log'; BigNumber.config({ EXPONENTIAL_AT: 1000, @@ -19,10 +20,10 @@ BigNumber.config({ }); export interface DODOContextInitConfig { - lpFeeRate: string, - mtFeeRate: string, - k: string, - gasPriceLimit: string, + lpFeeRate: string; + mtFeeRate: string; + k: string; + gasPriceLimit: string; } /* @@ -43,60 +44,99 @@ export let DefaultDODOContextInitConfig = { mtFeeRate: decimalStr("0.001"), k: decimalStr("0.1"), gasPriceLimit: gweiStr("100"), -} +}; export class DODOContext { - EVM: EVM - Web3: Web3 - DODO: Contract - DODOZoo: Contract - BASE: Contract - BaseCapital: Contract - QUOTE: Contract - QuoteCapital: Contract - ORACLE: Contract - Deployer: string - Supervisor: string - Maintainer: string - spareAccounts: string[] + EVM: EVM; + Web3: Web3; + DODO: Contract; + DODOZoo: Contract; + BASE: Contract; + BaseCapital: Contract; + QUOTE: Contract; + QuoteCapital: Contract; + ORACLE: Contract; + Deployer: string; + Supervisor: string; + Maintainer: string; + spareAccounts: string[]; - constructor() { } + constructor() {} async init(config: DODOContextInitConfig) { - this.EVM = new EVM - this.Web3 = getDefaultWeb3() - var cloneFactory = await contracts.newContract(contracts.CLONE_FACTORY_CONTRACT_NAME) + this.EVM = new EVM(); + this.Web3 = getDefaultWeb3(); + var cloneFactory = await contracts.newContract( + contracts.CLONE_FACTORY_CONTRACT_NAME + ); - this.BASE = await contracts.newContract(contracts.TEST_ERC20_CONTRACT_NAME, ["TestBase", 18]) - this.QUOTE = await contracts.newContract(contracts.TEST_ERC20_CONTRACT_NAME, ["TestQuote", 18]) - this.ORACLE = await contracts.newContract(contracts.NAIVE_ORACLE_CONTRACT_NAME) + this.BASE = await contracts.newContract( + contracts.TEST_ERC20_CONTRACT_NAME, + ["TestBase", 18] + ); + this.QUOTE = await contracts.newContract( + contracts.TEST_ERC20_CONTRACT_NAME, + ["TestQuote", 18] + ); + this.ORACLE = await contracts.newContract( + contracts.NAIVE_ORACLE_CONTRACT_NAME + ); const allAccounts = await this.Web3.eth.getAccounts(); - this.Deployer = allAccounts[0] - this.Supervisor = allAccounts[1] - this.Maintainer = allAccounts[2] - this.spareAccounts = allAccounts.slice(3, 10) + this.Deployer = allAccounts[0]; + this.Supervisor = allAccounts[1]; + this.Maintainer = allAccounts[2]; + this.spareAccounts = allAccounts.slice(3, 10); - var DODOTemplate = await contracts.newContract(contracts.DODO_CONTRACT_NAME) - this.DODOZoo = await contracts.newContract(contracts.DODO_ZOO_CONTRACT_NAME, [DODOTemplate.options.address, cloneFactory.options.address, this.Supervisor]) + var DODOTemplate = await contracts.newContract( + contracts.DODO_CONTRACT_NAME + ); + this.DODOZoo = await contracts.newContract( + contracts.DODO_ZOO_CONTRACT_NAME, + [ + DODOTemplate.options.address, + cloneFactory.options.address, + this.Supervisor, + ] + ); - await this.DODOZoo.methods.breedDODO( - this.Maintainer, - this.BASE.options.address, - this.QUOTE.options.address, - this.ORACLE.options.address, - config.lpFeeRate, - config.mtFeeRate, - config.k, - config.gasPriceLimit - ).send(this.sendParam(this.Deployer)) + await this.DODOZoo.methods + .breedDODO( + this.Maintainer, + this.BASE.options.address, + this.QUOTE.options.address, + this.ORACLE.options.address, + config.lpFeeRate, + config.mtFeeRate, + config.k, + config.gasPriceLimit + ) + .send(this.sendParam(this.Deployer)); - this.DODO = contracts.getContractWithAddress(contracts.DODO_CONTRACT_NAME, await this.DODOZoo.methods.getDODO(this.BASE.options.address, this.QUOTE.options.address).call()) + this.DODO = contracts.getContractWithAddress( + contracts.DODO_CONTRACT_NAME, + await this.DODOZoo.methods + .getDODO(this.BASE.options.address, this.QUOTE.options.address) + .call() + ); + await this.DODO.methods + .enableBaseDeposit() + .send(this.sendParam(this.Deployer)); + await this.DODO.methods + .enableQuoteDeposit() + .send(this.sendParam(this.Deployer)); + await this.DODO.methods.enableTrading().send(this.sendParam(this.Deployer)); - this.BaseCapital = contracts.getContractWithAddress(contracts.DODO_LP_TOKEN_CONTRACT_NAME, await this.DODO.methods._BASE_CAPITAL_TOKEN_().call()) - this.QuoteCapital = contracts.getContractWithAddress(contracts.DODO_LP_TOKEN_CONTRACT_NAME, await this.DODO.methods._QUOTE_CAPITAL_TOKEN_().call()) + this.BaseCapital = contracts.getContractWithAddress( + contracts.DODO_LP_TOKEN_CONTRACT_NAME, + await this.DODO.methods._BASE_CAPITAL_TOKEN_().call() + ); + this.QuoteCapital = contracts.getContractWithAddress( + contracts.DODO_LP_TOKEN_CONTRACT_NAME, + await this.DODO.methods._QUOTE_CAPITAL_TOKEN_().call() + ); - console.log(log.blueText("[Init dodo context]")) + console.log(log.blueText("[Init dodo context]")); } sendParam(sender, value = "0") { @@ -104,27 +144,37 @@ export class DODOContext { from: sender, gas: process.env["COVERAGE"] ? 10000000000 : 7000000, gasPrice: process.env.GAS_PRICE, - value: decimalStr(value) - } + value: decimalStr(value), + }; } async setOraclePrice(price: string) { - await this.ORACLE.methods.setPrice(price).send(this.sendParam(this.Deployer)) + await this.ORACLE.methods + .setPrice(price) + .send(this.sendParam(this.Deployer)); } async mintTestToken(to: string, base: string, quote: string) { - await this.BASE.methods.mint(to, base).send(this.sendParam(this.Deployer)) - await this.QUOTE.methods.mint(to, quote).send(this.sendParam(this.Deployer)) + await this.BASE.methods.mint(to, base).send(this.sendParam(this.Deployer)); + await this.QUOTE.methods + .mint(to, quote) + .send(this.sendParam(this.Deployer)); } async approveDODO(account: string) { - await this.BASE.methods.approve(this.DODO.options.address, MAX_UINT256).send(this.sendParam(account)) - await this.QUOTE.methods.approve(this.DODO.options.address, MAX_UINT256).send(this.sendParam(account)) + await this.BASE.methods + .approve(this.DODO.options.address, MAX_UINT256) + .send(this.sendParam(account)); + await this.QUOTE.methods + .approve(this.DODO.options.address, MAX_UINT256) + .send(this.sendParam(account)); } } -export async function getDODOContext(config: DODOContextInitConfig = DefaultDODOContextInitConfig): Promise { - var context = new DODOContext() - await context.init(config) - return context -} \ No newline at end of file +export async function getDODOContext( + config: DODOContextInitConfig = DefaultDODOContextInitConfig +): Promise { + var context = new DODOContext(); + await context.init(config); + return context; +} From 8fc6e24a70408c67244ed1b2a97510195269cdaa Mon Sep 17 00:00:00 2001 From: mingda Date: Sun, 13 Sep 2020 23:30:41 +0800 Subject: [PATCH 077/118] DODO Token related --- contracts/token/DODOMine.sol | 307 +++++++++++++++++++++++++++ contracts/token/DODOToken.sol | 106 +++++++++ contracts/token/LockedTokenVault.sol | 192 +++++++++++++++++ 3 files changed, 605 insertions(+) create mode 100644 contracts/token/DODOMine.sol create mode 100644 contracts/token/DODOToken.sol create mode 100644 contracts/token/LockedTokenVault.sol diff --git a/contracts/token/DODOMine.sol b/contracts/token/DODOMine.sol new file mode 100644 index 0000000..61c00d4 --- /dev/null +++ b/contracts/token/DODOMine.sol @@ -0,0 +1,307 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {Ownable} from "../lib/Ownable.sol"; +import {DecimalMath} from "../lib/DecimalMath.sol"; +import {SafeERC20} from "../lib/SafeERC20.sol"; +import {SafeMath} from "../lib/SafeMath.sol"; +import {IERC20} from "../intf/IERC20.sol"; + + +contract DODOMine is Ownable { + using SafeMath for uint256; + using SafeERC20 for IERC20; + + // Info of each user. + struct UserInfo { + uint256 amount; // How many LP tokens the user has provided. + uint256 rewardDebt; // Reward debt. See explanation below. + // + // We do some fancy math here. Basically, any point in time, the amount of DODOs + // entitled to a user but is pending to be distributed is: + // + // pending reward = (user.amount * pool.accDODOPerShare) - user.rewardDebt + // + // Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens: + // 1. The pool's `accDODOPerShare` (and `lastRewardBlock`) gets updated. + // 2. User receives the pending reward sent to his/her address. + // 3. User's `amount` gets updated. + // 4. User's `rewardDebt` gets updated. + } + + // Info of each pool. + struct PoolInfo { + address lpToken; // Address of LP token contract. + uint256 allocPoint; // How many allocation points assigned to this pool. DODOs to distribute per block. + uint256 lastRewardBlock; // Last block number that DODOs distribution occurs. + uint256 accDODOPerShare; // Accumulated DODOs per share, times 1e12. See below. + } + + address public dodoToken; + uint256 public dodoPerBlock; + + // Info of each pool. + PoolInfo[] public poolInfos; + mapping(address => uint256) public lpTokenRegistry; + + // Info of each user that stakes LP tokens. + mapping(uint256 => mapping(address => UserInfo)) public userInfo; + mapping(address => uint256) public realizedReward; + + // Total allocation poitns. Must be the sum of all allocation points in all pools. + uint256 public totalAllocPoint = 0; + // The block number when DODO mining starts. + uint256 public startBlock; + + event Deposit(address indexed user, uint256 indexed pid, uint256 amount); + event Withdraw(address indexed user, uint256 indexed pid, uint256 amount); + event Claim(address indexed user, uint256 amount); + + constructor(address _dodoToken, uint256 _startBlock) public { + dodoToken = _dodoToken; + startBlock = _startBlock; + } + + // ============ Modifiers ============ + + modifier lpTokenExist(address lpToken) { + require(lpTokenRegistry[lpToken] > 0, "LP Token Not Exist"); + _; + } + + modifier lpTokenNotExist(address lpToken) { + require(lpTokenRegistry[lpToken] == 0, "LP Token Already Exist"); + _; + } + + // ============ Helper ============ + + function poolLength() external view returns (uint256) { + return poolInfos.length; + } + + function getPid(address _lpToken) public view lpTokenExist(_lpToken) returns (uint256) { + return lpTokenRegistry[_lpToken] - 1; + } + + function getUserLpBalance(address _lpToken, address _user) public view returns (uint256) { + uint256 pid = getPid(_lpToken); + return userInfo[pid][_user].amount; + } + + // ============ Ownable ============ + + function addLpToken( + uint256 _allocPoint, + address _lpToken, + bool _withUpdate + ) public lpTokenNotExist(_lpToken) onlyOwner { + if (_withUpdate) { + massUpdatePools(); + } + uint256 lastRewardBlock = block.number > startBlock ? block.number : startBlock; + totalAllocPoint = totalAllocPoint.add(_allocPoint); + poolInfos.push( + PoolInfo({ + lpToken: _lpToken, + allocPoint: _allocPoint, + lastRewardBlock: lastRewardBlock, + accDODOPerShare: 0 + }) + ); + lpTokenRegistry[_lpToken] = poolInfos.length; + } + + function setLpToken( + address _lpToken, + uint256 _allocPoint, + bool _withUpdate + ) public onlyOwner { + if (_withUpdate) { + massUpdatePools(); + } + uint256 pid = getPid(_lpToken); + totalAllocPoint = totalAllocPoint.sub(poolInfos[pid].allocPoint).add(_allocPoint); + poolInfos[pid].allocPoint = _allocPoint; + } + + function setReward(uint256 _dodoPerBlock) external onlyOwner { + dodoPerBlock = _dodoPerBlock; + } + + // ============ View Rewards ============ + + function getPendingReward(address _lpToken, address _user) external view returns (uint256) { + uint256 pid = getPid(_lpToken); + PoolInfo storage pool = poolInfos[pid]; + UserInfo storage user = userInfo[pid][_user]; + uint256 accDODOPerShare = pool.accDODOPerShare; + uint256 lpSupply = IERC20(pool.lpToken).balanceOf(address(this)); + if (block.number > pool.lastRewardBlock && lpSupply != 0) { + uint256 DODOReward = block + .number + .sub(pool.lastRewardBlock) + .mul(dodoPerBlock) + .mul(pool.allocPoint) + .div(totalAllocPoint); + accDODOPerShare = accDODOPerShare.add(DecimalMath.divFloor(DODOReward, lpSupply)); + } + return DecimalMath.mul(user.amount, accDODOPerShare).sub(user.rewardDebt); + } + + function getAllPendingReward(address _user) external view returns (uint256) { + uint256 length = poolInfos.length; + uint256 totalReward = 0; + for (uint256 pid = 0; pid < length; ++pid) { + if (userInfo[pid][msg.sender].amount == 0) { + continue; // save gas + } + PoolInfo storage pool = poolInfos[pid]; + UserInfo storage user = userInfo[pid][_user]; + uint256 accDODOPerShare = pool.accDODOPerShare; + uint256 lpSupply = IERC20(pool.lpToken).balanceOf(address(this)); + if (block.number > pool.lastRewardBlock && lpSupply != 0) { + uint256 DODOReward = block + .number + .sub(pool.lastRewardBlock) + .mul(dodoPerBlock) + .mul(pool.allocPoint) + .div(totalAllocPoint); + accDODOPerShare = accDODOPerShare.add(DecimalMath.divFloor(DODOReward, lpSupply)); + } + totalReward = totalReward.add( + DecimalMath.mul(user.amount, accDODOPerShare).sub(user.rewardDebt) + ); + } + return totalReward; + } + + function getRealizedReward(address _user) external view returns (uint256) { + return realizedReward[_user]; + } + + // ============ Update Pools ============ + + // Update reward vairables for all pools. Be careful of gas spending! + function massUpdatePools() public { + uint256 length = poolInfos.length; + for (uint256 pid = 0; pid < length; ++pid) { + updatePool(pid); + } + } + + // Update reward variables of the given pool to be up-to-date. + function updatePool(uint256 _pid) public { + PoolInfo storage pool = poolInfos[_pid]; + if (block.number <= pool.lastRewardBlock) { + return; + } + uint256 lpSupply = IERC20(pool.lpToken).balanceOf(address(this)); + if (lpSupply == 0) { + pool.lastRewardBlock = block.number; + return; + } + uint256 DODOReward = block + .number + .sub(pool.lastRewardBlock) + .mul(dodoPerBlock) + .mul(pool.allocPoint) + .div(totalAllocPoint); + pool.accDODOPerShare = pool.accDODOPerShare.add(DecimalMath.divFloor(DODOReward, lpSupply)); + pool.lastRewardBlock = block.number; + } + + // ============ Deposit & Withdraw & Claim ============ + // Deposit & withdraw will also trigger claim + + function deposit(address _lpToken, uint256 _amount) public { + uint256 pid = getPid(_lpToken); + PoolInfo storage pool = poolInfos[pid]; + UserInfo storage user = userInfo[pid][msg.sender]; + updatePool(pid); + if (user.amount > 0) { + uint256 pending = DecimalMath.mul(user.amount, pool.accDODOPerShare).sub( + user.rewardDebt + ); + safeDODOTransfer(msg.sender, pending); + } + IERC20(pool.lpToken).safeTransferFrom(address(msg.sender), address(this), _amount); + user.amount = user.amount.add(_amount); + user.rewardDebt = DecimalMath.divFloor(user.amount, pool.accDODOPerShare); + emit Deposit(msg.sender, pid, _amount); + } + + // Withdraw LP tokens from MasterChef. + function withdraw(address _lpToken, uint256 _amount) public { + uint256 pid = getPid(_lpToken); + PoolInfo storage pool = poolInfos[pid]; + UserInfo storage user = userInfo[pid][msg.sender]; + require(user.amount >= _amount, "withdraw: not good"); + updatePool(pid); + uint256 pending = DecimalMath.mul(user.amount, pool.accDODOPerShare).sub(user.rewardDebt); + safeDODOTransfer(msg.sender, pending); + user.amount = user.amount.sub(_amount); + user.rewardDebt = DecimalMath.divFloor(user.amount, pool.accDODOPerShare); + IERC20(pool.lpToken).safeTransfer(address(msg.sender), _amount); + emit Withdraw(msg.sender, pid, _amount); + } + + function withdrawAll(address _lpToken) public { + uint256 balance = getUserLpBalance(_lpToken, msg.sender); + withdraw(_lpToken, balance); + } + + // Withdraw without caring about rewards. EMERGENCY ONLY. + function emergencyWithdraw(address _lpToken) public { + uint256 pid = getPid(_lpToken); + PoolInfo storage pool = poolInfos[pid]; + UserInfo storage user = userInfo[pid][msg.sender]; + IERC20(pool.lpToken).safeTransfer(address(msg.sender), user.amount); + user.amount = 0; + user.rewardDebt = 0; + } + + function claim(address _lpToken) public { + uint256 pid = getPid(_lpToken); + if (userInfo[pid][msg.sender].amount == 0) { + return; // save gas + } + PoolInfo storage pool = poolInfos[pid]; + UserInfo storage user = userInfo[pid][msg.sender]; + updatePool(pid); + uint256 pending = DecimalMath.mul(user.amount, pool.accDODOPerShare).sub(user.rewardDebt); + user.rewardDebt = DecimalMath.divFloor(user.amount, pool.accDODOPerShare); + safeDODOTransfer(msg.sender, pending); + } + + function claimAll() public { + uint256 length = poolInfos.length; + uint256 pending = 0; + for (uint256 pid = 0; pid < length; ++pid) { + if (userInfo[pid][msg.sender].amount == 0) { + continue; // save gas + } + PoolInfo storage pool = poolInfos[pid]; + UserInfo storage user = userInfo[pid][msg.sender]; + updatePool(pid); + pending = pending.add( + DecimalMath.mul(user.amount, pool.accDODOPerShare).sub(user.rewardDebt) + ); + user.rewardDebt = DecimalMath.divFloor(user.amount, pool.accDODOPerShare); + } + safeDODOTransfer(msg.sender, pending); + } + + // Safe DODO transfer function, just in case if rounding error causes pool to not have enough DODOs. + function safeDODOTransfer(address _to, uint256 _amount) internal { + IERC20(dodoToken).safeTransfer(_to, _amount); + realizedReward[_to] = realizedReward[_to].add(_amount); + } +} diff --git a/contracts/token/DODOToken.sol b/contracts/token/DODOToken.sol new file mode 100644 index 0000000..672611f --- /dev/null +++ b/contracts/token/DODOToken.sol @@ -0,0 +1,106 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {SafeMath} from "../lib/SafeMath.sol"; + + +/** + * @title DODO Token + * @author DODO Breeder + */ +contract DODOToken { + using SafeMath for uint256; + + string public symbol = "DODO"; + string public name = "DODO bird food"; + + uint256 public decimals = 18; + uint256 public totalSupply = 1000000000 * 10**18; // 1 Billion + + mapping(address => uint256) internal balances; + mapping(address => mapping(address => uint256)) internal allowed; + + // ============ Events ============ + + event Transfer(address indexed from, address indexed to, uint256 amount); + + event Approval(address indexed owner, address indexed spender, uint256 amount); + + // ============ Functions ============ + + constructor() public { + balances[msg.sender] = totalSupply; + } + + /** + * @dev transfer token for a specified address + * @param to The address to transfer to. + * @param amount The amount to be transferred. + */ + function transfer(address to, uint256 amount) public returns (bool) { + require(amount <= balances[msg.sender], "BALANCE_NOT_ENOUGH"); + + balances[msg.sender] = balances[msg.sender].sub(amount); + balances[to] = balances[to].add(amount); + emit Transfer(msg.sender, to, amount); + return true; + } + + /** + * @dev Gets the balance of the specified address. + * @param owner The address to query the the balance of. + * @return balance An uint256 representing the amount owned by the passed address. + */ + function balanceOf(address owner) external view returns (uint256 balance) { + return balances[owner]; + } + + /** + * @dev Transfer tokens from one address to another + * @param from address The address which you want to send tokens from + * @param to address The address which you want to transfer to + * @param amount uint256 the amount of tokens to be transferred + */ + function transferFrom( + address from, + address to, + uint256 amount + ) public returns (bool) { + require(amount <= balances[from], "BALANCE_NOT_ENOUGH"); + require(amount <= allowed[from][msg.sender], "ALLOWANCE_NOT_ENOUGH"); + + balances[from] = balances[from].sub(amount); + balances[to] = balances[to].add(amount); + allowed[from][msg.sender] = allowed[from][msg.sender].sub(amount); + emit Transfer(from, to, amount); + return true; + } + + /** + * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. + * @param spender The address which will spend the funds. + * @param amount The amount of tokens to be spent. + */ + function approve(address spender, uint256 amount) public returns (bool) { + allowed[msg.sender][spender] = amount; + emit Approval(msg.sender, spender, amount); + return true; + } + + /** + * @dev Function to check the amount of tokens that an owner allowed to a spender. + * @param owner address The address which owns the funds. + * @param spender address The address which will spend the funds. + * @return A uint256 specifying the amount of tokens still available for the spender. + */ + function allowance(address owner, address spender) public view returns (uint256) { + return allowed[owner][spender]; + } +} diff --git a/contracts/token/LockedTokenVault.sol b/contracts/token/LockedTokenVault.sol new file mode 100644 index 0000000..c25c868 --- /dev/null +++ b/contracts/token/LockedTokenVault.sol @@ -0,0 +1,192 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {SafeMath} from "../lib/SafeMath.sol"; +import {DecimalMath} from "../lib/DecimalMath.sol"; +import {Ownable} from "../lib/Ownable.sol"; +import {SafeERC20} from "../lib/SafeERC20.sol"; +import {IERC20} from "../intf/IERC20.sol"; + + +/** + * @title LockedTokenVault + * @author DODO Breeder + * + * @notice Lock Token and release it linearly + */ + +contract LockedTokenVault is Ownable { + using SafeMath for uint256; + using SafeERC20 for IERC20; + + address _TOKEN_; + + mapping(address => uint256) internal originBalances; + mapping(address => uint256) internal remainingBalances; + + mapping(address => bool) internal confirmOriginBalance; + mapping(address => address) internal holderTransferRequest; + + uint256 public _START_RELEASE_TIME_; + uint256 public _RELEASE_DURATION_; + + // ============ Modifiers ============ + + modifier beforeStartRelease() { + require(block.timestamp < _START_RELEASE_TIME_, "RELEASE START"); + _; + } + + modifier afterStartRelease() { + require(block.timestamp > _START_RELEASE_TIME_, "RELEASE NOT START"); + _; + } + + modifier holderConfirmed(address holder) { + require(confirmOriginBalance[holder], "HOLDER NOT CONFIRMED"); + _; + } + + modifier holderNotConfirmed(address holder) { + require(!confirmOriginBalance[holder], "HOLDER CONFIRMED"); + _; + } + + // ============ Init Functions ============ + + constructor( + address _token, + uint256 _startReleaseTime, + uint256 _releaseDuration + ) public { + _TOKEN_ = _token; + _START_RELEASE_TIME_ = _startReleaseTime; + _RELEASE_DURATION_ = _releaseDuration; + } + + function deposit(uint256 amount) external onlyOwner beforeStartRelease { + _tokenTransferIn(_OWNER_, amount); + originBalances[_OWNER_] = originBalances[_OWNER_].add(amount); + remainingBalances[_OWNER_] = remainingBalances[_OWNER_].add(amount); + } + + function withdraw(uint256 amount) external onlyOwner beforeStartRelease { + originBalances[_OWNER_] = originBalances[_OWNER_].sub(amount); + remainingBalances[_OWNER_] = remainingBalances[_OWNER_].sub(amount); + _tokenTransferOut(_OWNER_, amount); + } + + // ============ For Owner ============ + + function grant(address holder, uint256 amount) + external + onlyOwner + beforeStartRelease + holderNotConfirmed(holder) + { + originBalances[holder] = originBalances[holder].add(amount); + remainingBalances[holder] = remainingBalances[holder].add(amount); + + originBalances[_OWNER_] = originBalances[_OWNER_].sub(amount); + remainingBalances[_OWNER_] = remainingBalances[_OWNER_].sub(amount); + } + + function recall(address holder) + external + onlyOwner + beforeStartRelease + holderNotConfirmed(holder) + { + uint256 amount = originBalances[holder]; + + originBalances[holder] = 0; + remainingBalances[holder] = 0; + + originBalances[_OWNER_] = originBalances[_OWNER_].add(amount); + remainingBalances[_OWNER_] = remainingBalances[_OWNER_].add(amount); + } + + function executeHolderTransfer(address holder) external onlyOwner { + address newHolder = holderTransferRequest[holder]; + require(newHolder != address(0), "INVALID NEW HOLDER"); + require(originBalances[newHolder] == 0, "NOT NEW HOLDER"); + + originBalances[newHolder] = originBalances[holder]; + remainingBalances[newHolder] = remainingBalances[holder]; + + originBalances[holder] = 0; + remainingBalances[holder] = 0; + + holderTransferRequest[holder] = address(0); + } + + // ============ For Holder ============ + + function confirm() external { + confirmOriginBalance[msg.sender] = true; + } + + function cancelConfirm() external { + confirmOriginBalance[msg.sender] = false; + } + + function requestTransfer(address newHolder) external holderConfirmed(msg.sender) { + require(originBalances[newHolder] == 0, "NOT NEW HOLDER"); + holderTransferRequest[msg.sender] = newHolder; + } + + function claimToken() external afterStartRelease { + uint256 unLocked = getUnlockedBalance(msg.sender); + + _tokenTransferOut(msg.sender, unLocked); + remainingBalances[msg.sender] = remainingBalances[msg.sender].sub(unLocked); + } + + // ============ View ============ + + function getOriginBalance(address holder) external view returns (uint256) { + return originBalances[holder]; + } + + function getRemainingBalance(address holder) external view returns (uint256) { + return remainingBalances[holder]; + } + + function isConfirmed(address holder) external view returns (bool) { + return confirmOriginBalance[holder]; + } + + function getHolderTransferRequest(address holder) external view returns (address) { + return holderTransferRequest[holder]; + } + + function getUnlockedBalance(address holder) public view returns (uint256) { + if (block.timestamp < _START_RELEASE_TIME_) { + return 0; + } + uint256 newRemaining = 0; + uint256 timePast = block.timestamp.sub(_START_RELEASE_TIME_); + if (timePast < _RELEASE_DURATION_) { + uint256 remainingTime = _RELEASE_DURATION_.sub(timePast); + newRemaining = originBalances[holder].mul(remainingTime).div(_RELEASE_DURATION_); + } + return remainingBalances[msg.sender].sub(newRemaining); + } + + // ============ Internal Helper ============ + + function _tokenTransferIn(address from, uint256 amount) internal { + IERC20(_TOKEN_).safeTransferFrom(from, address(this), amount); + } + + function _tokenTransferOut(address to, uint256 amount) internal { + IERC20(_TOKEN_).safeTransfer(to, amount); + } +} From 84e73feb4518245acc7cece087a108c96a4edaca Mon Sep 17 00:00:00 2001 From: owen05 Date: Tue, 15 Sep 2020 17:52:24 +0800 Subject: [PATCH 078/118] Dodomine user rewardDebt bug fix --- contracts/token/DODOMine.sol | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/contracts/token/DODOMine.sol b/contracts/token/DODOMine.sol index 61c00d4..b5b384d 100644 --- a/contracts/token/DODOMine.sol +++ b/contracts/token/DODOMine.sol @@ -55,7 +55,7 @@ contract DODOMine is Ownable { mapping(uint256 => mapping(address => UserInfo)) public userInfo; mapping(address => uint256) public realizedReward; - // Total allocation poitns. Must be the sum of all allocation points in all pools. + // Total allocation points. Must be the sum of all allocation points in all pools. uint256 public totalAllocPoint = 0; // The block number when DODO mining starts. uint256 public startBlock; @@ -234,7 +234,7 @@ contract DODOMine is Ownable { } IERC20(pool.lpToken).safeTransferFrom(address(msg.sender), address(this), _amount); user.amount = user.amount.add(_amount); - user.rewardDebt = DecimalMath.divFloor(user.amount, pool.accDODOPerShare); + user.rewardDebt = DecimalMath.mul(user.amount, pool.accDODOPerShare); emit Deposit(msg.sender, pid, _amount); } @@ -248,7 +248,7 @@ contract DODOMine is Ownable { uint256 pending = DecimalMath.mul(user.amount, pool.accDODOPerShare).sub(user.rewardDebt); safeDODOTransfer(msg.sender, pending); user.amount = user.amount.sub(_amount); - user.rewardDebt = DecimalMath.divFloor(user.amount, pool.accDODOPerShare); + user.rewardDebt = DecimalMath.mul(user.amount, pool.accDODOPerShare); IERC20(pool.lpToken).safeTransfer(address(msg.sender), _amount); emit Withdraw(msg.sender, pid, _amount); } @@ -277,7 +277,7 @@ contract DODOMine is Ownable { UserInfo storage user = userInfo[pid][msg.sender]; updatePool(pid); uint256 pending = DecimalMath.mul(user.amount, pool.accDODOPerShare).sub(user.rewardDebt); - user.rewardDebt = DecimalMath.divFloor(user.amount, pool.accDODOPerShare); + user.rewardDebt = DecimalMath.mul(user.amount, pool.accDODOPerShare); safeDODOTransfer(msg.sender, pending); } @@ -294,7 +294,7 @@ contract DODOMine is Ownable { pending = pending.add( DecimalMath.mul(user.amount, pool.accDODOPerShare).sub(user.rewardDebt) ); - user.rewardDebt = DecimalMath.divFloor(user.amount, pool.accDODOPerShare); + user.rewardDebt = DecimalMath.mul(user.amount, pool.accDODOPerShare); } safeDODOTransfer(msg.sender, pending); } From d64d204031ff8261e0bded0bc57847f3342ed3b7 Mon Sep 17 00:00:00 2001 From: mingda Date: Thu, 17 Sep 2020 15:04:11 +0800 Subject: [PATCH 079/118] DODO Token --- contracts/token/DODOMine.sol | 8 +- package-lock.json | 1519 ++++++++++++++++++++++++++++++- package.json | 3 +- test/DODOZoo.test.ts | 7 + test/Trader.test.ts | 48 + test/UniswapArbitrageur.test.ts | 26 + test/utils/Contracts.ts | 8 + test/utils/SlippageFormula.ts | 16 + 8 files changed, 1620 insertions(+), 15 deletions(-) diff --git a/contracts/token/DODOMine.sol b/contracts/token/DODOMine.sol index b5b384d..9cb11a5 100644 --- a/contracts/token/DODOMine.sol +++ b/contracts/token/DODOMine.sol @@ -160,7 +160,7 @@ contract DODOMine is Ownable { uint256 length = poolInfos.length; uint256 totalReward = 0; for (uint256 pid = 0; pid < length; ++pid) { - if (userInfo[pid][msg.sender].amount == 0) { + if (userInfo[pid][msg.sender].amount == 0 || poolInfos[pid].allocPoint == 0) { continue; // save gas } PoolInfo storage pool = poolInfos[pid]; @@ -238,7 +238,6 @@ contract DODOMine is Ownable { emit Deposit(msg.sender, pid, _amount); } - // Withdraw LP tokens from MasterChef. function withdraw(address _lpToken, uint256 _amount) public { uint256 pid = getPid(_lpToken); PoolInfo storage pool = poolInfos[pid]; @@ -270,7 +269,7 @@ contract DODOMine is Ownable { function claim(address _lpToken) public { uint256 pid = getPid(_lpToken); - if (userInfo[pid][msg.sender].amount == 0) { + if (userInfo[pid][msg.sender].amount == 0 || poolInfos[pid].allocPoint == 0) { return; // save gas } PoolInfo storage pool = poolInfos[pid]; @@ -285,7 +284,7 @@ contract DODOMine is Ownable { uint256 length = poolInfos.length; uint256 pending = 0; for (uint256 pid = 0; pid < length; ++pid) { - if (userInfo[pid][msg.sender].amount == 0) { + if (userInfo[pid][msg.sender].amount == 0 || poolInfos[pid].allocPoint == 0) { continue; // save gas } PoolInfo storage pool = poolInfos[pid]; @@ -303,5 +302,6 @@ contract DODOMine is Ownable { function safeDODOTransfer(address _to, uint256 _amount) internal { IERC20(dodoToken).safeTransfer(_to, _amount); realizedReward[_to] = realizedReward[_to].add(_amount); + emit Claim(_to, _amount); } } diff --git a/package-lock.json b/package-lock.json index b5c0f03..14c102b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -53,6 +53,52 @@ "@babel/types": "^7.10.1" } }, + "@babel/helper-module-imports": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz", + "integrity": "sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + }, + "dependencies": { + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "@babel/types": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.0.tgz", + "integrity": "sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + } + } + }, + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + }, "@babel/helper-split-export-declaration": { "version": "7.10.1", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.1.tgz", @@ -88,6 +134,52 @@ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.2.tgz", "integrity": "sha512-PApSXlNMJyB4JiGVhCOlzKIif+TKFTvu0aQAhnTvfP/z3vVSN6ZypH5bfUNwFXXjRQtUEBNFd2PtmCmG2Py3qQ==" }, + "@babel/plugin-transform-runtime": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.11.0.tgz", + "integrity": "sha512-LFEsP+t3wkYBlis8w6/kmnd6Kb1dxTd+wGJ8MlxTGzQo//ehtqlVL4S9DNUa53+dtPSQobN2CXx4d81FqC58cw==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "resolve": "^1.8.1", + "semver": "^5.5.1" + }, + "dependencies": { + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "@babel/runtime": { + "version": "7.11.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.11.2.tgz", + "integrity": "sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.4" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", + "dev": true + } + } + }, "@babel/template": { "version": "7.10.1", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.1.tgz", @@ -251,14 +343,14 @@ } }, "@ethersproject/signing-key": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.0.1.tgz", - "integrity": "sha512-Z3yMPFFf4KkWltndDNi/tpese7qZh6ZWKbGu3DHd8xOX0PJqbScdAs6gCfFeMatO06qyX307Y52soc/Ayf8ZSg==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.0.3.tgz", + "integrity": "sha512-5QPZaBRGCLzfVMbFb3LcVjNR0UbTXnwDHASnQYfbzwUOnFYHKxHsrcbl/5ONGoppgi8yXgOocKqlPCFycJJVWQ==", "requires": { "@ethersproject/bytes": "^5.0.0", "@ethersproject/logger": "^5.0.0", "@ethersproject/properties": "^5.0.0", - "elliptic": "6.5.2" + "elliptic": "6.5.3" } }, "@ethersproject/strings": { @@ -338,6 +430,96 @@ "integrity": "sha512-UIfVKsXSXocKnn5+RNklUXNoGd/JVj7V8KmC48TQzmjU33HQI86PX0JDS7SpHMHasI3w9X//1q7Lu7nZtj3Zzg==", "dev": true }, + "@truffle/hdwallet-provider": { + "version": "1.0.42", + "resolved": "https://registry.npmjs.org/@truffle/hdwallet-provider/-/hdwallet-provider-1.0.42.tgz", + "integrity": "sha512-Q6+Pn6x9oLE0lTk72xC4V7il/UoI2i6dy8kSfh4xjYkE585SO9sc7ndXqX5K+epPolr7UAndEe7Lv6mHjiPmsQ==", + "dev": true, + "requires": { + "@trufflesuite/web3-provider-engine": "15.0.13-1", + "@types/web3": "^1.0.20", + "any-promise": "^1.3.0", + "bindings": "^1.5.0", + "ethereum-cryptography": "^0.1.3", + "ethereum-protocol": "^1.0.1", + "ethereumjs-tx": "^1.0.0", + "ethereumjs-util": "^6.1.0", + "ethereumjs-wallet": "^0.6.3", + "source-map-support": "^0.5.19" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + }, + "ethereum-common": { + "version": "0.0.18", + "resolved": "https://registry.npmjs.org/ethereum-common/-/ethereum-common-0.0.18.tgz", + "integrity": "sha1-L9w1dvIykDNYl26znaeDIT/5Uj8=", + "dev": true + }, + "ethereumjs-tx": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-1.3.7.tgz", + "integrity": "sha512-wvLMxzt1RPhAQ9Yi3/HKZTn0FZYpnsmQdbKYfUUpi4j1SEIcbkd9tndVjcPrufY3V7j2IebOpC00Zp2P/Ay2kA==", + "dev": true, + "requires": { + "ethereum-common": "^0.0.18", + "ethereumjs-util": "^5.0.0" + }, + "dependencies": { + "ethereumjs-util": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz", + "integrity": "sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ==", + "dev": true, + "requires": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "^0.1.3", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1" + } + } + } + }, + "ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", + "dev": true, + "requires": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + } + } + }, "@truffle/interface-adapter": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@truffle/interface-adapter/-/interface-adapter-0.3.3.tgz", @@ -750,6 +932,279 @@ } } }, + "@trufflesuite/eth-json-rpc-filters": { + "version": "4.1.2-1", + "resolved": "https://registry.npmjs.org/@trufflesuite/eth-json-rpc-filters/-/eth-json-rpc-filters-4.1.2-1.tgz", + "integrity": "sha512-/MChvC5dw2ck9NU1cZmdovCz2VKbOeIyR4tcxDvA5sT+NaL0rA2/R5U0yI7zsbo1zD+pgqav77rQHTzpUdDNJQ==", + "dev": true, + "requires": { + "@trufflesuite/eth-json-rpc-middleware": "^4.4.2-0", + "await-semaphore": "^0.1.3", + "eth-query": "^2.1.2", + "json-rpc-engine": "^5.1.3", + "lodash.flatmap": "^4.5.0", + "safe-event-emitter": "^1.0.1" + } + }, + "@trufflesuite/eth-json-rpc-infura": { + "version": "4.0.3-0", + "resolved": "https://registry.npmjs.org/@trufflesuite/eth-json-rpc-infura/-/eth-json-rpc-infura-4.0.3-0.tgz", + "integrity": "sha512-xaUanOmo0YLqRsL0SfXpFienhdw5bpQ1WEXxMTRi57az4lwpZBv4tFUDvcerdwJrxX9wQqNmgUgd1BrR01dumw==", + "dev": true, + "requires": { + "@trufflesuite/eth-json-rpc-middleware": "^4.4.2-1", + "cross-fetch": "^2.1.1", + "eth-json-rpc-errors": "^1.0.1", + "json-rpc-engine": "^5.1.3" + }, + "dependencies": { + "eth-json-rpc-errors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/eth-json-rpc-errors/-/eth-json-rpc-errors-1.1.1.tgz", + "integrity": "sha512-WT5shJ5KfNqHi9jOZD+ID8I1kuYWNrigtZat7GOQkvwo99f8SzAVaEcWhJUv656WiZOAg3P1RiJQANtUmDmbIg==", + "dev": true, + "requires": { + "fast-safe-stringify": "^2.0.6" + } + } + } + }, + "@trufflesuite/eth-json-rpc-middleware": { + "version": "4.4.2-1", + "resolved": "https://registry.npmjs.org/@trufflesuite/eth-json-rpc-middleware/-/eth-json-rpc-middleware-4.4.2-1.tgz", + "integrity": "sha512-iEy9H8ja7/8aYES5HfrepGBKU9n/Y4OabBJEklVd/zIBlhCCBAWBqkIZgXt11nBXO/rYAeKwYuE3puH3ByYnLA==", + "dev": true, + "requires": { + "@trufflesuite/eth-sig-util": "^1.4.2", + "btoa": "^1.2.1", + "clone": "^2.1.1", + "eth-json-rpc-errors": "^1.0.1", + "eth-query": "^2.1.2", + "ethereumjs-block": "^1.6.0", + "ethereumjs-tx": "^1.3.7", + "ethereumjs-util": "^5.1.2", + "ethereumjs-vm": "^2.6.0", + "fetch-ponyfill": "^4.0.0", + "json-rpc-engine": "^5.1.3", + "json-stable-stringify": "^1.0.1", + "pify": "^3.0.0", + "safe-event-emitter": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + }, + "eth-json-rpc-errors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/eth-json-rpc-errors/-/eth-json-rpc-errors-1.1.1.tgz", + "integrity": "sha512-WT5shJ5KfNqHi9jOZD+ID8I1kuYWNrigtZat7GOQkvwo99f8SzAVaEcWhJUv656WiZOAg3P1RiJQANtUmDmbIg==", + "dev": true, + "requires": { + "fast-safe-stringify": "^2.0.6" + } + }, + "ethereum-common": { + "version": "0.0.18", + "resolved": "https://registry.npmjs.org/ethereum-common/-/ethereum-common-0.0.18.tgz", + "integrity": "sha1-L9w1dvIykDNYl26znaeDIT/5Uj8=", + "dev": true + }, + "ethereumjs-tx": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-1.3.7.tgz", + "integrity": "sha512-wvLMxzt1RPhAQ9Yi3/HKZTn0FZYpnsmQdbKYfUUpi4j1SEIcbkd9tndVjcPrufY3V7j2IebOpC00Zp2P/Ay2kA==", + "dev": true, + "requires": { + "ethereum-common": "^0.0.18", + "ethereumjs-util": "^5.0.0" + } + }, + "ethereumjs-util": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz", + "integrity": "sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ==", + "dev": true, + "requires": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "^0.1.3", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "@trufflesuite/eth-sig-util": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@trufflesuite/eth-sig-util/-/eth-sig-util-1.4.2.tgz", + "integrity": "sha512-+GyfN6b0LNW77hbQlH3ufZ/1eCON7mMrGym6tdYf7xiNw9Vv3jBO72bmmos1EId2NgBvPMhmYYm6DSLQFTmzrA==", + "dev": true, + "requires": { + "ethereumjs-abi": "^0.6.8", + "ethereumjs-util": "^5.1.1" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + }, + "ethereumjs-util": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz", + "integrity": "sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ==", + "dev": true, + "requires": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "^0.1.3", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1" + } + } + } + }, + "@trufflesuite/web3-provider-engine": { + "version": "15.0.13-1", + "resolved": "https://registry.npmjs.org/@trufflesuite/web3-provider-engine/-/web3-provider-engine-15.0.13-1.tgz", + "integrity": "sha512-6u3x/iIN5fyj8pib5QTUDmIOUiwAGhaqdSTXdqCu6v9zo2BEwdCqgEJd1uXDh3DBmPRDfiZ/ge8oUPy7LerpHg==", + "dev": true, + "requires": { + "@trufflesuite/eth-json-rpc-filters": "^4.1.2-1", + "@trufflesuite/eth-json-rpc-infura": "^4.0.3-0", + "@trufflesuite/eth-json-rpc-middleware": "^4.4.2-1", + "@trufflesuite/eth-sig-util": "^1.4.2", + "async": "^2.5.0", + "backoff": "^2.5.0", + "clone": "^2.0.0", + "cross-fetch": "^2.1.0", + "eth-block-tracker": "^4.4.2", + "eth-json-rpc-errors": "^2.0.2", + "ethereumjs-block": "^1.2.2", + "ethereumjs-tx": "^1.2.0", + "ethereumjs-util": "^5.1.5", + "ethereumjs-vm": "^2.3.4", + "json-stable-stringify": "^1.0.1", + "promise-to-callback": "^1.0.0", + "readable-stream": "^2.2.9", + "request": "^2.85.0", + "semaphore": "^1.0.3", + "ws": "^5.1.1", + "xhr": "^2.2.0", + "xtend": "^4.0.1" + }, + "dependencies": { + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + }, + "ethereum-common": { + "version": "0.0.18", + "resolved": "https://registry.npmjs.org/ethereum-common/-/ethereum-common-0.0.18.tgz", + "integrity": "sha1-L9w1dvIykDNYl26znaeDIT/5Uj8=", + "dev": true + }, + "ethereumjs-tx": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-1.3.7.tgz", + "integrity": "sha512-wvLMxzt1RPhAQ9Yi3/HKZTn0FZYpnsmQdbKYfUUpi4j1SEIcbkd9tndVjcPrufY3V7j2IebOpC00Zp2P/Ay2kA==", + "dev": true, + "requires": { + "ethereum-common": "^0.0.18", + "ethereumjs-util": "^5.0.0" + } + }, + "ethereumjs-util": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz", + "integrity": "sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ==", + "dev": true, + "requires": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "^0.1.3", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, + "ws": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", + "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + } + } + }, "@types/bn.js": { "version": "4.11.6", "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", @@ -794,6 +1249,33 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.10.tgz", "integrity": "sha512-Bz23oN/5bi0rniKT24ExLf4cK0JdvN3dH/3k0whYkdN4eI4vS2ZW/2ENNn2uxHCzWcbdHIa/GRuWQytfzCjRYw==" }, + "@types/pbkdf2": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.0.tgz", + "integrity": "sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/secp256k1": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.1.tgz", + "integrity": "sha512-+ZjSA8ELlOp8SlKi0YLB2tz9d5iPNEmOBd+8Rz21wTMdaXQIa9b6TEnD6l5qKOCypE7FSyPyck12qZJxSDNoog==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/web3": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/web3/-/web3-1.2.2.tgz", + "integrity": "sha512-eFiYJKggNrOl0nsD+9cMh2MLk4zVBfXfGnVeRFbpiZzBE20eet4KLA3fXcjSuHaBn0RnQzwLAGdgzgzdet4C0A==", + "dev": true, + "requires": { + "web3": "*" + } + }, "@web3-js/scrypt-shim": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/@web3-js/scrypt-shim/-/scrypt-shim-0.1.0.tgz", @@ -848,6 +1330,15 @@ "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", "dev": true }, + "abstract-leveldown": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-2.6.3.tgz", + "integrity": "sha512-2++wDf/DYqkPR3o5tbfdhF96EfMApo1GpPfzOsR/ZYXdkSmELlvOOEAl9iKkRsktMPHdGjO4rtkBpf2I7TiTeA==", + "dev": true, + "requires": { + "xtend": "~4.0.0" + } + }, "accepts": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", @@ -1098,6 +1589,26 @@ "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", "optional": true }, + "async-eventemitter": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/async-eventemitter/-/async-eventemitter-0.2.4.tgz", + "integrity": "sha512-pd20BwL7Yt1zwDFy+8MX8F1+WCT8aQeKj0kQnTrH9WaeRETlRamVhD0JtRPmrV4GfOJ2F9CvdQkZeZhnh2TuHw==", + "dev": true, + "requires": { + "async": "^2.4.0" + }, + "dependencies": { + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + } + } + }, "async-limiter": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", @@ -1122,6 +1633,12 @@ "array-filter": "^1.0.0" } }, + "await-semaphore": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/await-semaphore/-/await-semaphore-0.1.3.tgz", + "integrity": "sha512-d1W2aNSYcz/sxYO4pMGX9vq65qOTu0P800epMud+6cYYX0QcT7zyqcxec3VWzpgvdXo57UWmVbZpLMjX2m1I7Q==", + "dev": true + }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -1445,6 +1962,15 @@ "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" }, + "backoff": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/backoff/-/backoff-2.5.0.tgz", + "integrity": "sha1-9hbtqdPktmuMp/ynn2lXIsX44m8=", + "dev": true, + "requires": { + "precond": "0.2" + } + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -1606,6 +2132,12 @@ } } }, + "blakejs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.1.0.tgz", + "integrity": "sha1-ad+S75U6qIylGjLfarHFShVfx6U=", + "dev": true + }, "bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -1741,6 +2273,32 @@ "safe-buffer": "^5.2.0" } }, + "bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", + "dev": true, + "requires": { + "base-x": "^3.0.2" + } + }, + "bs58check": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", + "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "dev": true, + "requires": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, + "btoa": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz", + "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==", + "dev": true + }, "buffer": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", @@ -1898,6 +2456,15 @@ "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=" }, + "checkpoint-store": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/checkpoint-store/-/checkpoint-store-1.1.0.tgz", + "integrity": "sha1-BOTLUWuRQziTWB5tRgGnjpVS6gY=", + "dev": true, + "requires": { + "functional-red-black-tree": "^1.0.1" + } + }, "chokidar": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", @@ -2057,6 +2624,12 @@ } } }, + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "dev": true + }, "clone-response": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", @@ -2096,6 +2669,11 @@ "delayed-stream": "~1.0.0" } }, + "command-exists": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==" + }, "commander": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", @@ -2241,6 +2819,24 @@ "sha.js": "^2.4.8" } }, + "cross-fetch": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-2.2.3.tgz", + "integrity": "sha512-PrWWNH3yL2NYIb/7WF/5vFG3DCQiXDOVf8k3ijatbrtnwNuhMWLC7YF7uqf53tbTFDzHIUD8oITw4Bxt8ST3Nw==", + "dev": true, + "requires": { + "node-fetch": "2.1.2", + "whatwg-fetch": "2.0.4" + }, + "dependencies": { + "node-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz", + "integrity": "sha1-q4hOjn5X44qUR1POxwb3iNF2i7U=", + "dev": true + } + } + }, "crypto-browserify": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", @@ -2420,6 +3016,15 @@ "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" }, + "deferred-leveldown": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-1.2.2.tgz", + "integrity": "sha512-uukrWD2bguRtXilKt6cAWKyoXrTSMo5m7crUdLfWQmu8kIm88w3QZoUL+6nhpfKVmhHANER6Re3sKoNoZ3IKMA==", + "dev": true, + "requires": { + "abstract-leveldown": "~2.6.0" + } + }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", @@ -2619,9 +3224,9 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "elliptic": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz", - "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz", + "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", "requires": { "bn.js": "^4.4.0", "brorand": "^1.0.1", @@ -2650,6 +3255,26 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" }, + "encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "requires": { + "iconv-lite": "^0.6.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", + "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, "end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -2658,6 +3283,15 @@ "once": "^1.4.0" } }, + "errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "dev": true, + "requires": { + "prr": "~1.0.1" + } + }, "es-abstract": { "version": "1.17.6", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", @@ -2792,6 +3426,28 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, + "eth-block-tracker": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-4.4.3.tgz", + "integrity": "sha512-A8tG4Z4iNg4mw5tP1Vung9N9IjgMNqpiMoJ/FouSFwNCGHv2X0mmOYwtQOJzki6XN7r7Tyo01S29p7b224I4jw==", + "dev": true, + "requires": { + "@babel/plugin-transform-runtime": "^7.5.5", + "@babel/runtime": "^7.5.5", + "eth-query": "^2.1.0", + "json-rpc-random-id": "^1.0.1", + "pify": "^3.0.0", + "safe-event-emitter": "^1.0.1" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, "eth-ens-namehash": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz", @@ -2801,6 +3457,15 @@ "js-sha3": "^0.5.7" } }, + "eth-json-rpc-errors": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/eth-json-rpc-errors/-/eth-json-rpc-errors-2.0.2.tgz", + "integrity": "sha512-uBCRM2w2ewusRHGxN8JhcuOb2RN3ueAOYH/0BhqdFmQkZx5lj5+fLKTz0mIVOzd4FG5/kUksCzCD7eTEim6gaA==", + "dev": true, + "requires": { + "fast-safe-stringify": "^2.0.6" + } + }, "eth-lib": { "version": "0.1.29", "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.1.29.tgz", @@ -2821,6 +3486,25 @@ } } }, + "eth-query": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/eth-query/-/eth-query-2.1.2.tgz", + "integrity": "sha1-1nQdkAAQa1FRDHLbktY2VFam2l4=", + "dev": true, + "requires": { + "json-rpc-random-id": "^1.0.0", + "xtend": "^4.0.1" + } + }, + "eth-rpc-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eth-rpc-errors/-/eth-rpc-errors-3.0.0.tgz", + "integrity": "sha512-iPPNHPrLwUlR9xCSYm7HHQjWBasor3+KZfRvwEWxMz3ca0yqnlBeJrnyphkGIXZ4J7AMAaOLmwy4AWhnxOiLxg==", + "dev": true, + "requires": { + "fast-safe-stringify": "^2.0.6" + } + }, "ethereum-bloom-filters": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.7.tgz", @@ -2836,6 +3520,185 @@ } } }, + "ethereum-common": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/ethereum-common/-/ethereum-common-0.2.0.tgz", + "integrity": "sha512-XOnAR/3rntJgbCdGhqdaLIxDLWKLmsZOGhHdBKadEr6gEnJLH52k93Ou+TUdFaPN3hJc3isBZBal3U/XZ15abA==", + "dev": true + }, + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + }, + "dependencies": { + "scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", + "dev": true + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + } + } + }, + "ethereum-protocol": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ethereum-protocol/-/ethereum-protocol-1.0.1.tgz", + "integrity": "sha512-3KLX1mHuEsBW0dKG+c6EOJS1NBNqdCICvZW9sInmZTt5aY0oxmHVggYRE0lJu1tcnMD1K+AKHdLi6U43Awm1Vg==", + "dev": true + }, + "ethereumjs-abi": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz", + "integrity": "sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==", + "dev": true, + "requires": { + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + }, + "ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", + "dev": true, + "requires": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" + } + } + } + }, + "ethereumjs-account": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/ethereumjs-account/-/ethereumjs-account-2.0.5.tgz", + "integrity": "sha512-bgDojnXGjhMwo6eXQC0bY6UK2liSFUSMwwylOmQvZbSl/D7NXQ3+vrGO46ZeOgjGfxXmgIeVNDIiHw7fNZM4VA==", + "dev": true, + "requires": { + "ethereumjs-util": "^5.0.0", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + }, + "ethereumjs-util": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz", + "integrity": "sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ==", + "dev": true, + "requires": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "^0.1.3", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1" + } + } + } + }, + "ethereumjs-block": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/ethereumjs-block/-/ethereumjs-block-1.7.1.tgz", + "integrity": "sha512-B+sSdtqm78fmKkBq78/QLKJbu/4Ts4P2KFISdgcuZUPDm9x+N7qgBPIIFUGbaakQh8bzuquiRVbdmvPKqbILRg==", + "dev": true, + "requires": { + "async": "^2.0.1", + "ethereum-common": "0.2.0", + "ethereumjs-tx": "^1.2.2", + "ethereumjs-util": "^5.0.0", + "merkle-patricia-tree": "^2.1.2" + }, + "dependencies": { + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + }, + "ethereumjs-tx": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-1.3.7.tgz", + "integrity": "sha512-wvLMxzt1RPhAQ9Yi3/HKZTn0FZYpnsmQdbKYfUUpi4j1SEIcbkd9tndVjcPrufY3V7j2IebOpC00Zp2P/Ay2kA==", + "dev": true, + "requires": { + "ethereum-common": "^0.0.18", + "ethereumjs-util": "^5.0.0" + }, + "dependencies": { + "ethereum-common": { + "version": "0.0.18", + "resolved": "https://registry.npmjs.org/ethereum-common/-/ethereum-common-0.0.18.tgz", + "integrity": "sha1-L9w1dvIykDNYl26znaeDIT/5Uj8=", + "dev": true + } + } + }, + "ethereumjs-util": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz", + "integrity": "sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ==", + "dev": true, + "requires": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "^0.1.3", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1" + } + } + } + }, "ethereumjs-common": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/ethereumjs-common/-/ethereumjs-common-1.5.1.tgz", @@ -2911,6 +3774,148 @@ "secp256k1": "^4.0.1" } }, + "ethereumjs-vm": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/ethereumjs-vm/-/ethereumjs-vm-2.6.0.tgz", + "integrity": "sha512-r/XIUik/ynGbxS3y+mvGnbOKnuLo40V5Mj1J25+HEO63aWYREIqvWeRO/hnROlMBE5WoniQmPmhiaN0ctiHaXw==", + "dev": true, + "requires": { + "async": "^2.1.2", + "async-eventemitter": "^0.2.2", + "ethereumjs-account": "^2.0.3", + "ethereumjs-block": "~2.2.0", + "ethereumjs-common": "^1.1.0", + "ethereumjs-util": "^6.0.0", + "fake-merkle-patricia-tree": "^1.0.1", + "functional-red-black-tree": "^1.0.1", + "merkle-patricia-tree": "^2.3.2", + "rustbn.js": "~0.2.0", + "safe-buffer": "^5.1.1" + }, + "dependencies": { + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + }, + "ethereumjs-block": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/ethereumjs-block/-/ethereumjs-block-2.2.2.tgz", + "integrity": "sha512-2p49ifhek3h2zeg/+da6XpdFR3GlqY3BIEiqxGF8j9aSRIgkb7M1Ky+yULBKJOu8PAZxfhsYA+HxUk2aCQp3vg==", + "dev": true, + "requires": { + "async": "^2.0.1", + "ethereumjs-common": "^1.5.0", + "ethereumjs-tx": "^2.1.1", + "ethereumjs-util": "^5.0.0", + "merkle-patricia-tree": "^2.1.2" + }, + "dependencies": { + "ethereumjs-util": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz", + "integrity": "sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ==", + "dev": true, + "requires": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "^0.1.3", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1" + } + } + } + }, + "ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", + "dev": true, + "requires": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" + } + } + } + }, + "ethereumjs-wallet": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/ethereumjs-wallet/-/ethereumjs-wallet-0.6.5.tgz", + "integrity": "sha512-MDwjwB9VQVnpp/Dc1XzA6J1a3wgHQ4hSvA1uWNatdpOrtCbPVuQSKSyRnjLvS0a+KKMw2pvQ9Ybqpb3+eW8oNA==", + "dev": true, + "requires": { + "aes-js": "^3.1.1", + "bs58check": "^2.1.2", + "ethereum-cryptography": "^0.1.3", + "ethereumjs-util": "^6.0.0", + "randombytes": "^2.0.6", + "safe-buffer": "^5.1.2", + "scryptsy": "^1.2.1", + "utf8": "^3.0.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "aes-js": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.1.2.tgz", + "integrity": "sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ==", + "dev": true + }, + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + }, + "ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", + "dev": true, + "requires": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" + } + }, + "scryptsy": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/scryptsy/-/scryptsy-1.2.1.tgz", + "integrity": "sha1-oyJfpLJST4AnAHYeKFW987LZIWM=", + "dev": true, + "requires": { + "pbkdf2": "^3.0.3" + } + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + } + } + }, "ethers": { "version": "4.0.47", "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.47.tgz", @@ -2934,6 +3939,21 @@ "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", "dev": true }, + "elliptic": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz", + "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==", + "dev": true, + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + } + }, "hash.js": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", @@ -2976,6 +3996,12 @@ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==" }, + "events": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz", + "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==", + "dev": true + }, "evp_bytestokey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", @@ -3166,6 +4192,15 @@ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" }, + "fake-merkle-patricia-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fake-merkle-patricia-tree/-/fake-merkle-patricia-tree-1.0.1.tgz", + "integrity": "sha1-S4w6z7Ugr635hgsfFM2M40As3dM=", + "dev": true, + "requires": { + "checkpoint-store": "^1.1.0" + } + }, "fast-deep-equal": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", @@ -3196,6 +4231,12 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "fast-safe-stringify": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", + "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==", + "dev": true + }, "fastq": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", @@ -3213,6 +4254,15 @@ "pend": "~1.2.0" } }, + "fetch-ponyfill": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/fetch-ponyfill/-/fetch-ponyfill-4.1.0.tgz", + "integrity": "sha1-rjzl9zLGReq4fkroeTQUcJsjmJM=", + "dev": true, + "requires": { + "node-fetch": "~1.7.1" + } + }, "file-type": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", @@ -3392,6 +4442,12 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, "ganache-cli": { "version": "6.9.1", "resolved": "https://registry.npmjs.org/ganache-cli/-/ganache-cli-6.9.1.tgz", @@ -4504,6 +5560,12 @@ "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", "dev": true }, + "immediate": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz", + "integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -4663,6 +5725,12 @@ "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==" }, + "is-fn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fn/-/is-fn-1.0.0.tgz", + "integrity": "sha1-lUPV3nvPWwiiLsiiC65uKG1RDYw=", + "dev": true + }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -4865,6 +5933,22 @@ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" }, + "json-rpc-engine": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-5.3.0.tgz", + "integrity": "sha512-+diJ9s8rxB+fbJhT7ZEf8r8spaLRignLd8jTgQ/h5JSGppAHGtNMZtCoabipCaleR1B3GTGxbXBOqhaJSGmPGQ==", + "dev": true, + "requires": { + "eth-rpc-errors": "^3.0.0", + "safe-event-emitter": "^1.0.1" + } + }, + "json-rpc-random-id": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-rpc-random-id/-/json-rpc-random-id-1.0.1.tgz", + "integrity": "sha1-uknZat7RRE27jaPSA3SKy7zeyMg=", + "dev": true + }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", @@ -4875,6 +5959,15 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dev": true, + "requires": { + "jsonify": "~0.0.0" + } + }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -4893,6 +5986,12 @@ "graceful-fs": "^4.1.6" } }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true + }, "jsonschema": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.2.6.tgz", @@ -4932,6 +6031,141 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" }, + "klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", + "requires": { + "graceful-fs": "^4.1.9" + } + }, + "level-codec": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/level-codec/-/level-codec-7.0.1.tgz", + "integrity": "sha512-Ua/R9B9r3RasXdRmOtd+t9TCOEIIlts+TN/7XTT2unhDaL6sJn83S3rUyljbr6lVtw49N3/yA0HHjpV6Kzb2aQ==", + "dev": true + }, + "level-errors": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/level-errors/-/level-errors-1.0.5.tgz", + "integrity": "sha512-/cLUpQduF6bNrWuAC4pwtUKA5t669pCsCi2XbmojG2tFeOr9j6ShtdDCtFFQO1DRt+EVZhx9gPzP9G2bUaG4ig==", + "dev": true, + "requires": { + "errno": "~0.1.1" + } + }, + "level-iterator-stream": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-1.3.1.tgz", + "integrity": "sha1-5Dt4sagUPm+pek9IXrjqUwNS8u0=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "level-errors": "^1.0.3", + "readable-stream": "^1.0.33", + "xtend": "^4.0.0" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + } + } + }, + "level-ws": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/level-ws/-/level-ws-0.0.0.tgz", + "integrity": "sha1-Ny5RIXeSSgBCSwtDrvK7QkltIos=", + "dev": true, + "requires": { + "readable-stream": "~1.0.15", + "xtend": "~2.1.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "object-keys": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", + "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=", + "dev": true + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "xtend": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", + "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=", + "dev": true, + "requires": { + "object-keys": "~0.4.0" + } + } + } + }, + "levelup": { + "version": "1.3.9", + "resolved": "https://registry.npmjs.org/levelup/-/levelup-1.3.9.tgz", + "integrity": "sha512-VVGHfKIlmw8w1XqpGOAGwq6sZm2WwWLmlDcULkKWQXEA5EopA8OBNJ2Ck2v6bdk8HeEZSbCSEgzXadyQFm76sQ==", + "dev": true, + "requires": { + "deferred-leveldown": "~1.2.1", + "level-codec": "~7.0.0", + "level-errors": "~1.0.3", + "level-iterator-stream": "~1.3.0", + "prr": "~1.0.1", + "semver": "~5.4.1", + "xtend": "~4.0.0" + }, + "dependencies": { + "semver": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", + "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==", + "dev": true + } + } + }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -4952,9 +6186,15 @@ } }, "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" + }, + "lodash.flatmap": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.flatmap/-/lodash.flatmap-4.5.0.tgz", + "integrity": "sha1-74y/QI9uSCaGYzRTBcaswLd4cC4=", + "dev": true }, "lodash.toarray": { "version": "4.4.0", @@ -4983,6 +6223,12 @@ "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" }, + "ltgt": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz", + "integrity": "sha1-81ypHEk/e3PaDgdJUwTxezH4fuU=", + "dev": true + }, "make-dir": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", @@ -5039,6 +6285,42 @@ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, + "memdown": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/memdown/-/memdown-1.4.1.tgz", + "integrity": "sha1-tOThkhdGZP+65BNhqlAPMRnv4hU=", + "dev": true, + "requires": { + "abstract-leveldown": "~2.7.1", + "functional-red-black-tree": "^1.0.1", + "immediate": "^3.2.3", + "inherits": "~2.0.1", + "ltgt": "~2.2.0", + "safe-buffer": "~5.1.1" + }, + "dependencies": { + "abstract-leveldown": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-2.7.2.tgz", + "integrity": "sha512-+OVvxH2rHVEhWLdbudP6p0+dNMXu8JA1CbhP19T8paTYAcX7oJ4OVjT+ZUVpv7mITxXHqDMej+GdqXBmXkw09w==", + "dev": true, + "requires": { + "xtend": "~4.0.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, + "memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=" + }, "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -5050,6 +6332,85 @@ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true }, + "merkle-patricia-tree": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/merkle-patricia-tree/-/merkle-patricia-tree-2.3.2.tgz", + "integrity": "sha512-81PW5m8oz/pz3GvsAwbauj7Y00rqm81Tzad77tHBwU7pIAtN+TJnMSOJhxBKflSVYhptMMb9RskhqHqrSm1V+g==", + "dev": true, + "requires": { + "async": "^1.4.2", + "ethereumjs-util": "^5.0.0", + "level-ws": "0.0.0", + "levelup": "^1.2.1", + "memdown": "^1.0.0", + "readable-stream": "^2.0.0", + "rlp": "^2.0.0", + "semaphore": ">=1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + }, + "ethereumjs-util": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz", + "integrity": "sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ==", + "dev": true, + "requires": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "^0.1.3", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + } + } + }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -5468,6 +6829,16 @@ } } }, + "node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "dev": true, + "requires": { + "encoding": "^0.1.11", + "is-stream": "^1.0.1" + } + }, "node-gyp-build": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.2.2.tgz", @@ -5890,6 +7261,12 @@ "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", "optional": true }, + "precond": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/precond/-/precond-0.2.3.tgz", + "integrity": "sha1-qpWRvKokkj8eD0hJ0kD0fvwQdaw=", + "dev": true + }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -5944,6 +7321,16 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, + "promise-to-callback": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/promise-to-callback/-/promise-to-callback-1.0.0.tgz", + "integrity": "sha1-XSp0kBC/tn2WNZj805YHRqaP7vc=", + "dev": true, + "requires": { + "is-fn": "^1.0.0", + "set-immediate-shim": "^1.0.1" + } + }, "proxy-addr": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", @@ -5953,6 +7340,12 @@ "ipaddr.js": "1.9.1" } }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + }, "psl": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", @@ -6522,6 +7915,11 @@ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" + }, "require-main-filename": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", @@ -6559,6 +7957,14 @@ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + }, "ripemd160": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", @@ -6589,11 +7995,26 @@ "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", "dev": true }, + "rustbn.js": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/rustbn.js/-/rustbn.js-0.2.0.tgz", + "integrity": "sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==", + "dev": true + }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, + "safe-event-emitter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safe-event-emitter/-/safe-event-emitter-1.0.1.tgz", + "integrity": "sha512-e1wFe99A91XYYxoQbcq2ZJUWurxEyP8vfz7A7vuUe1s95q8r5ebraVaA1BukYJcpM6V16ugWoD9vngi8Ccu5fg==", + "dev": true, + "requires": { + "events": "^3.0.0" + } + }, "safe-regex": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", @@ -6721,6 +8142,12 @@ "commander": "~2.8.1" } }, + "semaphore": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/semaphore/-/semaphore-1.1.0.tgz", + "integrity": "sha512-O4OZEaNtkMd/K0i6js9SL+gqy0ZCBMgUvlSqHKi4IBdjhe7wB8pwztUk1BbZ1fmrvpwFrPbHzqd2w5pTcJH6LA==", + "dev": true + }, "semver": { "version": "7.3.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", @@ -6797,6 +8224,12 @@ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, + "set-immediate-shim": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", + "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", + "dev": true + }, "set-value": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", @@ -7005,6 +8438,58 @@ } } }, + "solc": { + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.6.9.tgz", + "integrity": "sha512-DZ7lO6fpJQVMffN0vnVufyjQCkJMnqAOaqKWoqqK3ZjqA/Wl/emwFjUgMArUjtNSlQKcPUHN1GsvKZzaOOycXA==", + "requires": { + "command-exists": "^1.2.8", + "commander": "3.0.2", + "fs-extra": "^0.30.0", + "js-sha3": "0.8.0", + "memorystream": "^0.3.1", + "require-from-string": "^2.0.0", + "semver": "^5.5.0", + "tmp": "0.0.33" + }, + "dependencies": { + "commander": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", + "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==" + }, + "fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, + "js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" + }, + "jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, "solidity-coverage": { "version": "0.7.7", "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.7.7.tgz", @@ -8435,6 +9920,14 @@ "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "requires": { + "os-tmpdir": "~1.0.2" + } + }, "to-buffer": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", @@ -10394,6 +11887,12 @@ } } }, + "whatwg-fetch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", + "integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==", + "dev": true + }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", diff --git a/package.json b/package.json index ff6f3e9..5ab07b1 100644 --- a/package.json +++ b/package.json @@ -37,8 +37,9 @@ "dotenv-flow": "^3.1.0", "es6-promisify": "^6.1.1", "ethereumjs-util": "^7.0.2", - "lodash": "^4.17.15", + "lodash": "^4.17.20", "mocha": "^7.2.0", + "solc": "0.6.9", "truffle-hdwallet-provider": "^1.0.17", "ts-node": "^8.10.2", "typescript": "^3.9.5", diff --git a/test/DODOZoo.test.ts b/test/DODOZoo.test.ts index d275a5a..eca2bac 100644 --- a/test/DODOZoo.test.ts +++ b/test/DODOZoo.test.ts @@ -65,6 +65,13 @@ describe("DODO ZOO", () => { // console.log(await ctx.DODOZoo.methods.getDODOs().call()) }) + // it.only("remove dodo", async () => { + // console.log(await ctx.DODOZoo.methods.getDODOs().call()) + // await ctx.DODOZoo.methods.removeDODO(ctx.DODO.options.address).send(ctx.sendParam(ctx.Deployer)) + // console.log(await ctx.DODOZoo.methods.getDODO(ctx.BASE.options.address, ctx.QUOTE.options.address).call()) + // console.log(await ctx.DODOZoo.methods.getDODOs().call()) + // }) + it("dodo register control flow", async () => { await ctx.DODOZoo.methods.removeDODO(ctx.DODO.options.address).send(ctx.sendParam(ctx.Deployer)) assert.equal(await ctx.DODOZoo.methods.getDODO(ctx.BASE.options.address, ctx.QUOTE.options.address).call(), "0x0000000000000000000000000000000000000000") diff --git a/test/Trader.test.ts b/test/Trader.test.ts index 506aef4..8591724 100644 --- a/test/Trader.test.ts +++ b/test/Trader.test.ts @@ -52,11 +52,15 @@ describe("Trader", () => { describe("R goes above ONE", () => { it("buy when R equals ONE", async () => { +<<<<<<< Updated upstream await logGas( ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110"), "0x"), ctx.sendParam(trader), "buy base token when balanced" ); +======= + await logGas(ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110"), "0x"), ctx.sendParam(trader), "buy base token when balanced") +>>>>>>> Stashed changes // trader balances assert.equal( await ctx.BASE.methods.balanceOf(trader).call(), @@ -92,6 +96,7 @@ describe("Trader", () => { }); it("buy when R is ABOVE ONE", async () => { +<<<<<<< Updated upstream await ctx.DODO.methods .buyBaseToken(decimalStr("1"), decimalStr("110"), "0x") .send(ctx.sendParam(trader)); @@ -100,6 +105,10 @@ describe("Trader", () => { ctx.sendParam(trader), "buy when R is ABOVE ONE" ); +======= + await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110"), "0x").send(ctx.sendParam(trader)) + await logGas(ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("130"), "0x"), ctx.sendParam(trader), "buy when R is ABOVE ONE") +>>>>>>> Stashed changes // trader balances assert.equal( await ctx.BASE.methods.balanceOf(trader).call(), @@ -130,6 +139,7 @@ describe("Trader", () => { }); it("sell when R is ABOVE ONE", async () => { +<<<<<<< Updated upstream await ctx.DODO.methods .buyBaseToken(decimalStr("1"), decimalStr("110"), "0x") .send(ctx.sendParam(trader)); @@ -142,6 +152,10 @@ describe("Trader", () => { ctx.sendParam(trader), "sell when R is ABOVE ONE" ); +======= + await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110"), "0x").send(ctx.sendParam(trader)) + await logGas(ctx.DODO.methods.sellBaseToken(decimalStr("0.5"), decimalStr("40"), "0x"), ctx.sendParam(trader), "sell when R is ABOVE ONE") +>>>>>>> Stashed changes // trader balances assert.equal( await ctx.BASE.methods.balanceOf(trader).call(), @@ -172,6 +186,7 @@ describe("Trader", () => { }); it("sell when R is ABOVE ONE and RStatus back to ONE", async () => { +<<<<<<< Updated upstream await ctx.DODO.methods .buyBaseToken(decimalStr("1"), decimalStr("110"), "0x") .send(ctx.sendParam(trader)); @@ -184,6 +199,10 @@ describe("Trader", () => { ctx.sendParam(trader), "sell when R is ABOVE ONE and RStatus back to ONE" ); +======= + await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110"), "0x").send(ctx.sendParam(trader)) + await logGas(ctx.DODO.methods.sellBaseToken("1003002430889317763", decimalStr("90"), "0x"), ctx.sendParam(trader), "sell when R is ABOVE ONE and RStatus back to ONE") +>>>>>>> Stashed changes // R status assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0"); // trader balances @@ -225,6 +244,7 @@ describe("Trader", () => { }); it("sell when R is ABOVE ONE and RStatus becomes BELOW ONE", async () => { +<<<<<<< Updated upstream await ctx.DODO.methods .buyBaseToken(decimalStr("1"), decimalStr("110"), "0x") .send(ctx.sendParam(trader)); @@ -233,6 +253,10 @@ describe("Trader", () => { ctx.sendParam(trader), "sell when R is ABOVE ONE and RStatus becomes BELOW ONE [gas cost worst case]" ); +======= + await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110"), "0x").send(ctx.sendParam(trader)) + await logGas(ctx.DODO.methods.sellBaseToken(decimalStr("2"), decimalStr("90"), "0x"), ctx.sendParam(trader), "sell when R is ABOVE ONE and RStatus becomes BELOW ONE [gas cost worst case]") +>>>>>>> Stashed changes // R status assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "2"); // trader balances @@ -276,11 +300,15 @@ describe("Trader", () => { describe("R goes below ONE", () => { it("sell when R equals ONE", async () => { +<<<<<<< Updated upstream await logGas( ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90"), "0x"), ctx.sendParam(trader), "sell base token when balanced" ); +======= + await logGas(ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90"), "0x"), ctx.sendParam(trader), "sell base token when balanced") +>>>>>>> Stashed changes // trader balances assert.equal( await ctx.BASE.methods.balanceOf(trader).call(), @@ -316,6 +344,7 @@ describe("Trader", () => { }); it("sell when R is BELOW ONE", async () => { +<<<<<<< Updated upstream await ctx.DODO.methods .sellBaseToken(decimalStr("3"), decimalStr("90"), "0x") .send(ctx.sendParam(trader)); @@ -324,6 +353,10 @@ describe("Trader", () => { ctx.sendParam(trader), "sell when R is BELOW ONE" ); +======= + await ctx.DODO.methods.sellBaseToken(decimalStr("3"), decimalStr("90"), "0x").send(ctx.sendParam(trader)) + await logGas(ctx.DODO.methods.sellBaseToken(decimalStr("3"), decimalStr("90"), "0x"), ctx.sendParam(trader), "sell when R is BELOW ONE") +>>>>>>> Stashed changes // trader balances assert.equal( await ctx.BASE.methods.balanceOf(trader).call(), @@ -354,6 +387,7 @@ describe("Trader", () => { }); it("buy when R is BELOW ONE", async () => { +<<<<<<< Updated upstream await ctx.DODO.methods .sellBaseToken(decimalStr("1"), decimalStr("90"), "0x") .send(ctx.sendParam(trader)); @@ -366,6 +400,10 @@ describe("Trader", () => { ctx.sendParam(trader), "buy when R is BELOW ONE" ); +======= + await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90"), "0x").send(ctx.sendParam(trader)) + await logGas(ctx.DODO.methods.buyBaseToken(decimalStr("0.5"), decimalStr("60"), "0x"), ctx.sendParam(trader), "buy when R is BELOW ONE") +>>>>>>> Stashed changes // trader balances assert.equal( await ctx.BASE.methods.balanceOf(trader).call(), @@ -396,6 +434,7 @@ describe("Trader", () => { }); it("buy when R is BELOW ONE and RStatus back to ONE", async () => { +<<<<<<< Updated upstream await ctx.DODO.methods .sellBaseToken(decimalStr("1"), decimalStr("90"), "0x") .send(ctx.sendParam(trader)); @@ -408,6 +447,10 @@ describe("Trader", () => { ctx.sendParam(trader), "buy when R is BELOW ONE and RStatus back to ONE" ); +======= + await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90"), "0x").send(ctx.sendParam(trader)) + await logGas(ctx.DODO.methods.buyBaseToken("997008973080757728", decimalStr("110"), "0x"), ctx.sendParam(trader), "buy when R is BELOW ONE and RStatus back to ONE") +>>>>>>> Stashed changes // R status assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0"); // trader balances @@ -449,6 +492,7 @@ describe("Trader", () => { }); it("buy when R is BELOW ONE and RStatus becomes ABOVE ONE", async () => { +<<<<<<< Updated upstream await ctx.DODO.methods .sellBaseToken(decimalStr("1"), decimalStr("90"), "0x") .send(ctx.sendParam(trader)); @@ -457,6 +501,10 @@ describe("Trader", () => { ctx.sendParam(trader), "buy when R is BELOW ONE and RStatus becomes ABOVE ONE [gas cost worst case]" ); +======= + await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90"), "0x").send(ctx.sendParam(trader)) + await logGas(ctx.DODO.methods.buyBaseToken(decimalStr("2"), decimalStr("220"), "0x"), ctx.sendParam(trader), "buy when R is BELOW ONE and RStatus becomes ABOVE ONE [gas cost worst case]") +>>>>>>> Stashed changes // R status assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "1"); // trader balances diff --git a/test/UniswapArbitrageur.test.ts b/test/UniswapArbitrageur.test.ts index 1df1df3..eae0670 100644 --- a/test/UniswapArbitrageur.test.ts +++ b/test/UniswapArbitrageur.test.ts @@ -97,6 +97,7 @@ describe("Uniswap Arbitrageur", () => { await ctx.setOraclePrice(decimalStr("100")); // dodo price 100 uniswap price 200 // buy at dodo +<<<<<<< Updated upstream await logGas( UniswapArbitrageur.methods.executeBuyArbitrage(decimalStr("1")), ctx.sendParam(keeper), @@ -107,11 +108,17 @@ describe("Uniswap Arbitrageur", () => { "79836384956601695518" ); }); +======= + logGas(await UniswapArbitrageur.methods.executeBuyArbitrage(decimalStr("1")), ctx.sendParam(keeper), "arbitrage buy at dodo not reverse") + assert.equal(await ctx.QUOTE.methods.balanceOf(keeper).call(), "79836384956601695518") + }) +>>>>>>> Stashed changes it("sell at dodo", async () => { await ctx.setOraclePrice(decimalStr("300")); // dodo price 300 uniswap price 200 // sell at dodo +<<<<<<< Updated upstream await logGas( UniswapArbitrageur.methods.executeSellArbitrage(decimalStr("1")), ctx.sendParam(keeper), @@ -123,12 +130,19 @@ describe("Uniswap Arbitrageur", () => { ); }); }); +======= + logGas(await UniswapArbitrageur.methods.executeSellArbitrage(decimalStr("1")), ctx.sendParam(keeper), "arbitrage sell at dodo not reverse") + assert.equal(await ctx.BASE.methods.balanceOf(keeper).call(), "252761069524143743") + }) + }) +>>>>>>> Stashed changes describe("arbitrage with reverse pair", () => { it("buy at dodo", async () => { await ctx.setOraclePrice(decimalStr("100")); // dodo price 100 uniswap price 200 // buy at dodo +<<<<<<< Updated upstream await logGas( UniswapArbitrageurReverse.methods.executeBuyArbitrage(decimalStr("1")), ctx.sendParam(keeper), @@ -139,11 +153,17 @@ describe("Uniswap Arbitrageur", () => { "79836384956601695518" ); }); +======= + logGas(await UniswapArbitrageurReverse.methods.executeBuyArbitrage(decimalStr("1")), ctx.sendParam(keeper), "arbitrage buy at dodo reverse") + assert.equal(await ctx.QUOTE.methods.balanceOf(keeper).call(), "79836384956601695518") + }) +>>>>>>> Stashed changes it("sell at dodo", async () => { await ctx.setOraclePrice(decimalStr("300")); // dodo price 300 uniswap price 200 // sell at dodo +<<<<<<< Updated upstream await logGas( UniswapArbitrageurReverse.methods.executeSellArbitrage(decimalStr("1")), ctx.sendParam(keeper), @@ -155,6 +175,12 @@ describe("Uniswap Arbitrageur", () => { ); }); }); +======= + logGas(await UniswapArbitrageurReverse.methods.executeSellArbitrage(decimalStr("1")), ctx.sendParam(keeper), "arbitrage sell at dodo reverse") + assert.equal(await ctx.BASE.methods.balanceOf(keeper).call(), "252761069524143743") + }) + }) +>>>>>>> Stashed changes describe("revert cases", () => { it("price not match", async () => { diff --git a/test/utils/Contracts.ts b/test/utils/Contracts.ts index b07b068..245f6e3 100644 --- a/test/utils/Contracts.ts +++ b/test/utils/Contracts.ts @@ -13,6 +13,7 @@ if (process.env["COVERAGE"]) { const CloneFactory = require(`${jsonPath}CloneFactory.json`) const DODO = require(`${jsonPath}DODO.json`) const DODOZoo = require(`${jsonPath}DODOZoo.json`) +// const DODOWild = require(`${jsonPath}DODOWild.json`) const DODOEthProxy = require(`${jsonPath}DODOEthProxy.json`) const WETH = require(`${jsonPath}WETH9.json`) const TestERC20 = require(`${jsonPath}TestERC20.json`) @@ -20,6 +21,8 @@ const NaiveOracle = require(`${jsonPath}NaiveOracle.json`) const DODOLpToken = require(`${jsonPath}DODOLpToken.json`) const Uniswap = require(`${jsonPath}UniswapV2Pair.json`) const UniswapArbitrageur = require(`${jsonPath}UniswapArbitrageur.json`) +const DODOToken = require(`${jsonPath}DODOToken.json`) +const LockedTokenVault = require(`${jsonPath}LockedTokenVault.json`) import { getDefaultWeb3 } from './EVM'; import { Contract } from 'web3-eth-contract'; @@ -30,10 +33,13 @@ export const TEST_ERC20_CONTRACT_NAME = "TestERC20" export const NAIVE_ORACLE_CONTRACT_NAME = "NaiveOracle" export const DODO_LP_TOKEN_CONTRACT_NAME = "DODOLpToken" export const DODO_ZOO_CONTRACT_NAME = "DOOZoo" +export const DODO_WILD_CONTRACT_NAME = "DOOWild" export const DODO_ETH_PROXY_CONTRACT_NAME = "DODOEthProxy" export const WETH_CONTRACT_NAME = "WETH" export const UNISWAP_CONTRACT_NAME = "Uniswap" export const UNISWAP_ARBITRAGEUR_CONTRACT_NAME = "UniswapArbitrageur" +export const DODO_TOKEN_CONTRACT_NAME = "DODOToken" +export const LOCKED_TOKEN_VAULT_CONTRACT_NAME = "LockedTokenVault" var contractMap: { [name: string]: any } = {} contractMap[CLONE_FACTORY_CONTRACT_NAME] = CloneFactory @@ -46,6 +52,8 @@ contractMap[DODO_ETH_PROXY_CONTRACT_NAME] = DODOEthProxy contractMap[WETH_CONTRACT_NAME] = WETH contractMap[UNISWAP_CONTRACT_NAME] = Uniswap contractMap[UNISWAP_ARBITRAGEUR_CONTRACT_NAME] = UniswapArbitrageur +contractMap[DODO_TOKEN_CONTRACT_NAME] = DODOToken +contractMap[LOCKED_TOKEN_VAULT_CONTRACT_NAME] = LockedTokenVault interface ContractJson { abi: any; diff --git a/test/utils/SlippageFormula.ts b/test/utils/SlippageFormula.ts index 9f90189..0d9d714 100644 --- a/test/utils/SlippageFormula.ts +++ b/test/utils/SlippageFormula.ts @@ -3,9 +3,25 @@ function calculateSlippage(buyPercentage: number) { console.log(buyPercentage, ":", ((1 / (1 - buyPercentage)) * k - k) * 100, "%") } +function calculateLoss(priceGap: number) { + const feeRate = 0.0025 + const k = 0.1 + let amountPartial = Math.sqrt(priceGap / k + 1) - 1 + let loss = amountPartial * (priceGap - feeRate * 2) + console.log(priceGap, ":", loss * 100, "%") +} + // calculateSlippage(0.01) // calculateSlippage(0.05) // calculateSlippage(0.1) // calculateSlippage(0.2) // calculateSlippage(0.5) // calculateSlippage(0.7) + +// calculateLoss(0.006) +// calculateLoss(0.007) +// calculateLoss(0.008) +// calculateLoss(0.009) +// calculateLoss(0.01) +// calculateLoss(0.02) +// calculateLoss(0.03) \ No newline at end of file From c6c999c32fb35b0afdc6088e38992bf6365deb84 Mon Sep 17 00:00:00 2001 From: mingda Date: Thu, 17 Sep 2020 15:16:46 +0800 Subject: [PATCH 080/118] add cliff rate --- contracts/token/LockedTokenVault.sol | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/contracts/token/LockedTokenVault.sol b/contracts/token/LockedTokenVault.sol index c25c868..bb526fa 100644 --- a/contracts/token/LockedTokenVault.sol +++ b/contracts/token/LockedTokenVault.sol @@ -36,6 +36,7 @@ contract LockedTokenVault is Ownable { uint256 public _START_RELEASE_TIME_; uint256 public _RELEASE_DURATION_; + uint256 public _CLIFF_RATE_; // ============ Modifiers ============ @@ -64,11 +65,13 @@ contract LockedTokenVault is Ownable { constructor( address _token, uint256 _startReleaseTime, - uint256 _releaseDuration + uint256 _releaseDuration, + uint256 _cliffRate ) public { _TOKEN_ = _token; _START_RELEASE_TIME_ = _startReleaseTime; _RELEASE_DURATION_ = _releaseDuration; + _CLIFF_RATE_ = _cliffRate; } function deposit(uint256 amount) external onlyOwner beforeStartRelease { @@ -175,7 +178,10 @@ contract LockedTokenVault is Ownable { uint256 timePast = block.timestamp.sub(_START_RELEASE_TIME_); if (timePast < _RELEASE_DURATION_) { uint256 remainingTime = _RELEASE_DURATION_.sub(timePast); - newRemaining = originBalances[holder].mul(remainingTime).div(_RELEASE_DURATION_); + newRemaining = originBalances[holder] + .sub(DecimalMath.mul(originBalances[holder], _CLIFF_RATE_)) + .mul(remainingTime) + .div(_RELEASE_DURATION_); } return remainingBalances[msg.sender].sub(newRemaining); } From 43fc3332751823dd4bda1086cd83e63d38ff44b5 Mon Sep 17 00:00:00 2001 From: mingda Date: Thu, 17 Sep 2020 23:50:56 +0800 Subject: [PATCH 081/118] integrate withdraw base and quote to final settlement claim --- contracts/impl/LiquidityProvider.sol | 29 +++++++++++++++++++---- contracts/impl/Settlement.sol | 26 +++++++++++++++------ test/Admin.test.ts | 35 ++++++++++------------------ 3 files changed, 56 insertions(+), 34 deletions(-) diff --git a/contracts/impl/LiquidityProvider.sol b/contracts/impl/LiquidityProvider.sol index 338f22e..237209d 100644 --- a/contracts/impl/LiquidityProvider.sol +++ b/contracts/impl/LiquidityProvider.sol @@ -17,6 +17,7 @@ import {Storage} from "./Storage.sol"; import {Settlement} from "./Settlement.sol"; import {Pricing} from "./Pricing.sol"; + /** * @title LiquidityProvider * @author DODO Breeder @@ -58,6 +59,11 @@ contract LiquidityProvider is Storage, Pricing, Settlement { _; } + modifier dodoNotClosed() { + require(!_CLOSED_, "DODO_CLOSED"); + _; + } + // ============ Routine Functions ============ function withdrawBase(uint256 amount) external returns (uint256) { @@ -138,7 +144,12 @@ contract LiquidityProvider is Storage, Pricing, Settlement { // ============ Withdraw Functions ============ - function withdrawQuoteTo(address to, uint256 amount) public preventReentrant returns (uint256) { + function withdrawQuoteTo(address to, uint256 amount) + public + preventReentrant + dodoNotClosed + returns (uint256) + { // calculate capital (, uint256 quoteTarget) = getExpectedTarget(); uint256 totalQuoteCapital = getTotalQuoteCapital(); @@ -166,7 +177,12 @@ contract LiquidityProvider is Storage, Pricing, Settlement { return amount.sub(penalty); } - function withdrawBaseTo(address to, uint256 amount) public preventReentrant returns (uint256) { + function withdrawBaseTo(address to, uint256 amount) + public + preventReentrant + dodoNotClosed + returns (uint256) + { // calculate capital (uint256 baseTarget, ) = getExpectedTarget(); uint256 totalBaseCapital = getTotalBaseCapital(); @@ -196,7 +212,12 @@ contract LiquidityProvider is Storage, Pricing, Settlement { // ============ Withdraw all Functions ============ - function withdrawAllQuoteTo(address to) public preventReentrant returns (uint256) { + function withdrawAllQuoteTo(address to) + public + preventReentrant + dodoNotClosed + returns (uint256) + { uint256 withdrawAmount = getLpQuoteBalance(msg.sender); uint256 capital = getQuoteCapitalBalanceOf(msg.sender); @@ -216,7 +237,7 @@ contract LiquidityProvider is Storage, Pricing, Settlement { return withdrawAmount.sub(penalty); } - function withdrawAllBaseTo(address to) public preventReentrant returns (uint256) { + function withdrawAllBaseTo(address to) public preventReentrant dodoNotClosed returns (uint256) { uint256 withdrawAmount = getLpBaseBalance(msg.sender); uint256 capital = getBaseCapitalBalanceOf(msg.sender); diff --git a/contracts/impl/Settlement.sol b/contracts/impl/Settlement.sol index d301a5b..d8db11b 100644 --- a/contracts/impl/Settlement.sol +++ b/contracts/impl/Settlement.sol @@ -12,6 +12,7 @@ import {SafeMath} from "../lib/SafeMath.sol"; import {SafeERC20} from "../lib/SafeERC20.sol"; import {DecimalMath} from "../lib/DecimalMath.sol"; import {Types} from "../lib/Types.sol"; +import {IDODOLpToken} from "../intf/IDODOLpToken.sol"; import {IERC20} from "../intf/IERC20.sol"; import {Storage} from "./Storage.sol"; @@ -114,16 +115,27 @@ contract Settlement is Storage { require(_CLOSED_, "DODO_NOT_CLOSED"); require(!_CLAIMED_[msg.sender], "ALREADY_CLAIMED"); _CLAIMED_[msg.sender] = true; - uint256 quoteAmount = DecimalMath.mul( - getBaseCapitalBalanceOf(msg.sender), - _BASE_CAPITAL_RECEIVE_QUOTE_ - ); - uint256 baseAmount = DecimalMath.mul( - getQuoteCapitalBalanceOf(msg.sender), - _QUOTE_CAPITAL_RECEIVE_BASE_ + + uint256 quoteCapital = getQuoteCapitalBalanceOf(msg.sender); + uint256 baseCapital = getBaseCapitalBalanceOf(msg.sender); + + uint256 quoteAmount = _TARGET_QUOTE_TOKEN_AMOUNT_.mul(quoteCapital).div( + getTotalQuoteCapital() ); + uint256 baseAmount = _TARGET_BASE_TOKEN_AMOUNT_.mul(baseCapital).div(getTotalBaseCapital()); + + _TARGET_QUOTE_TOKEN_AMOUNT_ = _TARGET_QUOTE_TOKEN_AMOUNT_.sub(quoteAmount); + _TARGET_BASE_TOKEN_AMOUNT_ = _TARGET_BASE_TOKEN_AMOUNT_.sub(baseAmount); + + quoteAmount = quoteAmount.add(DecimalMath.mul(baseCapital, _BASE_CAPITAL_RECEIVE_QUOTE_)); + baseAmount = baseAmount.add(DecimalMath.mul(quoteCapital, _QUOTE_CAPITAL_RECEIVE_BASE_)); + _baseTokenTransferOut(msg.sender, baseAmount); _quoteTokenTransferOut(msg.sender, quoteAmount); + + IDODOLpToken(_BASE_CAPITAL_TOKEN_).burn(msg.sender, baseCapital); + IDODOLpToken(_QUOTE_CAPITAL_TOKEN_).burn(msg.sender, quoteCapital); + emit ClaimAssets(msg.sender, baseAmount, quoteAmount); return; } diff --git a/test/Admin.test.ts b/test/Admin.test.ts index 49fda32..4eeb928 100644 --- a/test/Admin.test.ts +++ b/test/Admin.test.ts @@ -327,8 +327,6 @@ describe("Admin", () => { .send(ctx.sendParam(ctx.Deployer)); await ctx.DODO.methods.claimAssets().send(ctx.sendParam(lp1)); - await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp1)); - await ctx.DODO.methods.withdrawAllQuote().send(ctx.sendParam(lp1)); assert.equal( await ctx.BASE.methods.balanceOf(lp1).call(), @@ -357,16 +355,7 @@ describe("Admin", () => { assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0"); await ctx.DODO.methods.claimAssets().send(ctx.sendParam(lp1)); - assert.equal( - await ctx.BASE.methods.balanceOf(lp1).call(), - decimalStr("90") - ); - assert.equal( - await ctx.QUOTE.methods.balanceOf(lp1).call(), - "9551951805416248746110" - ); - await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp1)); - await ctx.DODO.methods.withdrawAllQuote().send(ctx.sendParam(lp1)); + assert.equal( await ctx.BASE.methods.balanceOf(lp1).call(), decimalStr("94.995") @@ -394,16 +383,7 @@ describe("Admin", () => { assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0"); await ctx.DODO.methods.claimAssets().send(ctx.sendParam(lp1)); - assert.equal( - await ctx.BASE.methods.balanceOf(lp1).call(), - decimalStr("95") - ); - assert.equal( - await ctx.QUOTE.methods.balanceOf(lp1).call(), - decimalStr("9000") - ); - await ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp1)); - await ctx.DODO.methods.withdrawAllQuote().send(ctx.sendParam(lp1)); + assert.equal( await ctx.BASE.methods.balanceOf(lp1).call(), decimalStr("105") @@ -434,9 +414,18 @@ describe("Admin", () => { .send(ctx.sendParam(ctx.Deployer)); await assert.rejects( ctx.DODO.methods.finalSettlement().send(ctx.sendParam(ctx.Deployer)), - / DODO_CLOSED/ + /DODO_CLOSED/ ); + await assert.rejects( + ctx.DODO.methods.withdrawAllBase().send(ctx.sendParam(lp1)), + /DODO_CLOSED/ + ) + await assert.rejects( + ctx.DODO.methods.withdrawAllQuote().send(ctx.sendParam(lp1)), + /DODO_CLOSED/ + ) + await ctx.DODO.methods.claimAssets().send(ctx.sendParam(lp2)); await assert.rejects( ctx.DODO.methods.claimAssets().send(ctx.sendParam(lp2)), From 8b7bdb801c4765ae60c3779649b5f7e8a11015dd Mon Sep 17 00:00:00 2001 From: mingda Date: Mon, 21 Sep 2020 23:37:58 +0800 Subject: [PATCH 082/118] claim assets when single side deposit --- contracts/impl/Settlement.sol | 12 ++++++++---- test/Admin.test.ts | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/contracts/impl/Settlement.sol b/contracts/impl/Settlement.sol index d8db11b..ac6e2bd 100644 --- a/contracts/impl/Settlement.sol +++ b/contracts/impl/Settlement.sol @@ -119,10 +119,14 @@ contract Settlement is Storage { uint256 quoteCapital = getQuoteCapitalBalanceOf(msg.sender); uint256 baseCapital = getBaseCapitalBalanceOf(msg.sender); - uint256 quoteAmount = _TARGET_QUOTE_TOKEN_AMOUNT_.mul(quoteCapital).div( - getTotalQuoteCapital() - ); - uint256 baseAmount = _TARGET_BASE_TOKEN_AMOUNT_.mul(baseCapital).div(getTotalBaseCapital()); + uint256 quoteAmount = 0; + if (quoteCapital > 0) { + quoteAmount = _TARGET_QUOTE_TOKEN_AMOUNT_.mul(quoteCapital).div(getTotalQuoteCapital()); + } + uint256 baseAmount = 0; + if (baseCapital > 0) { + baseAmount = _TARGET_BASE_TOKEN_AMOUNT_.mul(baseCapital).div(getTotalBaseCapital()); + } _TARGET_QUOTE_TOKEN_AMOUNT_ = _TARGET_QUOTE_TOKEN_AMOUNT_.sub(quoteAmount); _TARGET_BASE_TOKEN_AMOUNT_ = _TARGET_BASE_TOKEN_AMOUNT_.sub(baseAmount); diff --git a/test/Admin.test.ts b/test/Admin.test.ts index 4eeb928..491f335 100644 --- a/test/Admin.test.ts +++ b/test/Admin.test.ts @@ -394,6 +394,40 @@ describe("Admin", () => { ); }); + it("final settlement when only deposit base", async () => { + await ctx.DODO.methods + .depositBase(decimalStr("10")) + .send(ctx.sendParam(lp1)); + + await ctx.DODO.methods + .finalSettlement() + .send(ctx.sendParam(ctx.Deployer)); + + await ctx.DODO.methods.claimAssets().send(ctx.sendParam(lp1)); + + assert.equal( + await ctx.BASE.methods.balanceOf(lp1).call(), + decimalStr("100") + ); + }); + + it("final settlement when only deposit quote", async () => { + await ctx.DODO.methods + .depositQuote(decimalStr("1000")) + .send(ctx.sendParam(lp1)); + + await ctx.DODO.methods + .finalSettlement() + .send(ctx.sendParam(ctx.Deployer)); + + await ctx.DODO.methods.claimAssets().send(ctx.sendParam(lp1)); + + assert.equal( + await ctx.QUOTE.methods.balanceOf(lp1).call(), + decimalStr("10000") + ); + }); + it("final settlement revert cases", async () => { await assert.rejects( ctx.DODO.methods.claimAssets().send(ctx.sendParam(lp1)), From 3ba3d05bb49f63377bfefc43c6e52018c23b97f2 Mon Sep 17 00:00:00 2001 From: mingda Date: Tue, 22 Sep 2020 00:47:50 +0800 Subject: [PATCH 083/118] DODO mine test finished --- contracts/token/DODOMine.sol | 12 ++- test/Mining.test.ts | 164 +++++++++++++++++++++++++++++++++++ 2 files changed, 173 insertions(+), 3 deletions(-) create mode 100644 test/Mining.test.ts diff --git a/contracts/token/DODOMine.sol b/contracts/token/DODOMine.sol index 9cb11a5..c22391d 100644 --- a/contracts/token/DODOMine.sol +++ b/contracts/token/DODOMine.sol @@ -99,8 +99,8 @@ contract DODOMine is Ownable { // ============ Ownable ============ function addLpToken( - uint256 _allocPoint, address _lpToken, + uint256 _allocPoint, bool _withUpdate ) public lpTokenNotExist(_lpToken) onlyOwner { if (_withUpdate) { @@ -160,7 +160,7 @@ contract DODOMine is Ownable { uint256 length = poolInfos.length; uint256 totalReward = 0; for (uint256 pid = 0; pid < length; ++pid) { - if (userInfo[pid][msg.sender].amount == 0 || poolInfos[pid].allocPoint == 0) { + if (userInfo[pid][_user].amount == 0 || poolInfos[pid].allocPoint == 0) { continue; // save gas } PoolInfo storage pool = poolInfos[pid]; @@ -187,6 +187,12 @@ contract DODOMine is Ownable { return realizedReward[_user]; } + function getDlpMiningSpeed(address _lpToken) external view returns (uint256) { + uint256 pid = getPid(_lpToken); + PoolInfo storage pool = poolInfos[pid]; + return dodoPerBlock.mul(pool.allocPoint).div(totalAllocPoint); + } + // ============ Update Pools ============ // Update reward vairables for all pools. Be careful of gas spending! @@ -242,7 +248,7 @@ contract DODOMine is Ownable { uint256 pid = getPid(_lpToken); PoolInfo storage pool = poolInfos[pid]; UserInfo storage user = userInfo[pid][msg.sender]; - require(user.amount >= _amount, "withdraw: not good"); + require(user.amount >= _amount, "withdraw too much"); updatePool(pid); uint256 pending = DecimalMath.mul(user.amount, pool.accDODOPerShare).sub(user.rewardDebt); safeDODOTransfer(msg.sender, pending); diff --git a/test/Mining.test.ts b/test/Mining.test.ts new file mode 100644 index 0000000..917e7c0 --- /dev/null +++ b/test/Mining.test.ts @@ -0,0 +1,164 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +import { DODOContext, getDODOContext } from './utils/Context'; +import { decimalStr, MAX_UINT256 } from './utils/Converter'; +// import * as assert from "assert" +import { newContract, DODO_TOKEN_CONTRACT_NAME, DODO_MINE_NAME, TEST_ERC20_CONTRACT_NAME, getContractWithAddress } from './utils/Contracts'; +import { Contract } from 'web3-eth-contract'; +import { assert } from 'chai'; +import { logGas } from './utils/Log'; + +let BaseDLP: Contract +let QuoteDLP: Contract +let DODOToken: Contract +let DODOMine: Contract +let lp1: string; +let lp2: string; + +async function init(ctx: DODOContext): Promise { + + lp1 = ctx.spareAccounts[0]; + lp2 = ctx.spareAccounts[1]; + await ctx.mintTestToken(lp1, decimalStr("100"), decimalStr("10000")); + await ctx.mintTestToken(lp2, decimalStr("100"), decimalStr("10000")); + + await ctx.approveDODO(lp1); + await ctx.approveDODO(lp2); + + await ctx.DODO.methods.depositBase(decimalStr("100")).send(ctx.sendParam(lp1)) + await ctx.DODO.methods.depositQuote(decimalStr("10000")).send(ctx.sendParam(lp1)) + + await ctx.DODO.methods.depositBase(decimalStr("100")).send(ctx.sendParam(lp2)) + await ctx.DODO.methods.depositQuote(decimalStr("10000")).send(ctx.sendParam(lp2)) + + DODOToken = await newContract(DODO_TOKEN_CONTRACT_NAME) + DODOMine = await newContract(DODO_MINE_NAME, [DODOToken.options.address, (await ctx.Web3.eth.getBlockNumber()).toString()]) + + BaseDLP = await getContractWithAddress(TEST_ERC20_CONTRACT_NAME, await ctx.DODO.methods._BASE_CAPITAL_TOKEN_().call()) + QuoteDLP = await getContractWithAddress(TEST_ERC20_CONTRACT_NAME, await ctx.DODO.methods._QUOTE_CAPITAL_TOKEN_().call()) + + await BaseDLP.methods.approve(DODOMine.options.address, MAX_UINT256).send(ctx.sendParam(lp1)) + await QuoteDLP.methods.approve(DODOMine.options.address, MAX_UINT256).send(ctx.sendParam(lp1)) + + await BaseDLP.methods.approve(DODOMine.options.address, MAX_UINT256).send(ctx.sendParam(lp2)) + await QuoteDLP.methods.approve(DODOMine.options.address, MAX_UINT256).send(ctx.sendParam(lp2)) + + await DODOMine.methods.setReward(decimalStr("100")).send(ctx.sendParam(ctx.Deployer)) + await DODOMine.methods.addLpToken(BaseDLP.options.address, "1", true).send(ctx.sendParam(ctx.Deployer)) + await DODOMine.methods.addLpToken(QuoteDLP.options.address, "2", true).send(ctx.sendParam(ctx.Deployer)) + await DODOToken.methods.transfer(DODOMine.options.address, decimalStr("100000000")).send(ctx.sendParam(ctx.Deployer)) +} + +describe("Lock DODO Token", () => { + + let snapshotId: string + let ctx: DODOContext + + before(async () => { + ctx = await getDODOContext() + await init(ctx); + }) + + beforeEach(async () => { + snapshotId = await ctx.EVM.snapshot(); + }); + + afterEach(async () => { + await ctx.EVM.reset(snapshotId) + }); + + describe("Lp Deposit", () => { + it.only("single lp deposit", async () => { + await logGas(DODOMine.methods.deposit(BaseDLP.options.address, decimalStr("100")), ctx.sendParam(lp1), "deposit") + await ctx.EVM.fastMove(100) + assert.equal(await DODOMine.methods.getPendingReward(BaseDLP.options.address, lp1).call(), "3333333333333333333300") + assert.equal(await DODOMine.methods.getDlpMiningSpeed(BaseDLP.options.address).call(), "33333333333333333333") + }) + + it("multi lp deposit", async () => { + await DODOMine.methods.deposit(BaseDLP.options.address, decimalStr("100")).send(ctx.sendParam(lp1)) + await ctx.EVM.fastMove(100) + await DODOMine.methods.deposit(BaseDLP.options.address, decimalStr("100")).send(ctx.sendParam(lp2)) + await ctx.EVM.fastMove(100) + assert.equal(await DODOMine.methods.getPendingReward(BaseDLP.options.address, lp1).call(), "5033333333333333333200") + assert.equal(await DODOMine.methods.getPendingReward(BaseDLP.options.address, lp2).call(), "1666666666666666666600") + + await DODOMine.methods.deposit(QuoteDLP.options.address, decimalStr("100")).send(ctx.sendParam(lp1)) + await ctx.EVM.fastMove(100) + await DODOMine.methods.deposit(QuoteDLP.options.address, decimalStr("100")).send(ctx.sendParam(lp2)) + await ctx.EVM.fastMove(100) + assert.equal(await DODOMine.methods.getPendingReward(QuoteDLP.options.address, lp1).call(), "10066666666666666666600") + assert.equal(await DODOMine.methods.getPendingReward(QuoteDLP.options.address, lp2).call(), "3333333333333333333300") + + assert.equal(await DODOMine.methods.getAllPendingReward(lp1).call(), "18466666666666666666500") + assert.equal(await DODOMine.methods.getAllPendingReward(lp2).call(), "8366666666666666666600") + }) + + it("lp multi deposit and withdraw", async () => { + await DODOMine.methods.deposit(BaseDLP.options.address, decimalStr("100")).send(ctx.sendParam(lp2)) + await DODOMine.methods.deposit(BaseDLP.options.address, decimalStr("100")).send(ctx.sendParam(lp1)) + await ctx.EVM.fastMove(100) + await logGas(DODOMine.methods.withdraw(BaseDLP.options.address, decimalStr("50")), ctx.sendParam(lp1), "withdraw") + assert.equal(await DODOMine.methods.getAllPendingReward(lp1).call(), "0") + assert.equal(await DODOToken.methods.balanceOf(lp1).call(), "1683333333333333333300") + assert.equal(await DODOMine.methods.getRealizedReward(lp1).call(), "1683333333333333333300") + await ctx.EVM.fastMove(100) + await DODOMine.methods.deposit(BaseDLP.options.address, decimalStr("50")).send(ctx.sendParam(lp1)) + assert.equal(await DODOMine.methods.getAllPendingReward(lp1).call(), "0") + assert.equal(await DODOToken.methods.balanceOf(lp1).call(), "2805555555555555555500") + assert.equal(await DODOMine.methods.getRealizedReward(lp1).call(), "2805555555555555555500") + }) + + it("lp claim", async () => { + await DODOMine.methods.deposit(BaseDLP.options.address, decimalStr("100")).send(ctx.sendParam(lp1)) + await DODOMine.methods.deposit(BaseDLP.options.address, decimalStr("100")).send(ctx.sendParam(lp2)) + + await DODOMine.methods.deposit(QuoteDLP.options.address, decimalStr("100")).send(ctx.sendParam(lp1)) + await DODOMine.methods.deposit(QuoteDLP.options.address, decimalStr("100")).send(ctx.sendParam(lp2)) + + await ctx.EVM.fastMove(100) + + await logGas(DODOMine.methods.claim(BaseDLP.options.address), ctx.sendParam(lp1), "claim") + assert.equal(await DODOMine.methods.getPendingReward(BaseDLP.options.address, lp1).call(), "0") + assert.equal(await DODOMine.methods.getAllPendingReward(lp1).call(), "3433333333333333333200") + assert.equal(await DODOMine.methods.getRealizedReward(lp1).call(), "1749999999999999999900") + assert.equal(await DODOToken.methods.balanceOf(lp1).call(), "1749999999999999999900") + + await logGas(DODOMine.methods.claimAll(), ctx.sendParam(lp2), "claim 2 pool") + assert.equal(await DODOMine.methods.getPendingReward(BaseDLP.options.address, lp2).call(), "0") + assert.equal(await DODOMine.methods.getAllPendingReward(lp2).call(), "0") + assert.equal(await DODOMine.methods.getRealizedReward(lp2).call(), "5133333333333333333200") + assert.equal(await DODOToken.methods.balanceOf(lp2).call(), "5133333333333333333200") + }) + + it("lp emergency withdraw", async () => { + await DODOMine.methods.deposit(QuoteDLP.options.address, decimalStr("100")).send(ctx.sendParam(lp1)) + + await ctx.EVM.fastMove(100) + + await DODOMine.methods.emergencyWithdraw(QuoteDLP.options.address).send(ctx.sendParam(lp1)) + + assert.equal(await QuoteDLP.methods.balanceOf(lp1).call(), decimalStr("10000")) + assert.equal(await DODOMine.methods.getPendingReward(QuoteDLP.options.address, lp1).call(), "0") + assert.equal(await DODOMine.methods.getAllPendingReward(lp1).call(), "0") + assert.equal(await DODOMine.methods.getRealizedReward(lp1).call(), "0") + assert.equal(await DODOToken.methods.balanceOf(lp1).call(), "0") + }) + + it("setLpToken", async () => { + await DODOMine.methods.deposit(BaseDLP.options.address, decimalStr("100")).send(ctx.sendParam(lp1)) + await ctx.EVM.fastMove(100) + await DODOMine.methods.setLpToken(BaseDLP.options.address, "2", true).send(ctx.sendParam(ctx.Deployer)) + await ctx.EVM.fastMove(100) + + assert.equal(await DODOMine.methods.getAllPendingReward(lp1).call(), "8366666666666666666600") + }) + + }) + +}) \ No newline at end of file From 95638c3728d650fbd992528e2ee3d61d3f6b5dac Mon Sep 17 00:00:00 2001 From: mingda Date: Tue, 22 Sep 2020 00:48:03 +0800 Subject: [PATCH 084/118] LockedTokenVault test finished --- contracts/token/LockedTokenVault.sol | 119 +++++++----------- test/TokenLock.test.ts | 180 +++++++++++++++++++++++++++ 2 files changed, 225 insertions(+), 74 deletions(-) create mode 100644 test/TokenLock.test.ts diff --git a/contracts/token/LockedTokenVault.sol b/contracts/token/LockedTokenVault.sol index bb526fa..f79f6a1 100644 --- a/contracts/token/LockedTokenVault.sol +++ b/contracts/token/LockedTokenVault.sol @@ -29,15 +29,17 @@ contract LockedTokenVault is Ownable { address _TOKEN_; mapping(address => uint256) internal originBalances; - mapping(address => uint256) internal remainingBalances; + mapping(address => uint256) internal claimedBalances; - mapping(address => bool) internal confirmOriginBalance; mapping(address => address) internal holderTransferRequest; + uint256 public _UNDISTRIBUTED_AMOUNT_; uint256 public _START_RELEASE_TIME_; uint256 public _RELEASE_DURATION_; uint256 public _CLIFF_RATE_; + bool public _DISTRIBUTE_FINISHED_; + // ============ Modifiers ============ modifier beforeStartRelease() { @@ -50,13 +52,8 @@ contract LockedTokenVault is Ownable { _; } - modifier holderConfirmed(address holder) { - require(confirmOriginBalance[holder], "HOLDER NOT CONFIRMED"); - _; - } - - modifier holderNotConfirmed(address holder) { - require(!confirmOriginBalance[holder], "HOLDER CONFIRMED"); + modifier distributeNotFinished() { + require(!_DISTRIBUTE_FINISHED_, "DISTRIBUTE FINISHED"); _; } @@ -74,82 +71,55 @@ contract LockedTokenVault is Ownable { _CLIFF_RATE_ = _cliffRate; } - function deposit(uint256 amount) external onlyOwner beforeStartRelease { + function deposit(uint256 amount) external onlyOwner { _tokenTransferIn(_OWNER_, amount); - originBalances[_OWNER_] = originBalances[_OWNER_].add(amount); - remainingBalances[_OWNER_] = remainingBalances[_OWNER_].add(amount); + _UNDISTRIBUTED_AMOUNT_ = _UNDISTRIBUTED_AMOUNT_.add(amount); } - function withdraw(uint256 amount) external onlyOwner beforeStartRelease { - originBalances[_OWNER_] = originBalances[_OWNER_].sub(amount); - remainingBalances[_OWNER_] = remainingBalances[_OWNER_].sub(amount); + function withdraw(uint256 amount) external onlyOwner { + _UNDISTRIBUTED_AMOUNT_ = _UNDISTRIBUTED_AMOUNT_.sub(amount); _tokenTransferOut(_OWNER_, amount); } + function finishDistribute() external onlyOwner { + _DISTRIBUTE_FINISHED_ = true; + } + // ============ For Owner ============ - function grant(address holder, uint256 amount) + function grant(address[] calldata holderList, uint256[] calldata amountList) external onlyOwner - beforeStartRelease - holderNotConfirmed(holder) { - originBalances[holder] = originBalances[holder].add(amount); - remainingBalances[holder] = remainingBalances[holder].add(amount); - - originBalances[_OWNER_] = originBalances[_OWNER_].sub(amount); - remainingBalances[_OWNER_] = remainingBalances[_OWNER_].sub(amount); + require(holderList.length == amountList.length, "batch grant length not match"); + uint256 amount = 0; + for (uint256 i = 0; i < holderList.length; ++i) { + originBalances[holderList[i]] = originBalances[holderList[i]].add(amountList[i]); + amount = amount.add(amountList[i]); + } + _UNDISTRIBUTED_AMOUNT_ = _UNDISTRIBUTED_AMOUNT_.sub(amount); } - function recall(address holder) - external - onlyOwner - beforeStartRelease - holderNotConfirmed(holder) - { + function recall(address holder) external onlyOwner distributeNotFinished { uint256 amount = originBalances[holder]; - originBalances[holder] = 0; - remainingBalances[holder] = 0; - - originBalances[_OWNER_] = originBalances[_OWNER_].add(amount); - remainingBalances[_OWNER_] = remainingBalances[_OWNER_].add(amount); - } - - function executeHolderTransfer(address holder) external onlyOwner { - address newHolder = holderTransferRequest[holder]; - require(newHolder != address(0), "INVALID NEW HOLDER"); - require(originBalances[newHolder] == 0, "NOT NEW HOLDER"); - - originBalances[newHolder] = originBalances[holder]; - remainingBalances[newHolder] = remainingBalances[holder]; - - originBalances[holder] = 0; - remainingBalances[holder] = 0; - - holderTransferRequest[holder] = address(0); + _UNDISTRIBUTED_AMOUNT_ = _UNDISTRIBUTED_AMOUNT_.add(amount); } // ============ For Holder ============ - function confirm() external { - confirmOriginBalance[msg.sender] = true; + function transferLockedToken(address to) external { + originBalances[to] = originBalances[to].add(originBalances[msg.sender]); + claimedBalances[to] = claimedBalances[to].add(claimedBalances[msg.sender]); + + originBalances[msg.sender] = 0; + claimedBalances[msg.sender] = 0; } - function cancelConfirm() external { - confirmOriginBalance[msg.sender] = false; - } - - function requestTransfer(address newHolder) external holderConfirmed(msg.sender) { - require(originBalances[newHolder] == 0, "NOT NEW HOLDER"); - holderTransferRequest[msg.sender] = newHolder; - } - - function claimToken() external afterStartRelease { - uint256 unLocked = getUnlockedBalance(msg.sender); - - _tokenTransferOut(msg.sender, unLocked); - remainingBalances[msg.sender] = remainingBalances[msg.sender].sub(unLocked); + function claim() external { + uint256 claimableToken = getClaimableBalance(msg.sender); + _tokenTransferOut(msg.sender, claimableToken); + claimedBalances[msg.sender] = claimedBalances[msg.sender].add(claimableToken); } // ============ View ============ @@ -158,32 +128,33 @@ contract LockedTokenVault is Ownable { return originBalances[holder]; } - function getRemainingBalance(address holder) external view returns (uint256) { - return remainingBalances[holder]; - } - - function isConfirmed(address holder) external view returns (bool) { - return confirmOriginBalance[holder]; + function getClaimedBalance(address holder) external view returns (uint256) { + return claimedBalances[holder]; } function getHolderTransferRequest(address holder) external view returns (address) { return holderTransferRequest[holder]; } - function getUnlockedBalance(address holder) public view returns (uint256) { + function getClaimableBalance(address holder) public view returns (uint256) { if (block.timestamp < _START_RELEASE_TIME_) { return 0; } - uint256 newRemaining = 0; + uint256 remainingToken = getRemainingBalance(holder); + return originBalances[holder].sub(remainingToken).sub(claimedBalances[holder]); + } + + function getRemainingBalance(address holder) public view returns (uint256) { + uint256 remainingToken = 0; uint256 timePast = block.timestamp.sub(_START_RELEASE_TIME_); if (timePast < _RELEASE_DURATION_) { uint256 remainingTime = _RELEASE_DURATION_.sub(timePast); - newRemaining = originBalances[holder] + remainingToken = originBalances[holder] .sub(DecimalMath.mul(originBalances[holder], _CLIFF_RATE_)) .mul(remainingTime) .div(_RELEASE_DURATION_); } - return remainingBalances[msg.sender].sub(newRemaining); + return remainingToken; } // ============ Internal Helper ============ diff --git a/test/TokenLock.test.ts b/test/TokenLock.test.ts new file mode 100644 index 0000000..d678ebc --- /dev/null +++ b/test/TokenLock.test.ts @@ -0,0 +1,180 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +import { DODOContext, getDODOContext } from './utils/Context'; +import { decimalStr, MAX_UINT256 } from './utils/Converter'; +// import * as assert from "assert" +import { newContract, DODO_TOKEN_CONTRACT_NAME, LOCKED_TOKEN_VAULT_CONTRACT_NAME } from './utils/Contracts'; +import { Contract } from 'web3-eth-contract'; +import * as assert from 'assert'; +import BigNumber from 'bignumber.js'; +import { logGas } from './utils/Log'; + +let DODOToken: Contract +let LockedTokenVault: Contract +let initTime: any + +let u1: string +let u2: string +let u3: string + +async function init(ctx: DODOContext): Promise { + u1 = ctx.spareAccounts[0]; + u2 = ctx.spareAccounts[1]; + u3 = ctx.spareAccounts[2]; + + initTime = (await ctx.Web3.eth.getBlock(await ctx.Web3.eth.getBlockNumber())).timestamp; + DODOToken = await newContract(DODO_TOKEN_CONTRACT_NAME) + + // release after 1 day, cliff 10% and vest in 1 day + LockedTokenVault = await newContract(LOCKED_TOKEN_VAULT_CONTRACT_NAME, [DODOToken.options.address, initTime + 86400, 86400, decimalStr("0.1")]) + + DODOToken.methods.approve(LockedTokenVault.options.address, MAX_UINT256).send(ctx.sendParam(ctx.Deployer)) + LockedTokenVault.methods.deposit(decimalStr("10000")).send(ctx.sendParam(ctx.Deployer)) +} + +describe("Lock DODO Token", () => { + + let snapshotId: string + let ctx: DODOContext + + before(async () => { + ctx = await getDODOContext() + await init(ctx); + }) + + beforeEach(async () => { + snapshotId = await ctx.EVM.snapshot(); + }); + + afterEach(async () => { + await ctx.EVM.reset(snapshotId) + }); + + describe("Lock operations", () => { + it("init states", async () => { + assert.equal(await LockedTokenVault.methods._UNDISTRIBUTED_AMOUNT_().call(), decimalStr("10000")) + await logGas(LockedTokenVault.methods.grant( + [u1], + [decimalStr("100")] + ), ctx.sendParam(ctx.Deployer), "grant 1 address") + }) + + it("grant", async () => { + await logGas(LockedTokenVault.methods.grant( + [u1, u2, u3], + [decimalStr("100"), decimalStr("200"), decimalStr("300")] + ), ctx.sendParam(ctx.Deployer), "grant 3 address") + + assert.equal(await LockedTokenVault.methods._UNDISTRIBUTED_AMOUNT_().call(), decimalStr("9400")) + + assert.equal(await LockedTokenVault.methods.getOriginBalance(u1).call(), decimalStr("100")) + assert.equal(await LockedTokenVault.methods.getOriginBalance(u2).call(), decimalStr("200")) + assert.equal(await LockedTokenVault.methods.getClaimableBalance(u1).call(), "0") + + await ctx.EVM.increaseTime(86400) + assert.ok(approxEqual(await LockedTokenVault.methods.getClaimableBalance(u1).call(), decimalStr("10"))) + + await ctx.EVM.increaseTime(30000) + assert.ok(approxEqual(await LockedTokenVault.methods.getClaimableBalance(u1).call(), decimalStr("41.25"))) + }) + + it("claim", async () => { + await LockedTokenVault.methods.grant( + [u1, u2, u3], + [decimalStr("100"), decimalStr("200"), decimalStr("300")] + ).send(ctx.sendParam(ctx.Deployer)) + + await ctx.EVM.increaseTime(86400) + await LockedTokenVault.methods.claim().send(ctx.sendParam(u1)) + assert.equal(await LockedTokenVault.methods.getOriginBalance(u1).call(), decimalStr("100")) + assert.equal(await LockedTokenVault.methods.getClaimableBalance(u1).call(), "0") + assert.ok(approxEqual(await DODOToken.methods.balanceOf(u1).call(), decimalStr("10"))) + + await ctx.EVM.increaseTime(30000) + await LockedTokenVault.methods.claim().send(ctx.sendParam(u1)) + assert.equal(await LockedTokenVault.methods.getClaimableBalance(u1).call(), "0") + assert.ok(approxEqual(await LockedTokenVault.methods.getRemainingBalance(u1).call(), decimalStr("58.75"))) + assert.ok(approxEqual(await DODOToken.methods.balanceOf(u1).call(), decimalStr("41.25"))) + + await LockedTokenVault.methods.claim().send(ctx.sendParam(u2)) + assert.equal(await LockedTokenVault.methods.getClaimableBalance(u2).call(), "0") + assert.ok(approxEqual(await LockedTokenVault.methods.getRemainingBalance(u2).call(), decimalStr("117.5"))) + assert.ok(approxEqual(await DODOToken.methods.balanceOf(u2).call(), decimalStr("82.5"))) + }) + + it("recall & transfer", async () => { + await LockedTokenVault.methods.grant( + [u1, u2, u3], + [decimalStr("100"), decimalStr("200"), decimalStr("300")] + ).send(ctx.sendParam(ctx.Deployer)) + + // recall u2 + await LockedTokenVault.methods.recall(u2).send(ctx.sendParam(ctx.Deployer)) + assert.equal(await LockedTokenVault.methods.getOriginBalance(u2).call(), "0") + + // transfer from u3 to u2 + await ctx.EVM.increaseTime(86400 + 30000) + await LockedTokenVault.methods.transferLockedToken(u2).send(ctx.sendParam(u3)) + + await LockedTokenVault.methods.claim().send(ctx.sendParam(u2)) + assert.equal(await LockedTokenVault.methods.getClaimableBalance(u2).call(), "0") + assert.ok(approxEqual(await LockedTokenVault.methods.getRemainingBalance(u2).call(), decimalStr("176.25"))) + assert.ok(approxEqual(await DODOToken.methods.balanceOf(u2).call(), decimalStr("123.75"))) + + // transfer from u2 to u3 + await ctx.EVM.increaseTime(30000) + await LockedTokenVault.methods.transferLockedToken(u3).send(ctx.sendParam(u2)) + + await LockedTokenVault.methods.claim().send(ctx.sendParam(u3)) + assert.equal(await LockedTokenVault.methods.getClaimableBalance(u3).call(), "0") + assert.ok(approxEqual(await LockedTokenVault.methods.getRemainingBalance(u3).call(), decimalStr("82.5"))) + assert.ok(approxEqual(await DODOToken.methods.balanceOf(u3).call(), decimalStr("93.75"))) + }) + + it("withdraw", async () => { + await LockedTokenVault.methods.grant( + [u1, u2, u3], + [decimalStr("100"), decimalStr("200"), decimalStr("300")] + ).send(ctx.sendParam(ctx.Deployer)) + + await LockedTokenVault.methods.withdraw(decimalStr("1000")).send(ctx.sendParam(ctx.Deployer)) + assert.equal(await LockedTokenVault.methods._UNDISTRIBUTED_AMOUNT_().call(), decimalStr("8400")) + + await assert.rejects( + LockedTokenVault.methods.withdraw(decimalStr("8500")).send(ctx.sendParam(ctx.Deployer)), + /SUB_ERROR/ + ) + }) + + it("finish distributed", async () => { + await LockedTokenVault.methods.grant( + [u1, u2, u3], + [decimalStr("100"), decimalStr("200"), decimalStr("300")] + ).send(ctx.sendParam(ctx.Deployer)) + await LockedTokenVault.methods.finishDistribute().send(ctx.sendParam(ctx.Deployer)) + + // can not recall + await assert.rejects( + LockedTokenVault.methods.recall(u2).send(ctx.sendParam(ctx.Deployer)), + /DISTRIBUTE FINISHED/ + ) + }) + }) + +}) + +function approxEqual(numStr1: string, numStr2: string) { + let num1 = new BigNumber(numStr1) + let num2 = new BigNumber(numStr2) + let ratio = num1.div(num2).minus(1).abs() + if (ratio.isLessThan(0.0002)) { + return true + } else { + return false + } +} \ No newline at end of file From b4b75bcb71957e90484df912b5a11670abc4a8fa Mon Sep 17 00:00:00 2001 From: mingda Date: Tue, 22 Sep 2020 00:48:15 +0800 Subject: [PATCH 085/118] fix evm increase time --- test/utils/EVM.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/test/utils/EVM.ts b/test/utils/EVM.ts index a1afc9d..75e071a 100644 --- a/test/utils/EVM.ts +++ b/test/utils/EVM.ts @@ -47,8 +47,17 @@ export class EVM { return this.callJsonrpcMethod('evm_mine'); } + public async fastMove(moveBlockNum: number): Promise { + var res: string + for (let i = 0; i < moveBlockNum; i++) { + res = await this.callJsonrpcMethod('evm_mine'); + } + return res + } + public async increaseTime(duration: number): Promise { - return this.callJsonrpcMethod('evm_increaseTime', [duration]); + await this.callJsonrpcMethod('evm_increaseTime', [duration]); + return this.callJsonrpcMethod('evm_mine'); } public async callJsonrpcMethod(method: string, params?: (any[])): Promise { From f0cffd840d63654d676a89ea7061d1c2f8e428ae Mon Sep 17 00:00:00 2001 From: mingda Date: Fri, 25 Sep 2020 10:51:03 +0800 Subject: [PATCH 086/118] [trail of bits audit] #1 Loss of precision may allow an attacker to get funds for free --- contracts/impl/Pricing.sol | 3 ++- contracts/lib/DecimalMath.sol | 5 +++++ contracts/lib/SafeMath.sol | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/contracts/impl/Pricing.sol b/contracts/impl/Pricing.sol index f9ce3ee..ce45235 100644 --- a/contracts/impl/Pricing.sol +++ b/contracts/impl/Pricing.sol @@ -14,6 +14,7 @@ import {DODOMath} from "../lib/DODOMath.sol"; import {Types} from "../lib/Types.sol"; import {Storage} from "./Storage.sol"; + /** * @title Pricing * @author DODO Breeder @@ -84,7 +85,7 @@ contract Pricing is Storage { uint256 Q2 = DODOMath._SolveQuadraticFunctionForTrade( targetQuoteAmount, quoteBalance, - DecimalMath.mul(i, amount), + DecimalMath.mulCeil(i, amount), true, _K_ ); diff --git a/contracts/lib/DecimalMath.sol b/contracts/lib/DecimalMath.sol index a121d24..99debb1 100644 --- a/contracts/lib/DecimalMath.sol +++ b/contracts/lib/DecimalMath.sol @@ -10,6 +10,7 @@ pragma experimental ABIEncoderV2; import {SafeMath} from "./SafeMath.sol"; + /** * @title DecimalMath * @author DODO Breeder @@ -25,6 +26,10 @@ library DecimalMath { return target.mul(d) / ONE; } + function mulCeil(uint256 target, uint256 d) internal pure returns (uint256) { + return target.mul(d).divCeil(ONE); + } + function divFloor(uint256 target, uint256 d) internal pure returns (uint256) { return target.mul(ONE).div(d); } diff --git a/contracts/lib/SafeMath.sol b/contracts/lib/SafeMath.sol index f543fb4..dc5bb8d 100644 --- a/contracts/lib/SafeMath.sol +++ b/contracts/lib/SafeMath.sol @@ -8,6 +8,7 @@ pragma solidity 0.6.9; pragma experimental ABIEncoderV2; + /** * @title SafeMath * @author DODO Breeder From 6e23a56a17ee6f802e6baf02207093ece02bd41c Mon Sep 17 00:00:00 2001 From: mingda Date: Fri, 25 Sep 2020 12:02:31 +0800 Subject: [PATCH 087/118] update audit report --- ...ield] dodo_audit_report_2020_16_en_1.0.pdf} | Bin audit/[Trail of Bits] DODO Summary Report.pdf | Bin 0 -> 112859 bytes 2 files changed, 0 insertions(+), 0 deletions(-) rename audit/{dodo_audit_report_2020_16_en_1.0.pdf => [Peckshield] dodo_audit_report_2020_16_en_1.0.pdf} (100%) create mode 100644 audit/[Trail of Bits] DODO Summary Report.pdf diff --git a/audit/dodo_audit_report_2020_16_en_1.0.pdf b/audit/[Peckshield] dodo_audit_report_2020_16_en_1.0.pdf similarity index 100% rename from audit/dodo_audit_report_2020_16_en_1.0.pdf rename to audit/[Peckshield] dodo_audit_report_2020_16_en_1.0.pdf diff --git a/audit/[Trail of Bits] DODO Summary Report.pdf b/audit/[Trail of Bits] DODO Summary Report.pdf new file mode 100644 index 0000000000000000000000000000000000000000..1022b38fab33dc20ad1d7d88601e4c3ef7fc7dcc GIT binary patch literal 112859 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%0D=txIuJ-PC@uq% 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 Zf50ohfM7pICqgk%NkT3zRb4g0{{i5|j`IKj literal 0 HcmV?d00001 From 0a7009d54bc285d706f68177b757a07d69bba06b Mon Sep 17 00:00:00 2001 From: mingda Date: Fri, 25 Sep 2020 14:53:38 +0800 Subject: [PATCH 088/118] locked token vault --- contracts/token/LockedTokenVault.sol | 51 +++++++++++++++++----------- test/TokenLock.test.ts | 4 +++ 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/contracts/token/LockedTokenVault.sol b/contracts/token/LockedTokenVault.sol index f79f6a1..682a158 100644 --- a/contracts/token/LockedTokenVault.sol +++ b/contracts/token/LockedTokenVault.sol @@ -31,8 +31,6 @@ contract LockedTokenVault is Ownable { mapping(address => uint256) internal originBalances; mapping(address => uint256) internal claimedBalances; - mapping(address => address) internal holderTransferRequest; - uint256 public _UNDISTRIBUTED_AMOUNT_; uint256 public _START_RELEASE_TIME_; uint256 public _RELEASE_DURATION_; @@ -42,13 +40,17 @@ contract LockedTokenVault is Ownable { // ============ Modifiers ============ + event Claim(address indexed holder, uint256 origin, uint256 claimed, uint256 amount); + + // ============ Modifiers ============ + modifier beforeStartRelease() { require(block.timestamp < _START_RELEASE_TIME_, "RELEASE START"); _; } modifier afterStartRelease() { - require(block.timestamp > _START_RELEASE_TIME_, "RELEASE NOT START"); + require(block.timestamp >= _START_RELEASE_TIME_, "RELEASE NOT START"); _; } @@ -94,6 +96,7 @@ contract LockedTokenVault is Ownable { require(holderList.length == amountList.length, "batch grant length not match"); uint256 amount = 0; for (uint256 i = 0; i < holderList.length; ++i) { + // for saving gas, no event for grant originBalances[holderList[i]] = originBalances[holderList[i]].add(amountList[i]); amount = amount.add(amountList[i]); } @@ -101,9 +104,11 @@ contract LockedTokenVault is Ownable { } function recall(address holder) external onlyOwner distributeNotFinished { - uint256 amount = originBalances[holder]; + _UNDISTRIBUTED_AMOUNT_ = _UNDISTRIBUTED_AMOUNT_.add(originBalances[holder]).sub( + claimedBalances[holder] + ); originBalances[holder] = 0; - _UNDISTRIBUTED_AMOUNT_ = _UNDISTRIBUTED_AMOUNT_.add(amount); + claimedBalances[holder] = 0; } // ============ For Holder ============ @@ -120,10 +125,20 @@ contract LockedTokenVault is Ownable { uint256 claimableToken = getClaimableBalance(msg.sender); _tokenTransferOut(msg.sender, claimableToken); claimedBalances[msg.sender] = claimedBalances[msg.sender].add(claimableToken); + emit Claim( + msg.sender, + originBalances[msg.sender], + claimedBalances[msg.sender], + claimableToken + ); } // ============ View ============ + function isReleaseStart() external view returns (bool) { + return block.timestamp >= _START_RELEASE_TIME_; + } + function getOriginBalance(address holder) external view returns (uint256) { return originBalances[holder]; } @@ -132,29 +147,27 @@ contract LockedTokenVault is Ownable { return claimedBalances[holder]; } - function getHolderTransferRequest(address holder) external view returns (address) { - return holderTransferRequest[holder]; - } - function getClaimableBalance(address holder) public view returns (uint256) { - if (block.timestamp < _START_RELEASE_TIME_) { - return 0; - } uint256 remainingToken = getRemainingBalance(holder); return originBalances[holder].sub(remainingToken).sub(claimedBalances[holder]); } function getRemainingBalance(address holder) public view returns (uint256) { - uint256 remainingToken = 0; - uint256 timePast = block.timestamp.sub(_START_RELEASE_TIME_); + uint256 remainingRatio = getRemainingRatio(block.timestamp); + return DecimalMath.mul(originBalances[holder], remainingRatio); + } + + function getRemainingRatio(uint256 timestamp) public view returns (uint256) { + if (timestamp < _START_RELEASE_TIME_) { + return DecimalMath.ONE; + } + uint256 timePast = timestamp.sub(_START_RELEASE_TIME_); if (timePast < _RELEASE_DURATION_) { uint256 remainingTime = _RELEASE_DURATION_.sub(timePast); - remainingToken = originBalances[holder] - .sub(DecimalMath.mul(originBalances[holder], _CLIFF_RATE_)) - .mul(remainingTime) - .div(_RELEASE_DURATION_); + return DecimalMath.ONE.sub(_CLIFF_RATE_).mul(remainingTime).div(_RELEASE_DURATION_); + } else { + return 0; } - return remainingToken; } // ============ Internal Helper ============ diff --git a/test/TokenLock.test.ts b/test/TokenLock.test.ts index d678ebc..b82e52b 100644 --- a/test/TokenLock.test.ts +++ b/test/TokenLock.test.ts @@ -134,6 +134,10 @@ describe("Lock DODO Token", () => { assert.equal(await LockedTokenVault.methods.getClaimableBalance(u3).call(), "0") assert.ok(approxEqual(await LockedTokenVault.methods.getRemainingBalance(u3).call(), decimalStr("82.5"))) assert.ok(approxEqual(await DODOToken.methods.balanceOf(u3).call(), decimalStr("93.75"))) + + // transfer from u3 to u1 + await LockedTokenVault.methods.transferLockedToken(u1).send(ctx.sendParam(u3)) + }) it("withdraw", async () => { From 46b3d84b482248ef198abc36ef91f6504d33ec50 Mon Sep 17 00:00:00 2001 From: mingda Date: Sat, 26 Sep 2020 07:03:01 +0800 Subject: [PATCH 089/118] update audit --- audit/dodo_audit_report_2020_16_en_1.0.pdf | Bin 0 -> 525620 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 audit/dodo_audit_report_2020_16_en_1.0.pdf diff --git a/audit/dodo_audit_report_2020_16_en_1.0.pdf b/audit/dodo_audit_report_2020_16_en_1.0.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ae4ee1e5499c5ddf6230f9ccf609c835e5fa56c3 GIT binary patch literal 525620 zcmeFa2UJttx;4BbAc!K;L}^h0rHF`tA_Ad^2#9o0q^N+>1nHfC2uK$YP>|khlp>ud z-GWp>n)F^n4I$-QSk8UVd){;Ixp&-ujQ`#tjsQDZS$nUw=QE%A%(a5tYL~AF2%Qn7 z=5Ft9{7Nl)?Cdd{yB5?E64ZiPt`AL*398<;&~$h}EqMKy(Al%pf>+G#>>ZAYoxMmc zc+J%MzJu8@ArYaA$G(5fv1)Pl01S>T(%mQ>xy0XMW)TT5iwVvh#In#%Qg z^wULq^{X)M^gT+v-CSIaLi^;+rBBoqaQW=0J#Fy45y8k6`P}4*ws=HbdL$P^B;6Ta zMXPsYOlBH4_UWI{xO0sfVYQD;gZIoH1YQo`O+M{!D|<&)kDM_xz4WAj;`p%w9t{^d zbwy{ckdE!BMDv>`8h-o>nj^eNvaYEgJHocVaX((} zae(owC-s34=LwS$C^=4%#yi*NjC5tYP!f%P>+Nfv>DYbNCx$A0DU#auG@Rbgb?Ei= zQ+rN4Iij_%TS7yc^0GHYIn&dtAI|Sd4=~ZHj-l71qT=ShM4OYY@s3>R4&55Z zu>cPq@~D(4E;758PxfzS&%=E3w@=TU6eW`tJ9=D~yd{<{iDK4-@nay=c%&B9!J3JB1_1Rxyvgkxq~w$K^2AEt7Z$JD2v7W6IAieU zTzr$xa^pTvyqN1&jul^$O>xuq>I5?0a-h~l5VtsOkA5&?;U>!7e;PgPVN=}O_o43u z{G7Ub)TM!ZkEQ+SL7K&bTU99i1g55f2aa|kpFhX4>P{8v_cW`U!pE(u4C5^>loXQ@ z>X&B39xlr;_eVbn;kUX@`{vu>R_{}}TNA2AiG~RM4%F7Orl4+cRt)JY`Rn_BL7C0Q-7kp~SkMnJXK23OhuS>SJ+Wq21 zOFqq>{kMj+yjp2z-kHRlk)-0duDW5k+;PT=tZCL+bBf~fakO{d(ta}|J-3AsO7q}N z>Da@Lcc`~$AJzCFwaq_#I(W3nz24oZ*V^!g?48l}pv<#|j70u54U&N<+t)+ai<(_u zZNK?+bLFNn%d1ziM`_#=of6$QB`jz9bgV~$iv$v7s1zD7g)?tP)tsWVm0b~pRD>)zAeeRbKnDLOlp-uXh$K~6_=&*`~3mNOES zhHVcL$yPh3Ukc2Nmay(sr+gYm_ngtqzki!n-gYQ|iJ$b~0@arcOv%l6JAF)-8EMLzVrCn*Pg*7sVY}f zzWc*!(zqimnI=m`O)Fw9dyfcy^X@ghsqAB()Kwy@Q&#Z7j{g-pQ64ecKyYr}+g16X zawU($;sm8o56}BI;rQOI=DkmsEO8RU;g%DvzODUE)ysLtDR3$G&uEuk@sIT>+y_NE z8xI<&fPZ>>rk*scE3lfCF-uT13kW{>?!3y1$2%?p}x-AMr~?s@{^UpZ@Y|tPDtbr z-2ao?&!0W_gW8Y%8{DpW%Z6Tt(QDYqmfpyT!TI?``{gJ`y$1|_ouX2=;Z$nJ?95+Z zo=0tcqVQ>AsXtdH8M}Or-@8lIdtz_;g|miC;c5?E;QmKxuDNB6Qa&DEfAUgef6CFO zJ|Sc6mdQ`7i`)I%^IxUZ7Mv+C|6Z_9D@dP3~f@`)#`Cy)SUCnk8o?Vxv?`(Z?#K3?C6Mlw9ki+*R~`C^|<+EQvrfr(Imp~fkwcY4fS{~xtY%)GVCUY zWY30EePGxZrWh~~z9^#^;ZnV@E+y*g#Ql0pu8x}b29qf zjeg~O(X=Pe3S8#%MDHto!%JjT3XM@LNYRO$4M`uE-?Uo@bQe`BlJUDK%IEG8y8imov4)9*qAk=FHUpu4uo4BwD@*`oWB9TEF)zpR3`Gzj7cMexI)m0Yb7R{72hplqo2WI8?t1KoMmpzz! z#;{x#zmy%nm3~}$QbI;^Lzr5H>4LUIT5y89gV+flci!ha=6vq2bP#D>-G$Sdqwme; z0%{g2lRCTc&kJjFUeFvC(H@-oWcZEa(T8cxxVdd9QS>_j_<^rGFkg5Na#?tIC36q* zBgIn2$OFlhAX&|$s^3Jl`?N5(zI^Br5iQ=Y;+dP%SimF_-Ft63>#>m;pOc{H8B%0i zzi3ORmW<|Wg^A?M)Xh=?nM7QtR#K+yl@oFOk)yisTEV3@WEu(~S$sD-)1;7a4OYj-?A;cxL}-X6BWt*l9Dq9doO1 zL(O9zX`>-yUz`pjnL}fd^pVa3**PCr^SWP*R;c*BeC>Qe+a3{p!J0ju(dgAsZ#Na; zKt<+VRLQ_z$DY%Y=EsceFS^~;oR{ma&g39*?y$v)XXH$03ugJrAt|Y;#qXOwh=@*3 zzOU26keEl3IsP&}TJ-VT{Cp1bd!|Fj&hqo`^|^VI{|Vnmob+uSoxOXCi%uST9{t4| zG$H$iBIxoqnOunR!e2zqcLe{vxc~noY8345xc)6pgw6^J|GU+}V*Eg1-mydeG)=e7 zo;2J(R!j0-vdBC4_Tj65FYMFk8|J6AvECQoTd>dvUOo|Vl?(h3Pk9q-@hp{_J`sDi zRrN*6DUK>})BDHrsM;!{(_e5F$vHcolWogB`R+`$$=*w+OuvXSs|s%DCo691-jb|I z2sUjj)!)?5P-OYjP(P+U>P*?DAwQ(zSi!5M{yY$;dc!r0XiX!rt-w6kfzhkCP$d_EF8k`Cl zI^8QPk?E9u*SKn`*lNn+{9RIEB8`GxgY^;C)Sm0I-$c<(_inZz8?Kyj&t?t3s8rPP zOPU*&)%aP7&tE=BVTBJkTf)3~ zQI3*TEa2q(d(SurPs$%3u(T2x)P!1_nzUYxHr9+_4ts~*Fduv^cAQ4JJK9s2uBbx$ z6`eQDQ^GLeQQk_w?L)AeGn=he6OWZhu>ci*`1-aLBise#i6gOfYs zbzVs(X^+U4*sa$2tys8TkliKReuEp%`uezH(dgCDBC7*>Hq(t(iB6MP1EYo}r)@W- zeeqKDnSsR-BR-l|k6$S=fBcXpz;K3(dCJDBf9sV@h$DME_Jdz>)(P$>&c*86WfI3( zqm6xW50hFCv4%C|O$P+n@mVL`t^c$TUn0S}&$^@b?UiQ#E>3?kwu5RZ&TX%Sj@f+3 z`rQ0^(W0-RY3K0y0|ox#&2Mn+K9gT(>gG=$`MiGR{IO1b*;c;u?}J{?zJmteP8(Rg zJY%t*n4HxFS9+w<9vna1lle7Wb$`B7R)VbN3haD=$}-=ncjB#APSB~nY`vE{uE#QL zH6e5H{7OxAGbU@jsYgN=H>y&1M5K7Dc~?<={` zgUlHE16hsXr&RPg=`5L8r%MBoFDYO3v0p?6hRS?>VkN-Mc0GXAxWo=K$aqIm?y^#9 znV4`FcInZjvu(v4Ee9GccrTt0Z9y}U#@@4TI+Q($*%(;Vo}9|QyqwgqdQMVn`IElK zK}V}+V*%~>m*goI_f7YkMLsMHI|&PDPku<%%EEK`k+d?2YyH5U2eYpW`0Frs{BmY5 zpF4bj)76||o8DNyYWB)4?8M>cf~STReIbbLY?hQw8wL)wnFD^$(r~=__djI;3<( z@d^Y3sT>CWL8Jjl4mv=!k9r^F0qT9!GzShGq+@5GJ9LPS^C&A5J0JIHeqL@Ko--n{ zVrPU9=XiL;uZtrtD<~-|30zRuRllkutEi-~+X?Id4GkSF-3bPU6AEW}&MN$uzesN( zIx6xDls;sz6VM(y7#SUm)BwT3byC2-fBi}uusvkt6niPbHSY%vN)JJMU}R)_$jK-u z$jL!#Pw+ZKPDeq1Tu5dwgZdrH6Sj=!d?He)IAveIW76nY;S#=U_h=vWVdf)8S-4N0 z;^E~J5j}rF?4r2bW%(-#R~3~swX}6~Z`{-~HZi?--^|>?-oeqy*~Qh(_pzUUz>~nB z$f#%0F|p5I#HFUCXJlq&=j0X@mz2IKE3c@mt8Zv*YHoS|p|h*|OHc3DzW&j%@rlW) z>6zI%%<9_u#^x4w8@D?y7)17CSm67Qk^O00bYNV2$jQmbDR;*O+v5x#WOU>d$A$LN z%cxV{v1K@M&WDOoHX`NqyM3I(8Y@h9?K-FrbBT;{V|Iu3ePsXMz#jd#M)tRX{l~ca zp#x+vaP!FMAOy6b$CK(!{rmBI4t`_cHwJ!V;5P<-W8gOieq-P_27Y7UHwJ!V;5P<- zW8gOieq-P_27Y7UHwJ!V;5P<-W8gOieq-P_27Y7UHwJ!V;5P<-W8gOieq-P_27Y7U zHwJ!V;QtH;=!1BYWt0`=$qol8=|McHLBAjWSLPrc?D)HG9(gsQ(BxrS_e&kq&uC-o ztMuC;mrfxF7THZ2SoN24vec_iqQ&xdu^fEQFgDcTPSbe)bK^JAFB7&7ByV1)oHd}U z({i7&Q-v#CvT#19dH^}kt%ZB3t?1}ZzSC=tH6cNKqXt9UPWRgK?!5?K3mUpzRUCIS zB&jZ9hy+>B285S}w~!z|6^<-ZLAs&Ko@MriZo^J_m*~1q#J^KWGs$oA)R5G^?n)Eq z=_=v86*D|{%7p|C8SCi~&we?!Z6fp;(XS8hVhVX>f6KyA4o+EVwr;^6QH*JfAGJ<( zQMHr0Lli~d&%0shvuXMKW#T{uzOq*$=kuksLeUg~7b)`GOfRxa)D@-o%QLFMen0+~ z&A~~tgCV$x{mpLac#qC-j9gFnh(GSJE8#;{wLII4y6?w*E4|JMY z&)jTB9!R6iGCc#% z=~og&1B+SIAqA7$EjQ=}*;od<@VD}Aj2tC)z_(1NH|7xHlZkYw$MgQ@a4H-*%KC}% zcB4jC znp?uPUOJhh<`XxX^VoE_rvpc>733bh)xCmfs&LJWbRH5eF3T}i?=_WR(<$m+(TZAc2ta{G!6gE;d>hU#`=PF%ab-vpXr^FX{phKSV z?JvbZ!AQ*mE9lIVylEYMbC!vIZ?<8kh2N~Omi#qI-u3# z_AA!*-w!20eJ4{={i6mgR4%3EbyYhf_tI~2m8%bW6l|{}q8;7t2d>vBQ^)S%RmB%a z`C^?!CmD4`R$j&Q3uhjA(cH>0K_lP_KE|Y?dF}X}a&t}+lxSy%4zR`28Tdz!=dr%z zUS&0>J<5i{5~CX>L`J8=KDcBndmgL|LQxDd(*-KF{XzLZz=-UC)@R!}`TClTIh}+V}VgD6l=ctSc9Nn+nI`>6(=( z@E0Tct5N=b?yv9u|Ma}D!JlLbTQWRyxyFO1#75nWcE3e}o;LRGkf6@&-U>x-@>mm( zntMZvMpgK_AfAG2k3gBW=bt<%04y~&856Q$s9pZ``oX`mYGpE-7nJ-esjq#Z)1+1M zJiDH5cJ66sC(B-LM)j+^o!wQJhuwV1=g;*Ly2#ZIQ|hR^!j?v1wRleh)~wI5(eGma z&hM*%#fZgz_gy1co%1sjP4^*)uM#A2ZL&8ZexTr)%3O#_S2kExR4bw)vYe? z!1hj_DJ^ZLtg`yu=`q4rghWAIcyq-jV-`1)(>kA!os-gZstey@Vf6)TqsSMsUjAik zt@q5tHOz1pdYmQCxq~^xd!C}`)2^$e4P?eWnu5zSYQ_Ce-++;aNa}TJFvh zNYJd7#by}^Iv$MLB0(AID5u!BHFT?Aye_(-KLKUXzWeQ;8VZ-x6)b>e*ir#}I_&V} ze!A9GmK2K@xrftR)#)-h*4M5{&axax7b)@g36y8lfKr3dX|v3FHSPXi#EyJh?4T?} zX3$&kE#Hl_bGjA1kY6ac6!Wb|m@C9aT}AS)aM{%rRyR&@Fds{!_$|BcFvEf6VkP-S(B8 zf%~P^F+;v&49_lZin8!u9X%vmAqE|Y^z?K3#*k#yOi!IMQiFWeQiFKFO#Cl?M8^D|G0%2O zCyAXuQ1_Qb8=@Su(J~2AN;6y(^l{^y%*ESnAfKztGo^rUjL<)OIHiVltC8JWip$?H zt)0znyPEw}RQ8LomVjbhDklhpspsyUB1f-we-8$xv{ds8EUhz-jz2zf?&6GZ@B9p( zDL0ezYxUqLMF9mfH_^|poj9M+9eEciD<(rwT;T6^s5v)qt>p0L6UKvCRd5aWI0ND9 zZ#oxZzV+=%o^y|y^PC%Dn$*dkLvZ${$!qG)i5&o!>{DK%E>HHC1>zdw5dKR%P-2rC+j4-oj7|Tq8zUoGG{6i0u*hXtt&%-k76_g~% z6vdtDEoo0=W=bOLIZ1-h<0L4spp6QFumF$CMhPmO7J{2ir8ipvB9nQk|6m4$PyG!e}!&X zJhH&t%_@(Hm}2vQ^UO$53u8nVr|2yrecM4~yInI8Tpb1_g8f2*I0cdjZsCM|d7o#< zW=IfLS>hrIlKBYVAtIW>|L&;vVXC)OI0<@OT%WYg25vKY9B+;s|H=EV@VLp zc5M)Z(z6FmbbikAjB`4$hb1IpsiixToFEnihEuNxCvJK^(2A|29j6{NK}e4VKX zyz?>W8&M__j-&ocf<|PKp&lRQAx}|4MLM!wrx~1_0dGbe>_p7)8-ot_5k=Po7-8$Z zn^O_s>TbdDRH~S)lLc9dM3h?T9pa}sWPwMsGPa$v>%HfFPIBe!n{6<;N2((*gW`}Sf{-^l>t&y1+$k)kVU^8vR7~ojA!F7iw<334CCU8 zR7UvrG(jG6=+^zP6A#WXtYvMZNrF7pD8Df3e&iL2c$rp|q^5#cj76+r1PPmFWOL&D z)A0QU`bqR(X{9vd{aOZ9-EiXnUM}HpspX$%$xIl#dg67rpg`LBk!XJ>wd<;4#WYb@R^CgjsO6&Y6+T;P|HnvDYM&!F*LM@8FRDeAgrt|90dp6`ERW2QX3JkhIQP z3&7Wmw=Bo1=g;9XtDNG(QY1eq+LUt@(UZ}im6qyDrq%xId_7vrYv~pfka6>4rh#bH zMmos;CN5>fM`TvwtU_d=-#KQ`~$QeGw3X34|q_-q4Xm!~?@pP}~FkPEv?zg}cWu2$Ayv$Pv zlG(B;QzYlR&Hg8a1etg5Tb3`tCpGg**6}oR@#QbnCn(HO-0!VY9x;5f?KaF-V>AVv z6*H56YOm<{#RR*%K8jd0{DentfF$}QxXxtcqhq*QAVHBB{rENG*g{{&0Ri*8CUMW^ z3yKDEF4qOn0$sjK$pE8S_M?^!Q~Na3msgWMM&P>hwNGyG-Qerco!rU4T{e`vs{OIb zd@;!c^So`xfEZAt;nsgnL-z_>(e>6tyScVoKqc`*TyECC<-=a3+SR!_K*m`g8F zfku;96$dr^?R_=IqlUmWPGnDfAg5YZ5n)a39|1dd+t#2AfBYK@peycJ0*(>37Rt14 z^M_}c=vEZ`RZm?hZ7X_;NPs++&Z=^;C8kH#M000-&a!%gI8`5<+g@5mJkW9U)&Jyv;+!`5T@Q_ z*d$^pR9xO{(m_zClw~4&(~WRYG7Sqag}`50doImQ{*(=G%oF94PhswnAnLUb%e5lN zmeB_!$PmPRO3g!&pQ+8pMfh?+1ILK~)ry#_sg8FIB~0!pE>SH?9}&@gO@iu@JHRY* zdXk_pBnIS?q)vB>3u#@)k#*h@c0n761FxkC~iXqc!Lt0~G4Y z&IEK!<|w$~fG0-806k=b_7`ahdy@cNfONwo&7rCs_K+W>*wO29pqngk0c0d7C{NtE z&Qkf-%&8}OV$s)e92Y{!-9Co z;7y3tlk@P6NkO8w<-nXeP?0bg;dF0+- zIT;m6Pw*~qbrMu)yd5-~_Y9jrf=)i=ziwdJ*@wE z_ydps$qFB3Al}&Xn}8pp!a8k@3$VtBWfis&#F{ra@qT^o?*L%}>VpC?aUmPo3&YQU z=Ia6~AJ>g0`1xx3jp_j}Taci}*u3v9(}B9bxG$8K!#N*I-+b;3%_$aEU2RV-ZHR>w zFX(f~dP)-J;0Mefi4ptwCWn`3W#%^!A1cpmOpfut8N9nL`I3W9p0`c6tK}h^o4UM! zEl2V*jSgw1=`#PZ6H%#^9G`^so3cg)-oDS0qBRm|g9B*>|6Dn!t|yzGy!0Yk=}>k7 zm#gST{$}L!r4+LpPW)T70V#OCc<>is2W0H&!p68GXthN@S|n13U3;IUJPBVCYr)g1 zW2dTe#>UoT!dE2vpYtl*m_su>7OB@`@sIM%5@J>pN8M-3!7DH&S{5jZI()v*%zQ7u zX_0Hx^<)k6yIMGl!=BAqWaoq-Y%a*%o#ET-YTD%B3jZ{_q>2#Y0({)YD4FOubNg<& zkSJ2gB5gcMhH}d|3IQ1g{pT{ewH)*vq`j=(IGL1#(Y3E>`ZH-o|5T+hdDkH zYXCpVFv9Hq0%d!^bF>V*5}nfzO>oH~`ft4Lb;d*lyL>*2^zVR3Q0;RNtfN2DV_`F> z2E(0(H$JNp$a~oh%If5GFx3i`a>wB@hyutx4AE6w<| zNZpX~LszcROH&bTd8Z$aa)9B^wmO8{*c)*Own5R_VSV=AR*3v&nk@4DsD# z{!daD=r-8}6er#vhkF}gP^zfY*l}W(0ts@nAw+sh00r}Xl4&nv`N1R$OcUIa2>UGi z@|wH=pSOH;1!)(gC|SKti+^e!{?&>9v**SnG|GDdH$ssGCOU1w$cZzOWAINs0`3m% zv(4?>A=jf#=YTY|y8HL~^!j!@Oe@k2_Fe?)FU=fat(qC5cB+^Nduxx+-3Sk`E_A9U zLFFN9ZKsh3heI9Suo#p+B987I-+I0w+N{e!m6^Kq883Cv-a$gu6SxTi#}*B{;h+^FPK)KX$of%XV}SwOY9Jx1vkR z8MAf?JFGR-w%h`jd0XgINy~w3na?Fby-q~Owx0?yX+;{DY0+FBhM4*?#WV*eM~tuO z0NS!eo=>K|S*Se59JnkYm~~74raXCpNCwq2dWcNocF?@#XQ}hZmV@=gs-#J2wk^EC zqC3%}WO!%m6bWKhzzYoh;n2`i9&)3{8}#~m^yt}gJh}icT+=|-4Fk zEuu!5_V>?e{r%y;YQnzT3kmwsO?o57S7Z89mw@U{emyR3*W_BpQQQJS-GmYbu8<&+ znP!Wy2N>nc<3Q5v_unD&7W0m0%|4@9DL9&!iUjRvk5dWOjc7+);apMgAL zeoN$vZDf%sD;nUgQn(mwA#`k1ySQbm@ag>;5F77owi%bu^V{fka+FN+p6c4^F`S(J zY2{Sm$9Jo0dqYOX#rhiE{5+~aTR5QH-Ydj=-jWxH%x8f_1V!W9Hey{SxPteV;0kUc zSB@buq7%>5D8a?nO_YK*r-8@zUB3R|=wG+M9ztN_R+V_jdZWf^;^9dOFBD2f0NDe# zz^^_teA{mbIc#YtDG#~R;?D>O6Mb}zwsvLi{@`oieA>N)&C>C1HOg1u3dXt+Gfa-a z2`B(=VM!Z~!r<3ixsXRhqKL&R)$pZgM7MU0@R;?B+&LYb=bI!q)AFY$CUw~o6{nNg z;xN?f;l6Gc`bFJC_2gLvG(SE`S}xO&3XTBIOET@9Y-HxFTh?hMzmt3MzV(N+3Pe_CHGiYwsanj*ls{&1SSD=4@!BrH<6J_ll;TBa-GMy^=#%NXQBdMh z>jDS#vK*1T*B^MK^I#Gc>fvkOkUQ&UV7Ajn!?%}hL33Jcub*xKUVP=~8=-lYK_m2N z!QznDblO=-0;LT~n)XV`O9Q>;huN4w#Eg??@V;ys7EXG^n(l|3dEEsTb4!*zK zV#!PJmCeybwy`fT++_GhAj960Zujl z=n(P(hw!{=PTHw%;L;flxB-{W3c13KY)U6~fdHQ-_7X{uAh!3@MXAi#?~UFg?{hv5 zTB0=W(2-UoSbXu=UYREO@2jdTRsORE#$V zRhK`=zWOvC(@FNya8-egmjPDJ4~5q0$?&0wMZjWf-voCSbU*fOiM)`?^p;B9(MIF9 zf{8nfp1H$B_eK!ALEFx!zJ(;YLAc<*y+M6554pX}OxWa~987XM=cxjDDn)XJr18^g zU(D+L$Qr&Czm{f8T=Q~(ZOAjN){YaV@H5|#)x!ypr@Ficss;^yWgXaQ1tr+7N0?*@ z>gc3EvBh4=5TT(w^Jr}7zvXgn|Y&kW+43Df_DSscLRmnKa3nvMutM3Lh>GM z1atxT1GPKguHFK7b+`vTBM8XfM}Q~-TW@4qLu?WO>&mz<KbA=Ge%GVc9E0O%EsU_tr*<1?PbRS;yFtx*6TPW4f*9q+ zFcT=Qr_e%kWuc*uP+6-o-`EsT1`lRkdW!ao)$Khs%i%)V|!U7-=A zb0sAD>A6=UkII|7Ss-rj{!gmZdEH&Lu}ldI+!yJF9;F^O?vQ?u@Ghu9)JI)AtX$XL z}qw2h32)|)969dSt3iKm1vhM zkNd$}c*^auN`3+H&UZ-1BjiZB38JHq^Vo~{6PK6_U{KQs$_AE6Vo7xR z!-u!#?n~6=zbO)D!szc5Js9VFMdQ0of;RH5v^6+6bDj1}vDw6VA;*Kp&2nStY0Oj3 zHhl?OB4%aop=y~58m~s=)l|r89s(Yv(~2_iTnrz~gVwu5!K=9x3X6cfNT`mjJ5Ke?Z>63+>E{RA90 zM}ly4g+1jqehilr_Xir9Tv;=EBrWMVU$mnIau=WzHS%>WxVi67`jG0P{J|(NNhX%7 zk)F-8;Y%;O-X+r}csR*ndv!QV>&Z4KnS5>~g6NBAy8-;53dDJ*kkQV4f*IKt%T}-Rie*Y&X~gwU_UmML%g(${USK__1)&VGPZ5$k znU?dH3`ngS_C>6U0TE*e9x2@Jh8;5qK4{x82$yEI4v%J4NXBQAO}g>Vg{HN8X#>H- zqz`8w$_=k#yG`Vw-AFzt^{djcz@DL634Jd~Gfzi?JdP2gXPDl30FO38Tot#2oGAU) z4l_FQ4WMQn+^P=r3siRAIRm0oIQJ}te zaMwmH6kH;D2q2a_fdYU$n&mw&5u&q@ZGKq1e8*3qNVa3OUgaA;~i zyfzBB-YXW*$C+ZbFd45@bWbAkHYhp42or;F#ygbqK%2?O63I|lb%GCAc4$8VG83#9 z)TvW$IQUy}g-yZ7`HMqB62a3d#5Mc2@*{9Rph0e%q1UO302=}oN8ORUC(nZ3RnM{e z`RA|C$5%w}^z!8DlO%Or} zP7Z`T8Hc-FSyw08eoMn30#8?qW_jjrY%zamq>iZ6S?BO}maHwOtdo!{9Cq>5u>3g9 zmB<;Y`jKT5LcVM#PdtfX-wG6EaCE`SL@>(K-tbwF#7=DGEB%^a{$4M3Eak#oNn^by ztYIwRKX1UHuiPOl%M73;A=Z`ow?_9?OGB*%hadKAE=Wy3{3PiK^pxs#vOPgRK0mX9 z3P!F<09m2WNxV{?yXYkV(1p1`co@FTGM4?_+bdif8ODccAbSDFiWVL$l|X=N^}>If z{S?d_(xhBC`bcIL3j|2Ft{;#ootO*w4Ui$wWO#GUF;w8wiFg25H`)~u*ph?p6J*_2 zj39pPHE00pq9EY4_`M!8+MWiv%L~93n7^a)E=asUIKWEVCEA@;BsLc@YUL73bp47P z2Fj#Sjj~+b@Hh~X#trDT&-Fxn5|J-4iCIE6E#5#hJSUI@rL|MOQ8(lVO`IFxYtxy? z;T#0E5;1Cx^(A_&x9x1~R%Fr~U*ug-c!A+V$hO26;OyX1#z0o`s~UrEuXQ1oyOZz+ zkh?aMs!GCA$w$jrNTh@FY0Wul33q#49ZfSS>FO5Dzt~L}D`uYETC#4X++LYSWDI{)dSyP?9uEZb&mF4T@vJ)4 zwU53W)y{nAT_zJ11Qp1;>Ed~Z6o`-BpttIGN9GK^B^RIwE8VcE65R}BT|zf;M&6o1=%d+mXf9x8U=vpQv*Yn*@-`gaGnViW|z8)1m-6(d3GFnv!aI1{kJy+FJd z+5#24ryTc_q-*z*pn@LcPyh+Kj}k!XVvj-L+E#YgjjY7iFK<0mm5%fdh&#jzHT@iYDSd}~Yq0q|-T0N-#XSyKktlj5JKxMxXJCuwFX48G8 z8-WKkQuvTAv7!;*Ut{+-*W@oZ)chLEzw=W`kB2N46F2$bR{JYFhRF0u_vScL>oY(! zDz@9c`U!4WUAL>-3vPs+Z7&%;xAS2*-@`UTZ?nj^j2DS6`5%@_*wJ4%zZsEHBJ^Jp zOYT~T+ip4E@l9iiejpH8AsQBMX?o;_@w=tr2CvLQTP5Bi@g~2Q-pM9WhRW90m+ilW z7&DoKggUF1R6J3(zp-rGc)dFS&MsCBpN1qRC~#Ft!9@lY7Kwl3`sg6 z+-#L(w345@p50;1vEvmG7}&slem294pd1^QF*)Ti`#gt8_ZA;u)ReO^(IM~HBowrz z9d_!X;bgr%q%t1`%oOp)z!w>s%x-?GxUlw zOG|IHx^X&hNLhky*a^87T;gzBfA##09znrdX_v;?_z0A!im9>;SRS_Q9y}~Nk7?tOy_(|hA|@)T-KA@tU|ky_xSHn}eBt^G_+$JLGP_yN=&S{Lm3cQd zmVv-v!8wMV^Q7=-%*FQ?j34yBkHBJ*sh|DHa2Gf(vbzFMqP9m}SsvncL%k(I+aTx$ z5c7uGhQ%xL3Vn{}i2^gii@snBm7y^PO_aeI5geno1>786ZJKE}#1T7PNUmhsQ@@bg zUb`RJ(gxD;ciWX|k!cL9f1xMtgFrz63QD2g{IQFZ|7|TV33@LL4*^{ zi0)(~5>&-Z4Az4tvVSfEY!3S(S5JZ1GE&9IRP~P%>3EDNa>ytO*}!6jtu%!P;5*OS z%-Remy1a`sdsTq1=Rr_`z~@7LSi@Nk;oD?4fqAuS!4zt{Q|!NEoqINq-WvhaF@y1B zqCA2*dQlDGPlMGc!E`&NO(UXhRi{vA8GKhVVYEg>g@dcmd?;|BOT>stg;^bt6m#nk05YRj)LSEz94X)=)(;7@BmmF2G*}m z_~zka&}}fVg!dwWbleZ_K{616L^1?cZLcF!8o@7rR|%3JAO(}~Jj6Os&e9>lqDLE% z5tblt;K`{K`ub$NOF&2R9Re@9FD?L&1r{FQVQMHx{$^a$68W%bJ_fawc#d+8uN16M zJX3?r71R}##DVo`35=kp2NM7iUxQ?E0`-Oc_<6H8ibJ!tNL|E@t)%HV{)RnX_WXoa(veywb`@~zZ5qa|cOi#uCJmK;CV4dFp|argI~@@Jr5Z8Kb^#z;Y+YGV9T4u1D>d8;OfqlUP-!)?D zBas51H$4AV>IkxB%@lY6MD68uSepx&+RL7|h&63%Olzf{3>Y$SsQdHq$6|EaC?@I9 z4Pa5QFk$cvS9-&vy8iJ_WUDnR)_`clo4w#GjlxxYfrhpE}-g=#i{3c%WeumLY zi9f0kHD-ek2gI-fCy?v%{+Jdw^gF;IsGSZHbP~mbx`92BG*g+jDR>0$11eZ(gKrHU z3N!$1CslEebRLy=cAC~8~wiy5xa-b+Ak>}d1)j7?=^?s_$)Z} zWj-3j1=;vs&pT~uPkq(_71Y%jdLRBL9H&?S%Zp(z)BiOL1!wr<;}XS}Cl}SSmpvrRhh$PE;pIhFwDP)u&ckXlirbv(w1q zJ2w?Lq>3_cKdDkzv5*(3Vy~B3YU_3F_V&YRKbrTrq}iJ{QeS2HKW5+Zy7%REDIdR8 z^&?=9q&)?R@%A4}bf%oqkEmjc>?8O{kAV4sjYiY1*vaF*cYInzUyfukb4+%|KYkW_ z#mzuKqs!WFGQ|F1{zcrns9p8>`~}a;Ch1XffWPH`u-cDh=3l?>lV?hB&zs%6xTC!w z6oKc$4?mq=&$_qCU~X-8FKB!N4!q+p(3_XF(aP!#G&;xykwB1DwK%V5w302F zgroY390$~?;%syPF(C)mGeAhpT&b*tFre&UX(NzZAuu4~Plo^9Q4I*Sex$er=A$Q zZGSW>SP5^CEG+3-;Euv&IH3`msRau*CYj={S!)A;?iW3{`rH0l~Po-N8rOYRHm-HnmBVRxXgmJR2z2pno2pXFe|&0JvTc+ZAE*fGf(hc?Dz`B&x)dYw%c>X^ zPTDqjXO$l0zf6=oNrG(A5vbUtWq5(79H2CgC}jC?OYg_Ft?(Xi)?b!Yw+;d`PD!vg zn&4}cv&axIzA~2$!{_QjfBp}Y=!@}kpkDo!1#(p+xXF75@bhfJ;+hsT-5uiUn$dG7B^#EtM>qTAwnP^e-=MqpEu|Q zBtlCJa()z1;Nti_4+-qw3g}jsC5&!>rH{=QBQ1ppIa}eTLf@RiYvoK#w5dNa={f58GX4L~xtE1ch5df3CpIdT|`H zVKt9OPZuh5Q$x64G)>Eg9ZJGRyLqkQbfa~1@iwy=$N|+^L+zir=#LrM5NQ~=qD70n zx_t2B;Q;tnXFFw4?|w`G@iNHuC_iH9kS+}K6c`@-v^8&uTCg#|1K)?{1g8$b>*@?| zw347`_b)DjbxGSC1?c&BU@L6pLQ`HRlCUYIf;g~a*<;H{)piMkmcjBt!tw`Z!+lx3?Ws6xS=)7`x~MSLsdzDwY6gopC&Z{pol3tGtW)C!B) zTA<%rFgeIx)fxU5Kb*xH`;l)We2n5pqTujb(IsASN8>gSxI-v26g!p&G3JSER<`}a8iJuDru2PJ33g|{T|LH_ z$h06jp2UirkOV>0`x?kfAPpLS^_R19Y1tBS6|tG&R_dzycB!(X8D36;`lIK%{}qt` ztFOV7wZmIGm((1E&P$b#Rd3duksr*@N@1G%oWaH8=6{UHG&5otsSx@?;l{`A2aM{5 zK9jqtV|QBr>cLLwXLDJX#{Br`w*KZZJA~k*!997`+)E0_BKGNM967t7ptLL!ztMfV zAuWJS9LKVXai}o;^yYqXY|m79v3o%c4NUo}xJEDC+@E`=vh>AVuR@tSPccSw`uX2= ze8OJezSMT2>O(VzBQmZwX665}_ZCo9ZtdDIr68$DOGrqHbP6n_L#4ZA$ACEeY*VEIjT@Auv3J^TFUoNxSN{O63{JqBYxF`dt|=Dg+|*L~mf!9~eG z5}OTyq^?`YD25nS#SF%%cQqZ>aP&NKOnkl_Ve9eOcf|U>rzrAqo@Kvwa(k?@vys`d zD&`v>9C=9;MN`52i4a4}JBwXib?VX4WiduSekq!TMe`k(*$1Wf?C^sr8daGcA=qh0 zTx(HfwiM$*U-Qd()-9gsrs5e(lMp@d|*x4GK8@d-W+fhy@e z*8wDV23TngG45?(K~UJ6!gj9Kkx2gFJp_T$^S=ssO|j2%jW({P-O%DVIq$*inhW_r zTmAR7giKvZs>O>*~f*b1?#_V#K7q z*6$J1jn%2aSf2l&#`R!_f1$=V05uMTnWx$nBljTZTZ7(A4P4i#SJ{{Hs68WU!;lGn z$TiYK$UZRyI8bC1aBl*NbIfEwt#c^o0rmI-aGu9#K=(HSVgw!X$pLzaq7I#BhXQK8 zSKQ-~J0zWzvg{)gj&&*Bxe{c7c>nAg!J+>OISi0!I3Tkv;B~{vklZ!qxS>kn!<~Zr zwKgh7j`)o)Orl#XxKvYpIqSomarcu}tB$bU=1n3R7_X z(n<6ww=5w`yA)^R7vqCM3P5^MgS}PL3k+6TI>@DEgJgb*cfU z#Uzi87X6_txl!2gx3HBk5sSe;>0^Aw!=r;H1<%?;Lj0 zdF|weZ+Z#&{>jLE72=VG^)d=L;wHcunYx*V0mM6IBY=iofm`V6|DpU?n&d8sSsJ#$ zORQVyI_ie*E6AN*!mBtX2W0*ZV4ez@lG>Q%Hd4Rl{s0T*OPj z;15>_yL*A%`kez4VFFmtck?(sXJp^P?W+4mm-7@W!gz;fU4ZF<;}Zrz){em9Xefam z;1gakLUBPfLKX*h3Cu!-1v}7c3yu#7gf!>_B`F7X)UyQ+PlnTa@yaj(GRjYG zQEm?eErtPQI|$ZRa%;mJSZ57DeFUap;|A>}FUSR|*kyIq#VRF_ic5kfrLA*EUw@=W zgzcwb)7Ej!M-q%UN^XCafUrZGOQ0YbGa2skg8~OM>XbYCepc>6&BwEmp$8hHNUv~}UKMUbvZ;|CHj6V)g_C8hd>$UE(&U4CL8*KQ07D6=b%Oj@gec|IlFkMf- zvgp{F_^FDK<-zEu0v06*;W+3pEOhOxT7Kq=-S)iDweD|)74kpQ&5LcXwkG^#4!$G! zm_0AfY0yXaJ&yuf^H&xwKG2|{>{1ae^+JxhwT*=hvX4;-SWj(URE$vP}I`x3xuud`nZl0 zFV;X=RB$a9l}Tama5jRro4$^c?1nvN4c*9|d=Jbp*X*}=|H5lk(|ZDSb#~VIpaivK^Qnx>S0B?Y52B9fF4jG^ zJ`HoZJ$u4&ck#&>#|SiRtTw*vf!x3)sSqQVN>bS8Y_LUGpJTB2gMYGdcyG`_njX&q zJnGb9d4y8C1A_Ce2hs{-&E2Z~+-%+VzB@Cr_ zZnyNVHqlroEj9)QbEbmjA8bEvP5;|3b5%7})cI&lr=;UIEk*^fURt{I++6Ub)jQ(q z4vtB+T2sa4$+b^Q3u5{zXlwQdk6P^ddh)pkwc#bnMbPqYRrF;Qq|k#W2bga{Yw#+b zL#`vzhAq8KP$VJwrwcQXjNPy-0hp2xaFc3Zsj-u;LKK)|CkzArzVyQw9Vv`uOO3i%Uvzpog^N^Vn$Im za4~>rNnw>&`*4P1JkvGqvteQ71^~oR$lHxzTWZyBw_5e2~BL*Av9ov3Z#% z=|#)ce*UFl2iYD)({N8s(H}MdwLmi5JU%)D)Ka^PIA-M+hChf`zMdH1<5l;t@3U8&SAhB|i zaw9Fu?sBlo1B4DTzSWmm>1iT3>Yw++#bylQwaajc3MQQPhM$!(z#`}zK<(rFF^*}G zK?oK9Mp0fwiOcb5eG0LyUS&(pN58c5!mWM0XbQB_rxUq~NxI7$!wwj&awEk9ClmoY zx=YGj9*^eKhv|m*ZgX-x!hz9!CZ9hNreGh`tfv~ZD#J3+5jyZRyHLaM+H_?-g`_T( z8~;qA`=AF|C1VFWfW`rm(d$@our+cmGR+^&&IDy>nKgtCEiE4l>CT^3fwd zM{=YCj&plWEb6<)wr?uM`5LzyT|?j+DL5%+In)uffkqOT1u40tKKwp{FI|69uRrAE z-~G*dvO_ylajrdz4__YepN56f05Xo*+_z&|nF6-3)%G*Oh-eOEdLhuZ$`MfTKLETF z%v&qXf!Cu*AcRwf*mk99Q;(KldLuIg=ck6ftGjgI3l{@?wcf33iUvGwAGFi;x+ z0rn%xID?K}3&jQbHmL8uyp@6j{ZqYm3H=*&svCDumb~+f^KN6{!9~!K%r6>w$nzGo z)AWb*w*3(UIeK}V>;pX{9)WCq15B)!;M>}@CABNBhYef6%Vs=&d6XQgcZg5|+WUgE zkoNUI#$u=b_77)^;@T$a0{x6bmwMj;c?roa*a;r9bBx$^1q{##@-sN{)mEd$Y&{dS zGt?gVf_E>*eSW1+>!5l;mYs*dQ=rt^*AC=>c#l{EWJeK5|3|oF{Heobex)A#82TR> z>t>hx#jz<*j)wyIv>Yn%K$05H=2sgSWW$Kpky~(1_7mRBc zT^m^1_mk@t0ey!0zC)|g&uMOn{zx87%tYj{kjYX zNg}h%-q0$O^dl2a#Ku26+)74KBJs?Dm!w>IL&oa(Yx{wd>I0nA-G)mnSL2_n_^*26 z|N8iCY-Bi^>o{a_%j5J;-_56T{R8_@Z8cGO?Z%4R0xV}bQe2sQcG9w+V_td=Vbdij zD9#9Sq}NRq|t{`UA+t;}D$UR`(Hi#sBPzfi*- zMFv}-9j^?{`a3>Ukvge960{nYFRRrV8^0q1nRqo?FdlppY!=vqw#>>)eNbpYfxkKS ztfC(#g0m2pJYKw|UE0*WU0O}ldZsF<7_?djC7jr#5#_lQY})Qvp#!0fcT5?5;&w8) zzGd$^`#97BHtEwcew3>sRuGR3UxcU;Q(qF5(!q6C)(a5{~yZFR@B&wR=hQqE1rdcE$l z9+^y{a5qN_2 z#6x#Q2ADaQr!;BE4OyH7K40~(2$P)nEyW#P;pejve@BqezX*Y9&K9|KfB+6PD6`sy zz6a7N=MV8Xun(x<5LeS{k2WA>gDy?#O+dy@2;jK?yznz*gDts;>KE6lDYSmuqkfth z8E1)X;M&cV^mVVZSk6JG%4ke<_!FZ0L6@<$QHvdZ?t%C8K8KxIHR@2E8V(tp+Ur!ZSEZ!}&-(J&>%$;6gDlhB!1F5TP)8^?%$R9&dHs#C%kqo4+~&++efDBFiP#9CYrqKzmU59&|tU zJPhvZG5B@1;$E^~t^9_YoC0VnrIsKdfzOl>I?}NfTa< zUWTnHj0Pjt$XB2k5ff4$q~PRutf$3#@mhy~!n)+kbGa>DGTrHez@T$M;q`GDoMpKq z{Ka2xhnmiQq3HQx4>_n6(|KD(vMq!M?Sz>E&9eM6bniC$$Lb}A98|zXs-3RwpsP%P z<`m+pq0!q}S$QpAAB!H8*CM}q8g01Gc2PRIluK!MJK->k2z0jiift{(A1)^E{5 zfyVz)M84z?_bP$T16{Ld(Y2m}10dtqfpd*$1m@WLmnV$zj^Yxj3m^bEc7eropa97b zPDlzlz7Yii&8Wbeey$gy+V=LEdVmTFqx#5rP;yA(lYw~tX% zn86Hr4Tl8UxmExjUrz2BdtiA!43`A&&_Dw>`TUFcC^r33>_=5NckNjL_ljA<-+|s# z#zE^7UMZSLhOI~*r(na%T`1b;E^e7OoU}D0x~{zhj&CUVl~x-|6_bG-^-IF!mVY`q zI`b3+)90$P9hGHnVPz=Dh6rjXYsE#9D>`AI77OR{hBol&+lnbOQgA>IeoYx*cDc`v z^bWuQID-!G!$5T^7}ER>U@IB^>qYN_@qogsXN8$N1&Xb~x5Hk&??*{$eRtCPPu7>b zZeNUIyHM=(XdL(y#ZQZQ&*{JqJOOFZ9?KG4l0*>$Tj98oJ%b z5()cUBBn16{HG1(=~_{gM|9N7fpT

HIS}#v4b5N4p-k(p=`6Ys-g(Bzuc0CcMaW?a6a>!MGvrmH!1I7?t&Hhv zjH4QAdncX2L_4ol*`DZOj{Mnl4PmDUmF(;u*i}qN=0*{U8x3i$vJ%?IdT$2}MZL8> zhE{Tq$|Dl5;~=qGH-)RAys!`xt88F-=fZP_eB}aQY6UUhGvAQm5>FGsbYJhe`8pg!fBDn?yOQv50SirV|*)*-etC?AYWS#n&hq z)~8WVIiiYV)GAnqzV95U{T8x-9lUDReS+%NZo3=n5ZstkY)0unv?%qHPuH69R0=QP z*Tu%C;gq2v*^j0N={c^R$=aJzbgsHq`LPw2CIgeO~dg^+o z`^&td);5fI5)Yo~JTIyQk>D%{XT*|2YA0N_U@QT7SNB3aU3JAc=54(Orf?sQ2I<*f z=_oy(LMn1RZHfiVaiZUhVR+s{su6RV{a5*!eC;!1bkjxhMF4-2YUH7l+c-T72W~Z2 znF-m_3W{0B{BbxUUC%TT5c|~S@ZXJrX@d||laG9VaFs2B%osLqt0vRb)BWX#a;jIp zD;=D68EhmqmoVCSo7sB4Rp~TUN7^qJ4s76iD$XQ*bv`4q=psw$YRD>Xnw+iD$|%y1 zhp`E(_s81LAP^J9E|nllfQL|Vx~*hJu=3=JZ#ByaT3Xb5dL@)3mC`ne?XFAYftgP$ z$NGO`>>QRvQKAIcwr$(CZQHhO^R{i%pZ~8kx9$11&_ ztM?o9Epixf)B5YhUcWN<@1hS8(g^&hv{cPSwvCuz%HN)Kr!p{=`6(!Ho)FrHaUHHV9%yn~9J`#i^ubYs4IlcdYYijGOa^|*(@Dj;W(eUIaduQ*Gld^q*p zQ#q!X4jBJw0y-D-O|$5p6yM$Zb}ki*#yEopuht#!#D}>Qa`%{iwl2a2p;pE z^vlb+%Mvq0kkUzD%~LPVbh|9jGgi?w`)g8-<3ZjjX<{R6ALCRAIm)^zlTAa~Qep5^GD--(~ zJ9I}<`j>1E4Czzbb7gn@1R~p<6c1g|e#Guy+M z<~2p#Q;uXw!f@&(vIn{#ghMhAtSB(;NFgav&60TWN`^Qb<0&&l@5R*-{(i8Z?G^5q zs1X8nhZv7}?cd9V<9AH#>RoPylPmoWouTJR%(59h+%mudtamXv!O5xUw?`(J> z3C&+cto&eZcAbv6A1ID8<9{%Vk5(6zpb0!06ipX1FqPwjEO?xQEu+ixLD88OKdWi) znQk<%fFy)@(-p3EXh+90TL!!C)y;y`S25ww0>9ZJ$qdbBpINjr-zxNy;vA7 z-ad-w@dSEP^^aZeN%gU*d$P+vimw7_p%+RAuT9c9J;K;AbLVPfSAr$`y^K)iQuE?* zBz~4ra9eAh3@#U}XbJc*;ST_Mv6TiztowiN*PTTAKpp>b^zkq~nvA#Gi7sewb#s3t zO?yr02Iz%M4FW#CCs!SUHz!IFSbNX`PF|`|L#;Ex#`st}M5?3>jNkzaz!dGDI#4$l zBIdG#68OK4Z)#APXp3u`_Wb9P>(B=A^;N##AAL} z7^yaNIJDq+F`L^n1%k9EGjH-3=cM_tl;q&w85z)P7=61DAOp&x#4yTnIX{5>NxvPa z?ee7!IWAj*U22jJ64T1&6)7)C8|ljo_azmeOFwE%;}iwV5Z8DKtTbu@6{UwkeyslO z31i%^gHO?|L)EHWVXmyGn#C2LHUB7033AmSkYT!6zCTS`nb}OXNNb}qXDZe~$dJb1 z)hSU27BdaoU{fGtOwH#^P}A|+5)Xcxo{8W55i@*7T`joboUTK|v>NpsFpq%so;bcp zZ=j7{19XF)f0L{bLwHmy{$>`@at>1_szmY$Q&%|Dgd+YUb@$){h>R8+^!6{3?ML6Cbq3Aw57VoF1kLR@qu zhZiaVUIr<0vS&oeSdSeQ3w2M#5>Ldb)JjXXlD#OAs}vAX&hcZE7i+^D3{tgD}Qc_^zG{M3;7;R!wBMA0(qt8oVz_K+r3mlrwCJE=kZc9pdHSPQA9aV_(J+@NaW@iR9!z&=J)o|H zb^p?cfVQQ;(MJQglHxd#N?V`pn>B8?HI}(?Q0ZaTzLF?=XhW#hiTj~We*wm4o@+gE^9ws!s9HtDX+TvB9<96Vr4 zq}m{+RL%KDE*SQ{V$Z9YXG;R4%nx7w`9*FftC75~c1t-k6J2`r0Ru1?Ln|tjB2*o3XN@G^aE1TXJJ& zC!y@rM7WI(5*hThpb{*BhZhcU3w)n%J2fT>L_9rkWOJ!mWCLh_ECFxze;;&=#VK0P zf-^yOyXt-SfdgDF90xdPI0g@dG$WqtG`u#fHx;DAReLP{Ih(@ci}Bb_&$HEwWt{eO zNSXnJ0r_D$W|kRW(R@_jV5hf1sO~?@Z3aB}=Nf}tP}yU~$u(T=j6GE$_slt?C&mw| z9J{WjN!7Xbl!oaE|A6`7>fGZ)Z1pF{u*WlpZgmz;Ri!N7eAYCr6qg2mA{Ri~D-o(3 z$0^gBtOqOIXX50P#_oT8sY%Az{{2DI_A3!43DWaT!VOI?K1%6J3tI5-3x^i$PeTJ& z34pEetIPy0&u%HaC^UxMhh+V0xrJ8A){6ja2b@Q$Z|>u$>@J)bhmza~#F2&%KMWXx zmE%Xl`gAlk0?Lyy6afn2GG2QQNa!%Fy@4`y+Mxo7RGj z>AY!bZ!USVN|@W8up3 z9?t~Ei3pyo$eo+5-JE4*z>iGb=kS%r?4_J!eIRigqL*)Vrk!H|rH?3oa?v|m2dW(9 z(AO=J^-;d|AhutoWw49mxVN;&LM0djUajI_4Rd}L6%`s@i4Lb>ApX7WI%~Bh2=Xx3 zp?cH+q1Ll`-KIed%Opaxb-bd9)?V0z6?mRhS^>xvsE+MPkP*6(pW$mNjbbrChrHEm zVeFsOza}R}m#Rb!<{dNH5m;40rn2YDKi#6{uz4L_u7QLtFA9fYJC3u~A5j`T;}SXI zXyIVsnz0CZT*tmMi;@1G>^G!Q#fZ)pclh{iQve)#!br!x{w1PN%7;=wphF-i*}s&L zemlHNTHNadJ7;#LOq;jU9v6#k7*gyi5w_|Q31;IKYwv2w7<`5% zS2WI-)#72}uawouvqGOL+m2%bjYuUcto*r(aFreSiY=`u-}#=Owlif=v(9H|b-PU= z+$n!7vEJ!9N?afqQ^6S0QtGcO=LEudHqj^;1%%?&yW7PF@8VQ1^Y4@CXXi?bf%45F zlC=iYOp6S8RK28H-cXbJ2ew^qKRcLADM1!AMMcHg_QG%;JA1FuPuq{PJ`5|FN4De* znFeDID%da`2yGgPT68X8uVKXIi#)1Jp47tqii8k4>Qw(Zhf`E_xP0yD|I@x;G z7J*AIlj!;+>ep+Gt6+A+-{u+JtSeng(Mp||$AnTX>q!R$=Li4{&8lzynmHBA#S!HV^*_RATn>q4P%?IY?iRaQ zTRUWOZi1mH&2ykIO9B=q47SY%6UYcn;(=w942@2BrU?5k^y~9XGPjB0UEudUl?d0j zFpi-1>2^)mf4x=@A8rn0Xoj3mVl%=IiT5&7)Eq9W*+1sRBPQGhz2Bqv{NA+6u{$U(Svf;uh5HReDfZwInOo{>ZcDZK}nd zAoMFI&JauM`k62&0Yi2BzhYa-(WqtU0tw6&A<`Yc+=FZc@EI|M`zaxAaslU(BzY8v zHOU-~d?7?dV3Qyb`y{nALE8696e7~wf*f~N6q)je8NNl z(7zpZXC2}E%hfP1cT%$(hnU*Sg*7E>5Vz>lSS;KRyYPAUPms1Kmay1|nJdn3i}i|0 zT#&KiGyYhrHBplpZryPE5xvT6%;bLAQ8yqxnHbf3>qtoXp508W=Wf{pb4sls)M+5D z?d^*2C!vDpVSRt_mhpzTGL20se=*N;MY?+Ucxcu8-im>44*(&dZz#KPUfj@vIMPxa-z zE!06QP@4rfgkSLuCCp9`j4JMsrX)aGb04|`$gNz#u6t8I68F`TiieRy*@YiWJf>v?OQD&CJ5fh$hp>4P_f|aXf<0Bxb2eI&D-?^y-cKjx6@e(16OUs$oT1AGXTv z^^!zgL|*>6mre@f`;bjE-ZxkQCuBizs@z{l{Hen@`l6XFOnH z%A0lH+$5vCV_AA_{d>Rdl{5I?DdPrPcdWj zW4iWCgacT-7(_y^u$@@BqR}o;kVWev5!4fw($;j`eE<*u01)c0n@QF-sQ*c+h zt@T|f8~IJh*O4=7tY6)?`@_9v;~i9es|x;nPr%Wj3_6~(%QH~Nv%Bb75}UwJWf{44 zr8|1chMnGA(RjtC#aeWEZm%aa+0oHN2%+qk$cyI@>?*M=rZOAo8tJp-2}oe8vBNqU5D8$!tALRbOd?L|$AO^aHEd1TK{Sryi3 zc@yiuK^|RERhZan3)Iudq2b#Sm(O@6z}&a>%Ua&2=LQNj=@wN)liiDIdZ38IEwGAs zAPs`vj#tnYTgv7FdboePL;{|xzy;yH)E8^vsPPn=vcNUHY(hxZChqMuuD$qC==uX3 z;71R5apVI-dzv+|jKS=GzksKxLCnizsck1VN!oL5w_nnk@Tm95ji$G$#agG!SWJ4O z&q9BKaW!FsR|Aw{kYF9eZxhB4!(G`0`ZL12&N6;JoquRfcs6 zWRhnTe*JKPM~b0tWCVaJKV;#jS>>9}q#J#OMb0hYUj{^Q>3m?4c!`+jf-X^$R@9O5 zqhPju5~t4qPntGbCe=bkA5X{7M5t8V+J=?JPb?(YY%<8-oy0lv69qHcmEJ~QP?EQx zwxsz<@`5y~WZ3d}&)Ts(xDKkm*SpTwo{gSMIb~*`6Ar3n*3yOxC9nlPS7)T)z@rEG zPwN{D#+s_MykvPx6suFw}00P@4*U(q#Yf~ryVEX5sG zow*D0pQm_uLFhm${zu#*(eDi{?oJXXH!;K?K&g0O6Mcet`}9LgZ)3wP8bEow+hSYCJdGSxS6LAR&ccbP~|dqOkX15lgn!<$ylM4Ur*MGm0Q$S`J-76-mMrj;Wu9qD~ z=(R@B@Z&JhkQUI$6JO(K+U>TdEf4H*{=SVn96ASxv- z@kB`3k1&J%X%dy#Jefs?;F@lzceW0~0rqnKF!hi}=sKSi#->ZRIvQ$TlBjH(4zY1f$0o5nG*U6%7zi!|Kh@#);@nH`k0{xo1IUoToRZ|d6f=*0{%oj^3ja&=5&=S{oCTGjGz>hTTT&?M!Wvuc0IpNF-u%QgH zELcyjlF)ey63)9zgM|(npK^uZ?JuCjC|T0F=Bs0ns@2KHXlC#Z#`RkXpXW)YPa;za zk6kcB)J(E^U@0HBtFa0j*E3|QT(=jJnOZb0mFfpEGQLnr67VnhvSXNmTjDJOwmwg~A}TY0%JHVUOL?SU zdVTqhUqBpeTo;`Hixo*-&d>z+_ww=g-fF2}LES?9OfRI&3Ru0{P%}bej`gSHwc6e- z?yriQe)XK!IL3|;l{L{nTjZ~Fx|!cexpg>>GDNMe-}HnB@aG9HRUb)E9*m3&d0Uvk zmO&iYF1&Tu;Yc2>%N*EukCDo8<_86aqOl{@fA#SL^d~?aTQ0WkO5F5b$0-xrx6C+H z5HKz<2OnIE6p}_UJQ~8jc+Rqa7T-h|QV-j!u8aks>dX>@W=s@h+=x4_1xJavY=caJ z6Z~&;JNPG9Q4=clHYXibi@fMYB>28{jrRnYCOX#MK`FZ7cso4f%$r*fO7_mR1b2o*KUR)TL$F?31^l`@)l1Y$Lg;V>n)>o@S>Jw<}Rxx zeMO~UsIx$q&Rb>mV4~&Yfmwdc?!7(>VCj1mdH^6LW7QD}WkJNP1n;0h`tZfb9`9-w zV1Wp1KGy}BYHe?gX%q>4FKJw%Sned;8^TPC+FTOit2~^^x?fJTly~NuBNCEWimw6- zmHzCW0e8>tHDze(Kee7CJi-#oc!qDax`V-)FtU37h1rEYa+E z(OToI#%D)V(AhsP6}6!RZFy=o0&XIs0ZG&_ZRu0x6fobS`WpvROGGuh zTL=7ar@+{iAvOKpi}&kVWBxuX;g&_8IRx6)K3jRUEg^y=v(va?SP^g5XAcO0kaJ&B z1DZpxX33zzRA-0B8p98#6 zi~J>lXU^B_Eu(a+dpdN>UQlJ|3-b(n%?)b1ukrDJ!8r2@i`2@OE$s=t35@vq}290^8Q(n^KVO$C+*2Cu7+A#<%D?|X$6Rg;Hd*Yu9(ZZLb|8Q zsz&I=7QODBdbG-P?yDVXjV88WY&fH0W~wCRtnO)uP`Y(B|7@WS#97C8lA7d!Wx2I4 zNEGuG0YM>Z9m3I#FFH=1Fxo47+MW=^7)be^t9v1{d}@!7J$CZ3>bKv!ojIfm*(-Rb zS&l3gw!GfE&|ZoQtPcm1SlpNLK2pfV!=LW_n!J@9EJ>5ncbJF{%rJY_o@W?d1SIuE zB|NxMY)T-x1t5nOBppNIA`!_zVSwGQ$Hn9AwS;3vVysUIbbX%t5W}7970U68FZ~AS z@6Afojl7GHpy2Lceljsor`-qwM-ON7xjnt=N>b4x7Sogb_WCCwmJe3R&m`O1(WG*& z`Gnj;aCS%GdV5q~@et5j`%+|ariYa3xA;EEoB*$ut;bBU2XS5Sx#6L&gDElBGmE%= zIY{LnLO5Al(~=sqv^vG>kNV0d&$_s%n%E9Ujs6-+*7^azd960wFjvd9pXd@yf=k%e z=2;KiUQCz<9uC}UbV;?griDVvBUoRpF9ymmE#R67!<+@qwyaYF3&JqQ&=!2GI3!)? znZ;pRce)5rnOeXj^IW-((s*gn8DdZpX(cTeFO-jnx^3^30wqJh+BXg&v~zWw1mFa zU5|zrez_PhzRcMbm=ig<1V`x_>kXrSjHoLSjVbdJGj`{Ia6t-A6MS`(2~uAI8$1;z zx0`T-=c6a~BqHJCwp(?Nen>Oakg6E;HKjCYai=rC7E2wn7N%Tb>cqsV2O_mBUdNi> zCAqE54L4U$3EdmC_FA^L=fX@P!xfVfpO}k7hUe=9Excsi3BA!V?T|L57cn&^>y*RF zRN%?)u?aLH@-h*U87&OENJMDD>wKv)#2dftm};RY)b{+kSAW!fHc}jgSwxF|Z^a9+ zg=Ga%aqjOIacdu!V$Z(MYm<=&oS|e5Tcc2Qqrbn|l)oDh9_^-u&nV@T`BJKzPZl+D z(J8>wwJaddk;Hu1vW2SaSUbnA-Bj-+F%-FExnE#1YO(@wX70AeiCp@3ZrC1uqbi+S z3^qB4N`jpk<@K%>#uHyJg-LZW(F{VcgODN8B7|~XeM>2Q_s5Ekkf)0^q{A+QH0H>A zSWC3S>!pE0uUl(-F)2;x9@1-{9rri4 zl!bDc^J)H>6=5kF573IWcI_b@Y7s8hI4@HOABm&oH6I2kUDOGy;L91j6o=6E%V<=a zN}QmMRTtelxTem#E8VgAX1h;Cg8klW>X zjdqTzNFKcl9R_d?s^Ue9|3oQLx398038_6oP`g6s%gg8TD`{^$Umh3y6cir15mv!&fX>wGlJQL~@VVTr5r7FU$!eC? zWjTZw3U@S`h^W}Ogt{dy7?N2sY&zE8q!s5ER;%_qyoA3R9~;)jbvsr?$6Dwboj(TN zmv7ooe&WROsYsVCCpW*{z|)a9DwA))NI)x5e}f?9ZS#a9dg$L=qGWdur-{AP=E|2$AX6 z*3L;YoqZ))y1x6ft8fmcz|Eu5fmiLR|BtC|&$!VG>Rq|E03 zu9uC6B3k^EX|d|VOy+Kkths~tl!yBM>`nH${s~Hv;MR$S&;WvuvAyVeW8~V|a%+iv zBe0&WrUl)+%2Oncgt%V@c61!3C1MN+i4?LXu48Q&jMxrYu(sbdzVWp5{VNmlMJNNs zD^vri2eH-Dit^7`OO7{xg8S7EUB*L5E>%txh9FNCT=!fjfQ~giEN&f)W52jDOvS@Z zcLD2U-$A%MlYCKYN3C2-QB(TBSO&&06tnfXvq9Iy06cF6fHKp@i}pXhJ7>VI=zfu> z?kdrc)PqdD7k;#wF_yF4v7QhUx0r`>;^g4VYupMe47UgdHT@+A=IBnLgZW1=3d> zg0!ZVEK%$NGxL%<}(aK zXqMQAQ1hh%NgESaGL`1e6RH`}vU|3EKx+zN5TvPEi zfqT?AQ~__ug{{aGD8S6)a!lc{_(M)Fw+np36q5N51}dad!)#TGZ3D3{6icy5D0P97 zON9#KzGN>8sa8_86HWjKX`+@vSX2LpIZDCELx7tBF7G*?1C|vrg2K{7yx`0*c2qHc z4rje$!itkAEM*Zh*C*3Wkswo$%pZ<$hQw*zmaiCvP!s^Ng5V=<`FI z0m(wiPb*FtKReQS?4f?M1Cg}M10=zZj>Z*-HuKw)62)VplLEW&NSehjBXPh*`z85m zuWMGuU0ei+hJT2*L~V94pe)$H=#Q?C|5dGnGmxokS;xty(P1=N{y7V`3Dl`}%sV?1 z^nrCNU#7(|u~}1VP(Ba33?RX-WCPcV_-{d zs1-b)wzXIbpcQdJB{x>lTJT*0+JU)qe^%l%CZ#71CDZqd0uC=iKGh4Fs$6Vb3t^;Q zJ!?0Io#-A9Mc<8Hox@*30o7-*a@8WLHNsrL#p;}2lIJ-0b`(#0>a@AJN^~h9h6YrPI~+ zNt&@NT@~1$BVdeX$TbjGGRc}=dnUv!mO+2J8DDxj7D_SVRZ@an=3vgGgIdU55qfL| z20AFc(Asvvg9XkEXXoMH7+?|`{8H&IRGG07(jkDQFhkMac%N!s=Q0AEXIOxSF>?Hghq8%=@ zOV$4(Gk$EfzA6J@=%`c}?~thv`A1G=1+d^j*5g0! zV@3Jys5NLMkd0_)b>GtDoAA7WQcDe_7Nqj9$JrJn$rx2EyohNfVAsNQ{ioc(wsV*{ zoj=og`OQUZIJ|W3Rjc-s33j^C#ECZbT1dieI~I zx7PpGyr@^*-P>V1$*po-JhSRUL$?@_>Z*B58QL$E)W+_z&~Jpx*enybDbgq_xe=E> zXMUo;V5?c#-QB-g9VkW^Z*qMRZ2EN-0@TIg zd^cIz51q^rtFEJXXRroWP$IA>5`n$LS%@Z=TSmuqtK}1#&_#5^T4=;}HsTxyDP0f{ zBqchO8yR%juOFJR9h^w7m=~W%!&dIir0mv((^{|yqNr%kM+n&s5d^XX%M4Teb3a;z z4&7-)>qax`e@;CS%W?l%ck+FSDSNz+;d8Bpf=dN5SIF|%TVQg*ARfu=yBD6jVs3>!DgxTg69-J?rUVeiyupzV41^`&*a4Nc7gumXLG)^UaQ5?Vm zD__0M1$?5HIY6RueYuQDARY4Uv`t5Bdc!9#9PX8>jg1V?$Cg&pZXsoyQ2mKoS57XY zKZ2n6#+yPGMxOo9($IQntfuf!cxA|Ct(mcn*w-UM5CUJQCpw5lS|LCVuIr`%k7<4Q z>6o|*^W9$YK|*-9zx1f*uZdFcgRg=P~%W*<(9f1WBK9qU!0Cq}!r>AlaOiz6&N{6Vz`AuniJIz z>1XT6(}W|(+0BC(3YkMe7h(82->liH5z&88LO0S~2xV%pOlZBq0D+vxzAGK}ZC%@y z*qn-IRK8YiSOA0h=>HM4grj8h0Y(au^ghfHgQNDo>t@99hby}OwEoM3+Yg0mb2|Kw zAzd#iy>cg4F=~d=k*1)q9;q~k+7g|W?D7G34hc?hqrh%Ja|nC}X9g|4oq{6g%w4jy z^xt&OFU;?zCym?s?it3yhzMk4CIq&G+PnS_4=Px_zbfhhc?% zz2gm}Rbh!waSZAc@uO3rp}Tc8-GHdGowYMp&3Gu?Tom9jJ6n%tOT98emD%Kb=mTS2y`7yM88u1FM<&qALBA%>aNCTqY;GC+v}HHuDad{-B5@J^MwuLkCBI<} z7oncD4|f%K0MnXrD+N6tQ|3M1Y$pa8W_*hPdnYGeoyag?dcZ(bZ3l@1bKX8A z$QOfzrhgM$n%fsZ+9)o_bKSB+Q|qtYUg4cWnGVl2N}RRR`Znh}z^^6qvUrQ9cF%#u z4B31wSrf%!E>UcJT{JR!=0MT+NGY%*!Sm3Uq$z;Cgea2hv+i!^7kO$cbP*)?>qP$I z&a(1U`mq;ihyC%ZF*K01K)h(nhv+L75;F(bOC;pAt{hmRhC(Puh zW{9H2%4&r@O|&R04+4vD2~U*fjqx>ebZO)I7lLO!I5AUk@tEr|`bZ@B+D16u?PJD*q^dnZvf?TpPk;vWlTIgmY8t9iXM2_^Oa+(mQcRJiU8=O1gR>rON+r% zbWQm*Y0Z?u18Eut)S+#kvj-+8$M3Kf8(FVL?9e{Wd9`g^lHQkvel2|ZSa+fO&aNVq z2d3pIdX}-~3(51JhdRsawkj|e9oM<2RDB32tM)*ro>)$~+}#@T9R^WRB&*upT!dI? zTeoO-U%Rq!`L^iVgk4t4pg029US+d>XTqI?4G$j9~TuRy!siM3R4!-&t z>W4NuxT}LJOclYGDzi7?-5G)K9`@T>iH}< zsV49^Np`i<8i*6S&?%e*f7u@!vliXLhmFWUt;o{fB`gnZNK2zr#tAcG=j5EwT4CK* zFr6eP@=Ir_zO=h*LtnY@WQHpCq#vMdX7%gTq8e-ZFg~+@4X+Zm#%s04ry#p-k(JQg z7`{cslIq*ky64$#-ox)5*Lzu;eGU^QgZB$FnDS`Um#!oXSA+J=USPD`SE7=HA%1U_ zx&UWXA>sTW_9&zf`##EO6qg z2;r=26Lc!3&o;QtBbZ1|Zev#;lA#1ajel(w;`QwlbBjC|JZLZKjqE2;@EkIor0hzi zWiFDk&_?6?0&0K=D)i!DsZ#Rw=KWG>T(zi8K4!?BOK=D*?>PE7wI!{dph6ZZez`&V zyGT;ho$W{%H~p8_w?sL3LFty8-8d$^d=UF^m=_;XfBn>n5mPBT7WH~F?9!mlv*Du~ z*Q+l{(V7$I17~h~_@ThLoL8_z^BQdf?uIAKD+6!BufWd}0%x;sV;+2-EsHc>&epQ6 zkB3CVQGU*sPi-}#ryDWs7}yzT{kEa^J_2g!C(18+UVC~^u-soqMkok|J!8lfwnQHm zs9F>_km;vDj19;qhdgtJG>4j;lt?fuGM|rH2uUdoBt2+t1VIxrM9%f_h*x0vNO-EM z*FFbCf%R{1$yF|reRgXu<06*MU@lIHM=FHm%^f`OKXY&8+_}1aNXZ0>o9zWpN?N)2~+GXL~W9jH-6qqA7ojImQ_V z-aDeJa|vB}yWd^cjf;||0Q37(V>{?a2ShrNC^^MBB7C3~^7kPZ2$scTnU%e8u92NO zdD8kpdd$gw~G&Fi3a<44}X`Bq+U*=YS%T*P@YUe^D>m+;Nd7drP+q>1FV&^ zn2v&I-do`%1l}Llo)cH3ACtloC;~z?uTpd_2}FH*O454L>DUA}!t@UtcW}QE2URVC z)$0a>MTG5PA`G$}_$gO~FzT5R;smHg|Cnq>s@ST>pBd42fi9rNcE=@=af}!s0(@W= z(Th+OxP+uCOzXDF>+_H_2BEQScbG4+T^C*WpN)+Tb4l$rklEVm2{CeK_zv8cz4?a| zL8_lQX*fenc2Nx$K0vh2JFn-)zy^r>)a$X-O>RyckJ(GboYhVO4*HJ= zo>ZveUdy7z$}OauY7HgxlX%tD;)6usiV7Q8oxZOmMA=4LZhGK%bd=NPFsd`8U#q>mNP6Vw#*Pwk^X4vl=r zkVo9d%#HXp$4dT%Z8s(}jjl~AT%x|6cWbB?6q+^@(YJ+Cm60BWIb0Nh7-(G1&xzig zK8+#-a$1*(0;q(62{0{b%MwOy4MD!`L*$fV)G2qu7v-HnP#WM|gUcbC*pFw*`Ve<6 zl4`wHd6~kPPx^~{#8;uSH1?hS@ZEDoNwcS+0YD>j4WXh^C}$>s9^aFLF+UOwo^NRerNHV8 zP~Ql+uA!lUSPoG53YRNK04<_;lthp_}kv(d+)qYl|0U0Tn3`L8bCQd61snV8ptHP z|C@fV_-6VBF#9h|Ru}hI`ICD5qmB>YMj!qHpw#Ttf1{R-4N5?p8K9=TrzW^6Dg#+y zcXxSu0xln_+4=V>0(tzKUnQS*eDvv0`WHW}8T!5sbI=XV|Hk-(9mFXWz%xCADp2S5 z(-yAz<7$b&y>z3GUVL{N<=E=$&abJj^t(q**_#`C?vL~Fj^+<%oQANnl!$KRevkIO zjKCE&&1*)u;1c^o)@YVf%Z*YIQQ zEl=XlUz3RF6>nF6U85JUx4x+XNTaXO5xBR(;o}>>gRE9g&diPOul?6O_3!x4CMhE$ zJOgs@GO-8JK3>&ITB4)Q<3I+KWoSA%folkf`u*|0X)qm^#r)#3!(aBkSPa1&ZlniS zf4cvdjr3<}1`dXGm0(eX-W*d{gIk{w+d~ia+Q=m!fltRpZaeEyHLz?&I zCMd+rH)HIJM5w*_#(bWBLw=R7(ZgU|#S89Nn80NfKVzo*NA{E$!=yyBhID_up{2-R zy>uGk76=7l8Sa9#KkwNvJ#f&DsP_w8;Z86@F2JV=R9LJ185<1{@I+QvvcfEj$tiN$u7(Iws$(jcV~g*dR`ozzaahW?(IJHqraUA@uoUd#^Nt;j~Rd)+)^K^pC`nYHZe{{i?{4^{3;WxMacyel|s)XuJS!XP#=|qu5nr+Ki7SB(J;_7yMLHkz5(EaFoxy@UZ9GCFlottZ#aZ@P zhY|0!bvPTA1G&2I4N9lp>1s{8j)4i?K+wB^o+5@D`7Ih6v}*M9?MnvQVfAw8Sj%Az zXc=PEY;IV})@HG#97LJzAX#wcM=tXr2I}FV%h>jEOE%ag<%j*7Q4#f_HDAwn&IhU% zJt8yr5Ddn3LJUAdqwDd4A_g{*k3BU5RVBb?*almM(G1H{g+eseF#Y86SNglU_e;+r zt$uGlmedVMydI?+vb9LkSYjF&46z9BW>?uWTPK~*+@)=Pa5&U>)J;-Oi*y-8db;!27`}!p-;H`}&DB!SKSFz+w(_&9CE)_9}nz*Vfgy`F5DQ zbm1>|`CE;w)rA?~FCX2+%jEdXGznRF|x{)(+Yo)oh6-LRMh(tcfzeEi~QWS`zF2fHFM zNBn7~tn_)nXwet(zo~9F*IzfTU2=~NyaZsQdrzjLhc ztktF7$a`P#zkbQ0ov3jfCuG8(&tQ(smd_vcpIs<4l3jV`$V-Qn)cK*`CHHz>xpbCJ zqYyH+o|-0?9(W>{F7oEU@ z0x-E~xUoS)uTldv^Sw#A#zRY-C+CnnVitwt@?NR~UU}}6u4=ifk+T2@pbC-ZCNFt5 zc2!7K_(H|O<1))iHD^%h-d0MpI^Kl2g~vEP2n5IN71za(P0(d8zdYGGVR%*W51~LB z^a?Z)*g7?&G44ANHk;7+7Z`a zCctstKZgasNPFJKNThj_E8|iAJ{b+sx%eb;rs*5RT?c$Ou&3ZsM|*ZQxBl z#NNhUisb2eUXh$w9vol;DyD@7c;RF@Y&p)aPV2pWlX!PZ2cwuScg&P$u0MRipco8K z#7>Sla4JI?`&&JmZKG3M*(smo61V&fg`bW=%IgN(Mv$pBBRs=8)jQbcT@y|K2zsh+d4Bk)71Z90*FS z>Hp;|Y}L({K}h;#o?0$0(!Z&b!c%;i+9@Qy9M;Nu?8=xY@?OVB5Q9M6eV$loSLlzc zloXb81*72^X1KYfR=%@YO%STs$JK2n_yQRsSVYhGM<{kPkZEUcWn%lPS7Bcp>RpJSbMEZf^)aSI3>vCzSo^AOi%8N0rpcq1?P*zRpME}Mt#+f4 zvuXKadklZAtBv49(2A4kAGjWtr^R~soYBrIhxsuXESkEVFKpb(eA4RQ$gH8fXhuF~ zodub`ZZ|5Z(PEEYplH9S?$G$Aw<6m|*bN8&R~gK(U!4jPmMDl3*$a8e*rFFS5jkH( z1=z!w~AsnHyZ!o;$v|_#WkoBb*3>*gZ>KJtYL}P%;g4wH~h%P zaj+muJIZlWr_5aThkiKaS^IpuNmjqM-fIk9FfCy7cCj8%uW?qB3rFTqHIjvt0<>p6 z-Syo0b!oF}47uUWKK{`+?1<%(jsmP-^-M!Lp&-kLxq+0+a3s-XT{wk7=BhWj@8H>; zWYxBNlrx^Wo9zy>zch*SQ2No!tn#Q#&8>hX3h~r~GESPvuBT>QbZ;Dd zudyhQ4lI(2T~z^4`2;U6VM!DCnTgcT_9TT&Z-22U9s@fmZpNBEpzge?s*J!zgX@l9KKlf_Mwh>rL#8=@^BP^sUbS>vd{+X@H z2gx27{Zy4$h6&wsR5NeyOiJh?7epMf`$kroZllB9b+6QhHwn}aqba7*Fx&4LO5m3+a#^D< zAia5aoOA~6?fd1293sxx%;hEyIYMS)g>jW6Cw24KJ*&hWBSqwb^6TbDFV9Q!rN$hVW zD65$rI0FKqw0IvJP}l8}+}7xZ_TzmNFp%`ae>N4VZ{G)L->m@UQq`y0MKpFB03X+b zk-87fATsI5)9tfLP+y(wec98T($b+v*Dd6fvSy5%Vr;YC8uG2OYi0vyTiJ#pZqGNY zducCO8=$pT}<0FnN=sc=Okt~c!gabHmdL5H1}xArH^nl|Zs_0V=cnv5BR zt^LjX`i#esxXq{CPHBCTus~l+%1K0~`lVxVPMOFt{mEL*PCsoy`X_E2vuX0IBYbUO zaR7|N_tOYWHi0bRNGaXnFTx$kp*Ycr2F-}VcNtwnV->++{Mz8BespM7#k2#0?V?Ua zIbzTP)iW()JFd_hW-!;(8Vp&SEx)lv2QU-;BXZ*A3I`AR`6aoefxqC?E9IxWP>1%oD(-h^(M%AV3s4+I1Y<;#Pm%IPw+n=Ry-V&S= z{JSQyGXr0cxk(jX3#rljm_}`riO0=bXp#ZhcOZL@Ugo=Q+t&mXI|L`{#>&!cqFwt| zputbWbo4_U`M)6F+Wjs|$4H@>-Xa5#wNV03ARTjF-2Am)M{l6(!)dQ21+SGc7q?6D zB80#vJ1+|CQqdsFa$8t0GCl}DfnCeO@WUC#ec(t-va(Jtm37cg2h?hR@tH9AWt4p~ zE6`LIPc~e$Ux^u@5wb0u@c*0)QT3}rFHz(u6m?V3;&B%?=*rZ1rTgHYqh9@rx2D6n@2!tnW^edDN!V_)xZ-(# zzkIwdgKVl3s0*d-!HF<(ra(`^^ruSFYdkEV)u?#s1_;2M&&83x@d+)nto$Bl+-;Q< zu3fu%YWycrYJ0uK&Th%R2$X~|?bj@@`n17A50EDV9F&LwpJPvh?jWke^HyhXst0d~ zTzehg$=&6csbbsY}y?B$7uVJvD40TCfX z){%J!@5Gs1CvYiX*K2KczpbZAr?H^o-Q4O3EYwB=HCY=?fp4^1j0AH?{(;$^zT(tL zcc*=A9C0E-TeKl&chtg^Ewp9Q-J>0^0w_8o)|_(Bf+_8XbGFF*`(3?ST`w9`w`W-l zqG>9z);05DbKOb{ZA8>6-f#xRC*0k+c5YmO0xD@ItV);^db-NMJq`2Z`4${8CWNjl ziBY{*QO!eGD{sV8eQ2&7&^;`Crh~V1_r}6ojRRW=QX+5y^4;vQ1bTU7z7?kveQ~Bi z?K_|3)$^)sNa<}=tYHYkOI`T7oHrzELB3mh3&K>(rQiWT#LZ0L3)v+8=qJRYHuQu% zfWWWP=kc=fse5+)OEVa4W}O<5VY{uSHA(9`rFRJSL0lvd{EDTc%ZZk(=X4mkDpBlT z(*$iEvao57K4zBKDC`k*Ze$9(*R4~v*p+ly84locy}97kDBaUp0kUcMkKmrm;VUz2 z;6LB}IlCN6pp1RSPBhy8c(+a@#DdP`YlBu5IgjM>r359dMkamVP)cd#bgo0I@AK>% zeLN6R(5YU^%Wa-aFYunZUnKgSa(pb$pkH({cxy8pRXBEB%>GH@cfV~jTmjnzRUqjm zasQKYR(MA8{R*yxv#@e5+K8ZO zm?J^|U;)l6(bQv6w2wF*K${PZs}M$DYPU2;@P|~3w*H>)GL=XQ4mcDCf>G>aAJze} zIuf7Z_w}0OMTTPUglI@l?YmIYyH z_WC;Qaz}UAs-qEzz18C zFJE({-CYPZ;qzj5GPIK*8E8ESh3;>rnF9&sy;zpPh&Kr>J5M&iDY_DFM0uke_>$)g z(8joXaK8inxmIqN_i_w={Cw?Fzw!tAs`HMLb_Qc_ZS)Tj0SSD4LK`|&_v%xh69-Pz zNWCn&45U{}f`oi$#crKiTf2$a3#7?}%iPP&0yhWJc}DA6v3&XxL4xbO30kIG@uf;{ z{e(7Zv!sn1f4s&0F`FeZp5MRoa^q(KM@LK-bbWzM=b7)|h}7uI1W&S7V(OE_f+BA9 zZ>s%H3S4Gt9|YSidavx-3!>d$=lAWWS$f*GHR}mB0*F018;@)qit?B!5hG;yW5^x5 z5Woswf8R-7V9Z4%-Y9Hzp)7l)k?}lnkZ5+Gc8k?J^%xmJX_*IikSN7vX{XPZowN!a zt>JZAJ|B5fA_RAZBjF63IQ_guqo=2(XY`9_?Kg(#V0-|(-Yu%*CySVFru+JTFRUp{ zX4SBh7{XE=jv!=#mM|o?R(3stRJxE>aXxBrtzu&??DuBh9Awf^`xz)=LwYt{MZgew zat9-xqTA;VZb&F3RilBaTyh?X)E(@1>9vzQ6VTeAKHH0%tNVb+hI;-LP~{M8!gtRg zGv1|rc^8Rd3#m?hraO>);7ez?PG%KAd5KXqGAllf@Dh{0iRYE{c6NzU)ZD6K{4oul zD<|*XS&9DT<*N`L<*;BcFZ8chqN?sQW3Y6ekrgHp`wRPLzpd5&=gULsjYI~+(AB{EH|G`JkevZ^KyfupHjo2W|RHrf$~uoE-SrJW~~)^NJEO^~)D zYWthwGZdFlx9Xtg=Fv;E@(5)GPuuzHA6gxc8blQ?kxcKhD)TzeBJ-dejD)%y4M~KN zFrEB8;_G!QRMZ)=6z#!_?9G+bA3n}BPLd+^h{wI50!H+IS~TkfX#NUp5Qe4smM7w? zBBQQXYlcG7@(3&Dcg<{yp5{Z8aYr_|Wh-vDi6IZiHaUwx;v|t}lP^tWV8eth0=f>; zGHNrQp7eytl1QbWF4VZC!4!F}X#=5H4arf<(cWKuA@2LVccQv#u_%dQr@>p(pGEVu zjYDVJQIbmtyfOYLFBdczEiuw6=^5KO{Q|_}DkyN1MfMlrsmUgL-ER=CWzYdj34^Dy*))Hb9JY3)xC-UOo*YM1KeBi;+HU zitIi(#}wVYF$sd}%X8*!sR|9@m^I@2#PXy|5#+%1q?7<4jP$bp3-GIwVMg~(KupsMr0vrLzP}7e`rCk>jNfJVy_o^kOCp?Ehm};yecxQbAj!GQZ zb;^mV{zy}=|ho6|58+-8`n{o<37-N~mP9ToUnfjl? z&k<)5&?30BkqMZXE2+yNAxw^!=BR~W`Z@^FwMG8MRiPR2!6=J)Y*M4-7R{#LP)X>y z^$GaiY&6RZb*q-3u8<|UQz^Uh_WQotCatYV&b+x%0^-vbs$%p+e!bGTY2{uzTT`*e zg?C)ErKmsBTW1X?n(*g(O0t1wm441eYN5C9f+x1(&Ad;srqsLq;{W6$hh>;1_?*0@ZNb24GGf&W^eFiPH3xB*NnIq z$pQ+U?0lzSw`{}#k0hYUMW`Q|jB-!K0b~1HLhQr*QJ-rP5YVCtl%U#E<4L`_)#i#l zl!Vx!#y-KlmvgJ*TK}%}ZXhChBl(dzKbDMZaRPqzulAu5cTl7{7kYq-(+yzy1i}xq_IBicQN{{WCJ^f-h!k!Aa zO;z#Ckhb80bKkL{2Z_Scx?4r|NBFE2vX^{_xiQ9iMX`cc%gY&gX3GD->_T0 zpL4av^XfqV;)dKI#<7mF_tkq5uRloNHZ}t>zS%p+8ko{&+c&^|ow;>?Cby=8n&|aW zooSFfArK3AIx$o+ihfJ{_4mIa^R*K$tovYcnN0lB;6FW53M?qJ#@iqqJ zCz~GNOK?91ck2IY$deY!k_zI8I%lhZTAz-W4=A53(Bm5O0O6|7oMQ<>RqCEowQ z?5)BZnK``Hl%}Kbqz8=9sO95(aTR&QWDcmS_(nkJ;d2FFjU*RV+3BNTxCc@3>{+<5 zOWl)GmbC}B44@f%!oe7ONS>$5YX_Vw@Gsw@u$s+SWQiHLBc&P(1psvHOIO71|8wai z72NrtLP4!B3|6S_0`t7U-_P};DJU=C#0f6en%=V84y^5LFm`i2*Z9tRww~ZTND<+% zb+3|p`yg>wfAkG4zNe*@8g)x@49wbG1-g!?qfXQ2`MZ;S@5j}3dTli7Qo?EtwJOZj z9SSobFb}OJa}jqM31voBjgNMk$3yJ-;Gay}Cu`V2%7bncJ@=P2t3MnVz(4)KAs(w7 z#pXTm_8AGgwI_R!l+`NvTDM38#)FgVc?I@v*l+(jvp2>?ws_qOVvq02LwQCWJphfL zb=47K4-q(#d?`(vuOWJy`1_|9B(#S?7tT|Kh50^@C8?2XGpuo5j=a1a%Mk@z0n*VK zIcsv;@L&c2AU)x?_6epjBWt+}4^U0IQjDk(ko=x*7?Xo?XS6})n=AK?GjE!^3G$3s z|5!!7fXZtZs@31zezt_an2@WY_KL1q7|(m4m2dmPmX9C1xCDjA_8Y`Jw2M4zp0-`2 zDl74{UtHelE_PKmE8$F(rxs_{2htxk$0&AIpf*;zjJFlkxkMeHLvka{jI)+}yde za^|b^8JA#4T05hv04g-kqjm$B0hy2Xqbed^Uo=pAeLz_#-~##KGv6U#!T78iSNh`? zyKzFS8k_=AQwm?J&f;s`oe+sjD#Q9Rtwf$eEBQ=(zI7V&6M6?}c^UBcv8L2D@xW>? zv||J++V)Js1eplC0EG9!4u3edyzoxq~dJv;V z-<4qk%Hs)&Qk{3V(t1;d;ag<=j^*zab7%aJ1Zu3Ay#qp}dvC{4c;z)t{@bDOV31)o zA~me>_iwPzWnwSls^Wj-YN5Tfk45U^JMjWjuP6EmQIFeP3mY;c0j$>M*GiEd8c59L z^-6*Szt~|Vss1P^-Z&EW>?z3D?S(C|22N-$7Wumr86*2jD8@Ack ze#mH;7YHZzE2>ZjL&@cS<1SG2w_$c-Y&+R3SWjwtNPSzBL@k_Nq%;KsS>~Vwwatn3 z6xe`uSB?M8E;Q8?3YS-j8g}I^2$$mkOckSH3@J)SJuO0GnA>#w?49nhGxSPxj&`<~ z@3KERv*vH{d}eqQ*n6%Cz${W}*3RF?!fA0>#oMmL>+G{mYfX!1@%wycw4nQK-$tjT zsPqq6n;OpDPOC`!8m0!~*yoJxguK3bd@Y?8sY+dfC^stNiUCmU@4Zk7H?HH9w+CRWde@7L9t5yhk z_7P>O!}=Ucf|;)%SQNkCSe31okr$-^!boEnzI}fKOmw$ULL6tWnU`JgP1=rG7d4K0 zFEAILM=#sw`r|4xqh|heYmRBX1$-wcS)L6*RYU}ri5g|{*`0iHRX9aWx`JS#-WsTt zCq;SXXd~4aMa(;yFY{}W^m~OX$(pS8LmXE^)l)fw!%JN`$Xjp2#{Y-~y1qd%2Bt5#hXU8;pNXZm5!jGxeArVLPM3Ro8OR3rWf1V;fV0+DV?C2+kVR-Vq zR=Ikq0^sMklkJZ<^HhD+F@>h!&?L8FtXfpt9M0zf#S{K?=T3X(`s zHCu^9Ghb;D^NKb5)3G$UF8oBK7so!CQ&yk+A0d>~*$gR4 zE;t}Ohkk(KV97|uF!nf<|kaITlY?bfsHC9KM z+MD@~&Lov*TN*;;9or!|A@w>r_DX4+w!l78EP}_#??@9tt@rRfePU63=wTTQnSoDz z;g9~N0=8HpUxKQWuJ;2n-oyWZx+jAsm(C+Sw7vricytKgL90nJm$IoqPX6g1@s}@M z0W)yH!S`oNMxv)PU0ws}tIqcY(TG=ji=0M=lA}Mq8F0D_;y#82Dk0eHzQ$jF zIyd}orRJX5fLRI%5d?DoXpKk2SIR^$qQh&zK#7o@IU+3GO3|2~OROWj8&+UCK^pk! zHoLRD!eMwnb$%F!r5+R%Wq~MGLOhl#ulZ3_5L3@;b1 zCy%fQfmgHtQW3<7RhR&*`n%R?j+_d&<$|AE_S^Pu%PtGjHNJd%N)a?;2}BI+Kv^3U zOy8kVc(z8)3XUAM&vX3KN`ws7@T;*xZ!eDUscH^F>CVLI*?bZF0q&3h2t<*7TTBxa&!5$ce`=Iu+x(k6W4h zM8A}P)kXjxKnUspj3Z6?H9afe`|t*WEorYwvM$X03(1PWrf6T%mG)4R$09Z}|K{+^ zp;!UP#VN73I6;7!C9F&8uDFf{V{($E1-?TFn|~S|p~n5&NB=xrJiZKwsnYVQQr=}5 z&+L*1Z^7IgK$h&|fHC*7wa3A>fa5K3GhmJGCiw4D7V_`36|q}egepgZdJKI~{vAq= z5^-({R0;>E8iwF*#to7?$;2GD`n%MNmdLhu>CRRD-}*5J|2RdvM;?p-_##RkfD?6^ zPVO)1qhR)q;p7%N64>Tp`CgW`I+XuckXm_{L5;{JsfEyRiYv!a2GDKI3Z&Ock9x9w_ zPSIq8C#GCA=-L^Lmx4oAS$j{8ZV(Z5CBbykLUa67$e zH0AY0J4DU6Zmc2kq}g(FF;0FTMS3Seic~7MG(9<$f5mY4ya3?m=7x5tmvu}}Y?$T( zmII)6Qq-{XmWZ`sw5i=oAsH%C24fuMwUW|XQieLrLl*aw!s?fiq$cDuPK}zj zFb_?uF{d*^hEh7Px7LlBbyV3 z!$B&tzZhUc@tA|OifKib3tpPN!UNO^=G^>?3rKD^s)VtcrJ*{ij)J(~hS3{CCBzz1 zzbJJ5TfQ{_rokX({8`jeM|5u znXFCngfw1&*O`%4ij=w)pXpWr*29{J7)O)A(T%cDu&W`19osyuL}pwscDQOoCL?A-YNLzT$ z+8ue6rd&FHX@7A^q1_-acBCxOAv%#1pyd2h6S*-{eHKId!;3I6N)q1u_uLYi*q+hQ zf0?GC)k3CMthP!e`LK_(POtM0yMw~UClH-=FqtmfZJ);lcHgPP))+)@Vvu>8lu4(l zRa}4h;#W`HK9N?>IJ)%fi>p$h+s&cgp{)7bf49O8i{Qfdc!V?Y_gTMRpnBedB&+34 z)@?+T0rNdLPeOn6s?_{kv;E7ZwP8PKXx0=zI_LWfrm-;-XPsAw|>^wshWgXhA20+YMXCe zqyDlHvTm)pt9C0{E?Rb#w=|vst2bfe2QB#gE)|LhEsyBNe?CcvsL^7NJplvtZERP) zU2PS|^7HH2E69g90&+y9#jeDmQhx2;H@7+tYvGq=3-(;DiDBbXOhQGsx{&!22=Ihl z7r0X03~%2dsN5%dt7ce-t(09x7T80E<>523osr-iSYZIDTqY_B4CIRB<1*{CbH?nN zDx?~@g4Y5&W{h1#128%7WLHNe7Y9`Y{^)G2O;)Ue{H>VugED0Jn(_&BZ?%4T?)rH1 z^>_sdo#uN|s!Hgb#FsJiY?)-yEw<#2XoRa$1RQ;7QobZ#=?j4W*QCqv#mhR+G>S_h zt$x3NGOmJ9F*QSNof#@*;nVQ24Yv?b4;WlNXB1+~gq`?rwnP?$$q=$7^0iFj1{}87 z^sxA!AO+~Hk_B=lXvZ$GKQIx&BwQjf;zm{>JE^1fc_%B%d3ZEI?CQNDL&GA}eOv^;{Kil(MzWp-`=#yZzF z8XphIk%QN#yS^5K)0gW2z9^*tGFOEJLS+reNKAwdgCnxL-9I<8b~pgZXDj{Sgi>l^ zW@~6}aRn*g*jn$>#?b}x+}Yj++sW2H&(V87|D{&pUZDxQb>;Et>&rclr_xCNq zgr)vs7yL%O-%0_e|Lp0k&W}tig67Xi{nlX{f33alNxl9y{QYixy(=~Sfh;pMw)n4m z@9YS~)xqWWE9e}npOYA)ug6XwtpA5^OS(`M)C#dlBB^(X1 zuu+XV|Gq+DhwzG13YS3K zpXr{W_fTpAg+u;J{FsNESNjAkGTBH(Sy0r6QSxvV_W@Q^lWdGoht~hV7)3nXy(7L} z)(;b*GYga+k-8?}v-@86!HH)$;}VRCcCzNR;ry8!d6=tTnU>;-hAQXkYtcgn%7NLs z(;9cJWjoPoD_3SxIig8ARvN+lcnGBAC&JycBPW%dWt-TjLNvGR8YT5I{}Ypphg##S zI08fj!lPW5C`JPwqLby15Rv$x7j>TM7+Q1c9{GP1LGNg{(#O9r^+yMrZj?aX=#=X7 zb=ND*YQ~Q`pq{vkrho#>1{f^`?+yIXdQ#Bwbya;msqe^*Q5oiHVMgLwfqf5KrjG&5 z6KQlIfoVZkuG)5`_~6aeI<7@QI;iGj(KdV`;%3CO7IzI$`1D5xY{nG^njX*ZO6@kU^{&Xw@SV5 z5zveFk@;+?!G7rd(QW8$Yjv*BK8oZ~Py-;?d{Xgs7njbIuY9>qRA!*MwmJ6i{5lu2 zgi;j#rLEjwiwoec4Z(cpCpN*9i*~pC&}lJ`6Hm&ZR!Qh& z{ZQSc{Q_fk)9@UXxYVH&=eBa`urr;2-VD#Ey-}mnXQs$2e__~Sv*S&FnySosD8G%o z#SrP2H!$d)VvZmuf>}$E27w&=@)Hy9V_%1bww2t@Gp1-|rFwTpP>W5FjYDJXj!(WC zBO9HXbZ?m|OMWa!lQfYL1%^xIg@F3kYEDMEi zM&r3CV-@iWR#(43w&g1_n(Df}#X5RKfM*&FDjY;Z%W$dXNUFa_OB3__@-mBpugt#? zkFM~Fsx3*73N;(*9@*f7!6d|YXuZHRkW@8f4Cm37GugV2%e2u?JIMc)D-LVVn?;x6i=b{%5kuv%~HaP zi{tPpYBis}K%u}NGw`iA8 zi$U{n=i>a`xbl(SsnVxgX%J%{g8hU*g(PJKnrJz3h$}SDuLf!IRVhOZbd&c1h(C6z zgs3n4FY>B3pcYd2sajfWtb~A(-6Zi0!+{Ei$#`wV>_pPChDLrY%NLUvRC z&}fIyt3&|)8GIj^@rYEF5uXHX0_BARs6(F@?k!UGRBP7E+!)T3Tf{M6Y88Ud47L>H zr4jRBrlXxf3BbY&M2!}<7Y^WdivJ8eaBDipvTz>|SgxE%BvISRtUhh^_lwG%i*Qhr zp3BwnCiDs#Rt-*MXGn56gov-cAlm~m+C7$t&*OtpXAwe4Pf2pT+0A1E?&?7K8#V-6 z4C6=U?{s*zoB&Bq$o+8WlXi6G*P(NJ7&*K+M1#-c{0^E({%g~^NF0802JW%iy6eff zRf_e>`xOBFJj2V-8u=}wjqf$T(N44A9^CISVbOM!fy*_BkGiis-gv16jTd9VQQ9xW za(vsH$|EBYa6V*2pWaaITT55^Sg9MnEdi%&DDF`zf#Z6$^>3dU$)^T(A9=6UrdLdHaP7fVApKNwac& zoewy3#K!xwuH+o*)S1OD=>Y()NX>f&bp$SIjaC2M8YS>jt8dAG=JjJf=tdcQuZ3yY zP~Z*8XYh4!K6v1%I0}?ph5KC5lYNzFLTE$^G#xs)$PvwNycrCiKydcdVlhrB!1%L; zI;d&uou)&CKvr2c@hg&Z5{}NHE3w96=Kl4e6&X_$uDp~36d8PPATsC>cstJzfpe@7 za8<05Fz!MC$k`Ug9GE}71*=+0!F)CsgQe_-fb)BK&5|H4CZ4-}5p#_aQS}P?SGNs? z@5}g~ z@=qSx!(hHgLMAR*>D0-|ZT&!XjG1R6aEMFAVd2obQd?kSSk&q)66|C6o`!-BuW}H` z2iavev9Poj4pc&L3J$fG^n$c4Y*B^LT2dPQq|H9U8P56;RP8eBs;v_Tgmg<Ez3bQOUS#FxWNXA@O_vnAcmM9pa*>n1=$YsF zYAhwLD!`6YX#y%6ptv5>Q{RTGu0tYT5^cN&T!5jYPIc*@N#{y@qwUP9Es)wIp?Lw@ z$E7=YrSweSnx%9$zzs7!ak;oN{|U~(sfl}|r(V{`?YUCnT6>zVhTsj#ovOWtt^(5e zhO&pN!G%!;5{n6~-{uZW?p*a2NL~~m6o_&1JSTf77D3I!1>2464&2$j({x?TqMG)b z)DD85ZZ+#CmymU~fc~)!jn64=G@Qi4EZfxSw3c=ivYm@8&TKgCfT=@;0xWK2MC0g7dc`lthPKMkN91L<*-KB~ zA{faI9;?z*lIu0Xbm;83Srr6NjbeInd#AQo1lmMs;YfKk{IErM%@| zq|n7GRWP565IOt)iJBHPVci#p$Ege#^#ZUU?X%gSo0!N0=W_~W2CRG{D5={QBJ>2r z1lj-$qru)zV#B_pmg%e&1k+?X6i1eM9m(QUMKE95a7(U;;3cB$(ri;y(&_8$c*qbD zXiC~9>Gf=R*~SxiF%(MXKM%CkTC`iam?`>>7LL-oAIG6*@UGZxvsgr|T9w^T_7-`7 z@jHrt=hwn&F!}RrR7u!W%{NlqCmQdw6FrnITDlT!%o#rFcVKfV^Y7Tdcc+D2=5ZEI%=G@bywZ6kC-a99;fX1!?>uv(6tF6#aW!8LTtmXZ@$$WZN zDoLGcr}^urWJ#5w5kF%j1*vgR)W13oJ%>i*Zuxg67M65GMx#a`*(e^G8YYNUVO^79 z>(6A_^8K{I2VGtu#0_PC%*sHX{3~Q>j=KW{&-d^@V)WRS2docj0@lb?laXYB^b8P&_IZcgG zF~+0{$QkmV2N4X;IqZTg&X}DqK>OD8{JtPNC{j?efSp9p$BkRk@PMa-G3GYeV5X(z zcPZ(0b*)^#N{syj%Fm@Yz*_H(Q8irgmm6h`k4gypT(%4$8%}{pEBmgw5%ea79W03D zgH_^fVidkw3Bh(nNRSM!1PSs0DQ!TxH=4)sm%Kc$d#UL^&Uel%rSrE#YFVxCbouW~;RCc{hAs0*i=a!OCQnZ{8n6wCX* zJsBHQSVg;wT~We^o3z12J-P_{cAxIc{w@rPi;mhjqcFjPbgn!~;lGL{Kxl0B22L_4 z-4V|-8PK0%ZV)$|pg#_pJwvXr=nj2`s+I%+Ig+25+c_FhVhsl#VSYI^w3~o;3Gp7h z4TG=ddoTri(uv2d4xthf{jcs|`YEq~*$_Q)yfG(t61g=R+tTu8HgesWCQV65rt^RxArH9obK8p}uq~06wQ-YWIq&H{Wk#`Wr4RQC(bX z71U-#26?M!RN~MvKee`?9@hMojL#4oFN^nsr)_QUh1!&&*7o*wBr;b!gEche1#tde z`NkKo*XsGuSY-KbS~_YjrlLKAQ7X7a+eyr%xrxo^*dkD=?w{ar`KfpL%9P?OM+K<@ zE=Mu7q6QX7bWCayc=&BV#P5}>jMA5}E@}Q5a{oegAk;n zMO_0b>(KPYc%|9i%b(xUOZCV%h!zrWfbF4)M+m5j-Bg|%fS4eDXy6JG>5Ax=^xawb28Gu_?UrKX6G{ddfz%T?0||p}V8Ld!aF1-hF5>iI2D%TyyJ?vIDdK zyKdmT+dXFldH|qIJq4xq1e4*fy8#|Wr8W`9=(Ty{Y9`9|_Es23^d`u(t5r!wjgmlb z>|U7>&U~|m388lw+Q8^133PX2z-pjCClgjWesrsQQ_F=&Dvg(+p!;Lt9Ct+W8N)rz z73^Rzv2UQSv)bj|_izOY>L{trG2)NeQH{l0)LH}$OscgZ#6wajmhq5x+6~Dv@t9ky&)rmca}OsRPuUdH8heyzlEl*A+))9c3*2UFrhl$ z!yp34eBdA|wK7{a8@qRj8aV~pQ9;VciAXjyRL{!0mXuk91+N5*5(rs75(?Iz;?}JzqCoA!$8#^)etZBJIefFN`Q=>ZNDzb zBLxA_K@3dANrKA4>~zH8rBS_q}#XfgBtwjA*Fx^Z2*K#UEB>Ixa=Xoo7M_VZkRv0D-q z3Rbhvpkkr5IX{)%VINMjQY!~HO*W|$3|pOt^%Ltn9+SBt^4tB3#ClduJr+Wm;|uQ5 zcCZ#&=Sl(mXnk(r|GZbQq~-o3uoL{>c||=C8tsXl93A#X=aqSStWscuo|h6zew>VC z#UK(cp(boI?|K;9oBL82$4&usoeq4tJB*3o$P{J%4L$5Xn9!)OfOjoO#EQDM@f zPMg8L@HsQS{+)w7S}YTnLIxUCxF~$AJxeDQ4N{yz0@6h$RoFoJ#P{!);Pvg~0;m6q zt%US4I&bAE{Jz{;4`^tdI`Fe&95i1gJ0de@Y>BPOPrgYqFJr+ZNRy&c?$)P#EhZzu zPi-dnH;L2MvfUZS*VR_+pXpv<*_LN;mhr>h0Po|is2|6xDrGA{N*4&x$z@NNIZsJ& zoo9-^Y4=HUTrwY>YJ#6BNpj4+LF5nJW}fP93-sL>;ta{#tZk^H_5We)9%6;z!EFI= z+qP}nw!UrKwr$(CZQHhO+qnOopX8irhfSI^Z&#l+O%qY%yf{{5eVn6OzG?kHm7s_~ z#Wa~?*Tn+Z`<~fSM=sRroYROn#n&+Kz>@N5r?Llp9UzON?5=hqE?N9dt18b9-vmAOqlD}0b zagG|TX1)wfnqNcLieFg2~$t-R|7nhE#OzArdjqpO?eUt2hTMTtwFVI}AW!XT5l z3E1P_FhCQ6G-}iXmv-1b=R#Z&o}BpU>dfRDk_` zLLOm^{{hvCvAZ(T(6P+sK`6nC=Mf4gL$HVmxe@hX>?ROCfDv&nXNYTE3n!DgPR;gj z2ezjAN`(5GnS90K`$3AJ11WHA(wX-)O9={n`b%p?!%RgJ}eVkDpZS%lyoCN-h)sN`<|exS*_Vf1-%7)&TxtR}VnWfHx*W&upaiGyd8@3NwoF z{YJ}e?j_}O&-s7KGfd-PBJUH!5Smpn+)U0*`$iZZPa*VZ5@{6J<%&FsYC#@*4$Q*Y z*ke`*nG23phaT!vRRpa+q}%*%%X*K#%mA1&D$0QDU5`4@Lo@^}x|CK@>auI1wMRiX zUh^tl>p$9Y-BKnLXQL+rjLkq>Xd0|r3P1VS50^Mes`Uj0Pg)sXdaI>lsD~jYVykd^ z(|mh`ms#kXrv42sV)wU%RL#0r;6@e?{o7mp7ob#W=B-;kvCdlcIWJ1Wz|BhZ{t>?< z84!YiK4y*BcRwTH$LC;o0bsnXF(u*lfyRxU>3qxxKfTyotg|@R6x10X4J_Ny9KR6> zx10LD>zRnG1a}&7eaqYjq3VsWHxl#)%a#5=qZ>hJ!@d|_VcYS&YZEoM1Sq_e(*rHS zmX%`|pvlhN)8T)iFnbUx1H(n%P<$O`^E?9bJ|5}$I!hWhhN3=eiU?=o9_f(1B*FWe zxNhJzl>%epTi`W>r;CoCup(8iUIoLCscD@p*ma= zU-JZ;H=UU2=ghdIpUqYfdjqRM%7!XgeR2aOZsGeI^nISCi>^hv723FF>x2W~XM=)^1-g#Q(? z3*gyiY|+GBJx4jPv4)PDJ^6szk!GD9G3?wDGgTM%uf4z^wNSd<23FdTbNn?11+Ln} zBunp})2A+HUt193GchAWyH;L$mKM1>*->hEbpL&xj>?gud{5XI$YS7i^_M)4Mi)8s zz=9LCzcG0?w*m4ZZwN_(1SFALEuDiT_lk2|ol&SDtSJd5;|g-UD`DL{2~}P2RgpBl zPZ+y%x)HcFiFw&hC+#>ECH)wd`?BUKLoul(COX0=gR#Pe^J~mg${I8*v0=GAX=Z*~ z;1T_e39&IX18|;P4*MqaGd2h!YJU(>Gg_RVTiMGHr5tcC{=^^R8ufJj3R_)uHb)ke zhMLGbXtJzqHHtv-jeHKtrto#$LVD&Xq7)5$3^#zpgaqU2s0348tm+;5s&CCb5!uF)aKc_BIi5?*sbq~bsqlEAlG>aNQk3;X`W!)jxJy9u9}_V4 z&+BZW^a#5!?)`&xg|W7tx5U9#>XdK*hJp?K@3SzaxEDpIjZh-lmL}E116(7Ed5F#z zW%Q*1sqw6Fta%m2DERR9!gxcr*dPSZ=+C`cqM+fEr`-HPKl12tN{(~x%BvH%1nSsF zP!qcIk0kU{PGyp57pCmBudEcXASj*zM%&$7!rfqwGYj*H+2MI{H!x6*dgo~wE4Lf1 zFEc7Nm@K*Hb<48p*^U?|gM-3@!`PKJDhYCQJ7B)Mij}SPxzxb`$z~;(+U|~5T@F~; zITKcM$z8>$`QRv)1nDN^Xk~q^olFe77n#+T2lwLzEnfyjRR+2LH_dLfsSET5_p{o5 zzdlL%U}vC>DJUfU*0T0u*g|zg3l3Go%Cv`@X=`AX_Zcyvwk2S9{Xq8IJNli~^L6K< z*mb6B8&BWSVnE5J=zlN}H0Vy(xvw;C<2!~oA(w+y);f~uLt=UitzLvh`{zU169qLKdXJfC)!5ku_U`R{^eFJ09^JHR@QcQ3A0_v4- zQ5F*740|7XXk(48ePg7g=FRoVhcVJ&;&Ayb&waT9^>?u0$Kmrj88p;<8;^lIzWN3i zzc4cq{jf5iB>%#~ReD=fHi-GcMG2DU1Qtbfu|0xdaUabs`nYGGxsazMA6%lJFN8Eu}2MBv%2V4e1Q(>`H5H3!@#S(M;PJ zF&znUd#x159(5$Gn|EvDn!IUo!E?g89@c&B*=3}2WTK9U)!CFM+~|s^9(m-`$upK5 z0RijI<6C;CoswtOt>nvFOM%rLuZOwS&-s(%9E4loys#wt1Xgv{vxl|1BQ%k9H5c6) zDs`tQl)Jp1sll5oQJA033>soGC`^)8l)T z?}>R4CtPEt`GRaYWGXaaF-LTAjVo87Dqd5CvMYX~I_9@t$f9L1hW_yqju=8#+ z;cpC2TY^bbxyh!xf7;b=P24AU{VeqnHM=*DL2pg7&SM(x>D!%cZqr!9Z~66)Ms?`s zeIfnzMBBs;7UB1=o=?87-jY0YKBQXuZv#4GeB09opd_sqIL`rH;laNiXIR|4j8KD> zIr7>10~cl$zfX^UMSKqGkBke7>Fo$IZ(wjocbT;Wo}ni)&L;J%DGI6G ziOSz|!YE92?y>LsqQ;)M@!@Xym@@&qOT*y$t9l`PUYYzK$NRb)Ez$Exm3G_wBJZ#! z(%lzv1dtt!kA5U4bDg9PSYA3jPNQ`9X9sdYJ2M;+MwrVfvB+b*#!+^yOeg)y!R5T2US)iY=CmXq{nayD;i_%z|g94Qt_n0PJ$sm>}Z-N z8%)PH2hG1avWcO!*bD49@N&Z)dalU?aJ(;gM_Mkb8N8`y?fVCuk`tCrMa2)fD?EJb z8|L|@Zz2&pQ5p39EO zJMK&ZKgsQv$8UTK#gDwCK|X1@S!>yVP#>6&HBDQN))ytAf-&-!orP9ZA-8}hz8AUX z66N22ZT92uuKTiJlo9{RoOBuyMA8bL*1rb)Zq$8BJ*%~f6{^WczTggz=Q)YYV?{G# zr$MrZBILY|@rmfl{e)#q>zTc!y)6>xc*?A)K4)|9IZZwDyadR4J|INKjRO5F;O&8; zR2D_qEGU=#x3d5*GY{BlHl*_nxY7e%B1DU!TmY-MliHq92AXgKb7zIx-@@lcr9#79 z?_D9b&d|i`;j;tc3pnL``rw~8P|WiYi$^eTmh}B0spTz&gh29XzvM)eP3*+9@GvnQ zU=Do^)aPD%q#FTOmLtBcNF8ZztD#JAJ%#c38uYUZGMNdNNLJ(VR6y{yzgCnQ=o^F^ zI#%Ktu`gHs!B;DsUjfp^TK1e^+7)Bf&e`rI_bw}If9k7bkT*nhXs{V zh7Jv57ZzfZL${KVfWrR9gEkIxm$UnYbh{!j8xlTt@Zw8VrlEs7;*c}gVGYxrNxnj{jSE*cP zMk0Fz!rn8!9JU>^BT?WRLe@u-yQ5Tu`Ptec#QgxK^Mp2$tdWo63vsupZeH95Ip1WJ zqQLmRXa?7aBC6}Jg|kBTT4OsPUf{P~!<1G|gDkL9Rz8K0%3zVTi62Al^c*R(QRPzr z1BiCS2^XKA%nLaqRY%u$>cNMeP0A=Etu~_R7lp_clFp(E6 z+$W4R1EQYk3iRdC*vzeh*1nLDlOlIl$4r{t*Nak;tAt<-vIi?6M18-wJm{7_^yLYs zK2&;tH!3c#ZW~3J%Y^q)H7hIz^TBu01}XG-$+94%z)*^colpVl{?0uhNVb%xYaNDE z$!`}-FGZX)DbHKnFJMzhg$RlU%hqpgIL$`R*^V;utbjFho5@?No$6sKFCcdu1Bqk_ zt1A0?RT9ZYa6uNq;`C3@%tb&%OR={dHP*S19CAr-Glvlej5 z7=RC>`U65VaJ-LR7h@I^;FL~{=eD}>Vsw-ZM&~W{o6uF34f92u{R;!y-?!>R^1p`^s#?vW6ZDOX6F~ zBvHILYcbX0S}#&J93BmHB%`uJC<-CeLXr*LPB4OfuBE+!%BWLMcSkgXlR2giXw3IT`h<$yVX+s9mc0fV!$@SfUOnCma^!%pUY;BGrL`i zAr~$xyd3YssrUDdNPS05f^3`T@^`m??!KDK$Lt%VdEn7wG1a}{NtKN1G4lIb1acs) zzJD|;UwN{Bic~R+$B$?7Y)fE(9UR^C>?Nea9D57wPoWngpQISph;Q>t7cf12a{Pt% z$gV@nZKU4C)|M_D6AwAZ>#P}+22o~gL{UtXzmaGP6dsT;okOd?(Wg#m*B13cWINAQ z-3<3rEA_hMs-BiIbaMOI3^P&v8_7kR($?|niD}m~%aV2@#;IVyrU+*@8=Z8 zH7x+MidGJwtTtgKL_P35fJgd|(`7}#Pw=L4cSST$<}Jxx7h^fFL)@^+y}jk@!?|l; ztH5gw&#A80XzT3nZ0bkSS(Rw3uPeydRj&EA`_Cg0zTg<}FUhsLs9mKhOt`J8C*m~q zzyh`~S74C}je-|u;0TI^ykO~QExz1h+(N4+Jb(!M^;4`0$Hm&-4MYsP*WMO}{j})= z-V1|bg=veiePnzyYmXY+f`6}r8I30xn5lEJ8ND1@z}Si#>AGff4T-|HhU~(R*mfOB z*)wx=`>QYbaa%Z$jBY4U({ROBudA+;bu&6%=J1o;thgD072;O9lw;b#R-yDq=X`cqAyl<*1xyMH{*kGy`{`a#;GM(u={vT4aJuG zP43J=+)A_x^(l{L0`&-SbTdP<2;?Fg6l(TenhrXC=2iP*`3VR7LTTm~4anNE48-Zq z*lklD_er~|tAICCf@;O zjH-4Fo&e+V1u=hf4eZxT%ndf2=r^<~7`9@J81{xGFQi|sYYIaCenrl`H_>++y{@2~ z>Ov{F?ZwJ$2~2F(Q*vSPT49Cb)lTlJ3+7@oT}^x(w2!W(p(eIYUmw@4a#+!^SB#(# zx6^i82c~`K?tF5S+~LJ0-j`t@`+ z5ZzCHCma6I4L>44%-Qs%F5%7UVp;ay`S!5tS{26@yi-TV2ovJ}?lr&a!IW@P^msE? zQoy&e!O@?pBqTELFWM?7lHUNI0qN8z zbJ;FB&`2+-y7KUB~hCFS<+kz;jek=uO zpd*c)v=L$hY(-wf@>m|KGnPGo4OP_b{V29;k{C=&rMz_k({u@&XQq-le<66GQY3MA zIn0U++5Wa5H*p10Xw z{)VI%xNx$x%K1l$U**%T(kkPuSmx_Rzsew_i+=2rwPFh?N!O6vbRmyRJM-6z-hB3c zDVZL5hFL@oyS;^<&u?7oPmdMDu?WlKu|Rr5v+L4Y5bWCArgRdYgD86s3kS#M#i_x~ zTf5D#H~B67-!qXVgQ|G|8dsCUOBJ+`J0^rf&8)zrhgH@|=#T4foO;XIoy*_&>9TIC z6V6DVE?&ZO1q6m2D!6CRK+2py67iSuVaS>~N~nJLL@Ih1I+8iw1!^Kl#L^mj0`fgY zGtd}Qe8CK+pIx&y4w5|u%scL?Rr;3@)tC_&ZkhUe#p7`3sK}x;lwpd8=n9M={7okc zS?$8?)~ZhlwgJ2%87zq@p&3b|{UPPYo#RbK;|@xU1wq(hjYm zPgMxQimRnB&yq!zd+sz{g|L0T*02=a%$Cs*Es3Hg#mfy(kmX!W#NqC}X+jnb=8Yqc zV#c+t%TV_f7aTw0p~=8Bpj%tZ!jcmwLzdx0i-m`2fhxUw4!QaxK_SWgvMHPKITA#s zQ-UwlubvaV_v37cxl85UTw>Mqpl*gx9szWqf=c$=Lz*jb3ul?m@$t#^$|F#8vJ+m7 zfV=umwL@DJ8->e|;(v4G%J!<^)KoS#>tK&XzSSKNoX;U`UhYuQ5+iM=sd3;fs>^Xj zdLhpbZs!O|gW=p6YQg&ayz-(vr5tK@s<*38r@$iHDtNjv{4R6Xl~OCK84Apw$X?^; z+CGrRYQF6Xio4&X`i4kYM$he~kiwUHImg3zM{~6`#CuB>jHJQvDk3g-~=(k%LjeT?)gc$j2qmOxUgUC|Bg|Q2U z-A_((Rk)u3ju>s#D4=+o=)U3vPUBKRIE+8dFy89Uq#}%hnIfX(e8J}kBxCoKfxKwJ zuP%{L2JlXTeNS4@G1zu0+YxIuow+Aj_U}O~%^Eei$GcN>E@%$-?!KhkNCV>cPiA1U zwmm-|PQ&62h8^D1gX3jl$>rb^`0Q;Aa^%*(h3^L@Bce7N(bcGgN86KcSc=mTV&J{@9GRg{P|Be`Z6!!PI!low7%JQ2r zP_^@gGJaB9;3G^x&6I#BB43hQyOmhqUM5u17&-$H+Tw9Qs%eH>cxf@uxpMsB)R&h! zM-sR-fp8nKrtQ@nfEtJFk-B>RQww|#2CZ*Sgw88=?8$)gxo1jDCl(x*gNZW^oL45Y zjeYNie#Epd?r5IFZGLU%u=un*u;CA%NGQj|y)>IshKnRi@;K zEz*>5EY1o5hn#X{Lf6xx$4`2BoDOET-`_U?j^0sHQ3js}8;QpkmwrUmQS9d$!+f5b zGf-;S=Xp4Shjl%iaAQO*gzbz=Fn*M%l=F`8PDKX+GBMktm?m(?rF*di^zUIHlf^ED4b2(`IP+Ep_Y_L1}rRAw;&P5DtSIOWGZh)cjd2wl4ph&A)N7h z_WV8A2-oR$kR{c{lY%6uKnk$qvGQh1 zF<J(NSJ()`W?ArYmT+fmXn%RwXSJoUC@Teoo|GIUl_W{X>+ zt;B&$}u|-Xut~SGb8_?WLg^0fYz0MtUt5+ zbqb+qmJt>MGo5x)EWn`VzYYP$TI`aI(SE{^*umtv(&CsR-22W@#cqMrq5Zx~pt0QE zrO&9kg$3}0G~I3q{+NGYk#N-Y3$q49Ira;3@#j!JQ%3ho=Ll9i&4=KXh_hcRHD2?) zJzs!!W_3xq3b*%kL|x`jt@87`Tdg0X>C*G`E~M5PjmYp&{J@YPMZF>|t5#qG7)>v{ z;alM=xOlgDl7^-IH76v^9-XAFY@1TAKs%&^#tuB~QXvvmGlQ4Y7>_v1og9(lhM@cq zd0bke@#)-0G?BsdTrNP5f+IOJ455u9Pw3%*XRL+o^m*bU#&i(K{Zt{Q>i46P(0!ie z3inz0(m_}zNx;blc4250S0l#Nl6JY$Rycq60t0sO!xCer34Q-^7Gq2u78=0PXnOl>pnL-fT!*AJg9Ut%sje?^vJ+RkA~_!V(OcC_!kv}DX$ zUW2Jrn{^t!0t5@P(&YbsgCtc00t>fZ{W7&gXpHaQ4V1n?Fy+twZ0HLgt1t_`_Ogqs zuv&Rmz!`S>x&|T&(+56q7@S9?x~fCaE9}?)LNps%$v$93Ne?Jw+DYFzR*&|}+_yOE z?{;@G&@S2Ry5j(9*jiHxt2uTKyxZs-nCAVHuccvlBK;Ay@ zSlzozJf?exHVyV_#&1I_QC?cTQ36fj65g^+AP3tWP6Yx)O&}Y69!)XXKbPLTGtEiV zzh9in>aoCPEG;2%HYXTDMK{JJn@BG^7?_BAAd!c}&FOL|-(c8EC?y6PRJk#$HdA=9PH3y%i z1>V8|J@dwg3zW$t&l!1Z(YKR^iA)f~W~E`>Bv%im6#8v%#ZUD-HCo@M#gz!aA93ar z{l`cHrJ-@P55=4a&cU+0Nk3M%5_s)N^SQs?{Kl;gFyvbf7fVLlS7cbJS(YTe72}Tk>N*n`Q9azHh!d;jJBIZ(*xJAZxOIa%PZ_9z2(MbD3vwQS0%QxM9PDp0+Ttf99wSNj62 z=eJ~8mNTWn9+O($8r_LupKtOaK`m`uT4u5N20*(T4V+~!x{2=xefL-VQ0@3tV_^8R zBIKI&Pdj=Q7j=`ELqUm1&{c??(yZ#oNgJHSzI#$5bCU$XDP5*0165m#@NWTaKz4lW zM_8R1%5)#!&-2m?3|kPSU7$-x;U%k?hxiwI?WB( zgN~h!0BsTuxi4r4IEds8%1u0e!(8?ct>!a%S!vb2;SmH$ND_D74oJBb*n&Ojj|^k1 zsgt~=Pz&XfPFKhl!PK$b(k>`mO9}h?Y}11hB431~B-i_X<;*Q~(9P8Nix@&sy!M;? zxYstTHeh0&>g$3eAQGG098WMmMVsk{n>LgoEpmaF{DvgImr|t&6dn!KBrMR78jEPo ze3Z_5aunna=dhVYRvLlg&4x^|Hc{rsYkVpJk+05|IU;U@3!K)6saQFoe_)9J zec19;YZKlKrNsf{4Wtt_Nd;8A0HBNo?5i6`B}9#OVzYun>(d}t?s>XNvmbiekJ19X zJR%#yZ9UHA&v-;kj2`$@%3XFFra4v!$Vp2O$)@PQI_a;5cHq4{VqweV#e46cTOcsR)6^WJj25!B6Jg#p9?h@f9T-&_~pbj zGcYufDDc-U3e__yR6{g`O$qSQ{u<7I-4|keL-=}-2E%o^VX zfnb%a+3SkK-q8aT#ll*6KKcQz!#mvJu6zLBq z($g;N!a2P#r0U`UT?&dXzbgE7G(ZE_!4f~dVX_>Cew9u!Aq3g&3Nafhb=kh7dpRq) znnGY4jN2;8?|kW{6-NS@2m2I6FTnm8=*E%T;u%vmuxp=OVZ4|bg$bcAroLy}pnj)p2QN zNtn&=7SvjuR@MHR-}McepSfaHA^njPLGHY^W=ide))KQ`G*7*k8p5Z!0iduuvyoyo zbDwp_mWmTeJ2OywL)94mE)OLY0oWn6>`Dk2rWlBBURwrYp3A5 zp#}%d16$0LOLOi$l!~iT(p7H#k?o!oy{_E+%<-fY4r?53j0b`cbQ@@LQ_# zQ6B4Iue{G|C8_J=NF9q`_zb<$r(xHA*G@!<+D@!Fb$1}CYkuF6wDCMNi7LSn#IN`n ztOe~L(9gBYEtb|U=osHi^4uYh*3#qxUIlL(R}iQnBiJ^PL7P1qVf*Zd-Kwpodpoek zt!)F9JJX;1sn)ERwbRO4xpvILAriYFA0ZJ_J*N;Ci`4MqMnql~N=^ItHI}`#3g2OK zOHumoyn$X%2S9ojI3kHOpul}Bhw?Ag@GfImL&v<)9|e zj-$?4b`^mUSy)3pE_{p}sSP{8noeVlj-AU_N>(&hC8XK02WCH~!2nEeyK_#TsJ@1h zNM{WMx;a@K**6w;+Vw5rc&0Stz$lE<)tPjLn~ae0L9I2ueG|g+Fo$z!&V-&Td%HWW z%Slr}iX>x!pU1fLksl3D`t<3VKt=cs$0;`(G#~8~;r2hE@=H+lDxnFys3j&435`_< zL%w`Z7q3Fc$Dqxv2(+~fr@vdDWlQ_E%u|T`!x9vd4j>eqKsNQ`m2z^`=gc&n;b;hJ zIVmr-xQ&8r+hvHgA85RPK@(gum*$#C)HJj#h9)_DUraP)%ZO0q7~HGaY8Z+3v8#_) z-1)7DjNeB0=r0Gc;t@l6FEF7V;cqj}>C?i0!6t&+Bdy2HS7S*@fM}d;uvLW8WympF z3j#ndml(9>0Q5RAP-Jsxe~ick#woskZkdf~(m*Ki8mJnW4zGq9kpJCJ6FnnA86n3K zDI{Q4i_nPkicAFAA>eT)T|sY{@n8q(0T&$rT9xMq#zF#R_ad=s3z>Mv{UT+>we7GX ztIuV14v6u&4X89pE)}|)1MyMIIcl5bATV=lbo@0P-Y>mkfvqAlm*o>?T#JY{Rwj%+ z^iw$EOaBm?>zzJD%$-A}xYSRU)n)I%T1cUm<+*2}R~f_N`-5%XBd}^T4LiTYTd$l$ zI1ayK&Ie731gSn)unKgt>eW@Znt6P1N{^^4y}VlJs7sSCL=M&THxS7D;<~=(+jtbU ze53F_gsi^b>4$*dIzC;aAfG&p`9%k^3qXgRjmVxMUAQ$&jZWvw>ehvF#?@ zxD~w_I1o4gaa{o?7S2EJGXCCCO}3L~C5`GIn}>Pc9kw8vkPge8APHXun*5B!FSx;h zT08lsY&Kv%Ubn(-DeQ*m5UnkeNaRSsls@_o^aQ2vgaNSl0~8lUX}=p z+Yu6$zV16|WLCI(zTbUD;iF9%H9%40SzZwwJr0Gh%mY{vJ%lkJ83w9QNEcFYN6iZh zWJ^r*FCgmL{K5v1haPtG5?;tZCTv7dbZ^U<8mEDEDd#n=QaNk=^DfY4LiLew1hy-w3l<*{65QJ!qbaT{HtS`e5I4~V+E~4k z0L-nzD4rBEu+d`+9wq1a4#Es@n}Ar<*0!AR1v7L_1GRHmJKr!^G|(K z;Y}4AT>U1>uz9U0Kd;UW=Y5~34bnFBf>9mJB*NGYb{b1dDPbJ9eMd~EEEP;pHv`V- z7ehI}IyC0GP>a!GWTnKZXZml!uu~`+J`7#IFVDdcAhAXr^MN_Ac!+k3$P8%cMNN>veQ4rt8@kO@%z(6^o-n4Ai|DDOUm)o!%=;Mz}8L|FN%hPA>6y9 zm}swcn1S*{1e&=IDR_!j{E;>m=H{PnC1?gYD!~?N)y4n=9+xl=jC?L>i7zeFrv33S z{=AXI4xbH|f9`n~Tg1d{kNn5@pCca+ia()zbZhNe{Srch&$% z4WH7NGJ8aFx1hckWp`@?$cC*q>vs@DV8^$Qo1p(zqfKR zn)F>SQ{-|?u+&RFsW9XT|TcpCtDvCy&8UGqgCcp z_tQ#Nbk2tIn3kf(EZX>p+=v5ibOA|a$%u%LFSmX-Ff`i04azs{DS_KB>@c`DIL55E2E2}8{6YB{YTf= zH2c^4!}@o_WA|+mkPsjonSg*~r>O$|_1WE_!POZ4QZlNb1Ypfzo7n0=$2l;xGcf>* zr(yzD-~_Dw!=rfmA9cVCjSXyUfAHksp?(nR+`u=ue@M&?Z4E%<;S|u3lM__HBEgs` zA%I}3qW~5UeJ882aN2$g0>t29f6n6I_TPCX7We#9_kOE?jjy$TnlSb@R8YLwdddm3>%Bz|jF@ehYG`sf}Q&0stxXF)1}k z#PfIrMn*8rZD16b>fGNd!@JwZeG0(TPSS0EdiQ^#5*%3HsKWD`&vo8=f3W{uPcyrK zVoqjo|1NC|^*_|g{0=Sq{piKP%&l*YU+j4A>nQx{R@O&17jORXKHB~>NQ_aE|0SZL zmHzCZd?%qbur)HWwXuOxaQ>n$_wT;@1^6vKf}Q@w&ihS#yA=b-{LQ5?+BdViftvf6 zz0XB^|IIz=NuT`{1P5Dd^PXq;+5?e1j3;#Kwptgttx!4> z=tvLyk>{q`FVqO!idZ}D@I37({cZgw%yPS4p6N%!jcZx1(62W+qZ|1uPngH5&UZlL zRHzacS2~#`JU0?AX%OwhW3y{A1H4VREEbPs^7hvuwJ{?P=hu5$Sp&QRARSK;`mw~x$`2Ir=aGI zI7|ptbkw5>25e)zVH2j^1&sF(T4C_{Fx)9UI3c8bUyk4!SPY(Tg-czCkY3R3$ZIt+ z{O@Y~+sRg_bc`umGyVO8!y*S6Z@lqIy#{wGw}`H%h~T+}#hesLk?p0D`yu0z=la1Y zX%GT0@k7cTF;65UBcuB`l2K=xUNS2|nRl@H%e=N%f}!gY6qwin2L>)zqJP-9Q9kRv zc)#7@mYnvZAtwapSnoTN1U&JN^4q_^eD!Cdn#vXmd%Ky^8%ri_vl`Q14Q%pML6;F5 zlK--%r2Un0fxo1~L!V5$dmB-BTwD`+buGZ&`3ddB5N&z%pA8r=Od+ry2cIb;`aB6_ z5~G3bwHFfe7<(eSAv|9ieaUWvML8^meLnh)G^d7(IahKENJr;(lP+e1zq5Hm=y-fuQFj`7IB;Xo&!ioQU7d(=|%C82E!RQaxu^L?PsK3GkjJ(=P;`!C!jigT&J}_UdJqH&>L}d zTj;q>7cu(!_g0ZLHZ81R*+1;HxIHAOpl*|{X{dklm?7u zJda@yL|&T*n1`V^Nn4Nex#SRJ7-%CL zjWxn1s)@^#^!}chvJ!5T!yd3A#%R=RoZ6ZwZJ4eD%WqN&aWEg(D8=WC6ye)%5N*$L z@KGs*4K0}uaUPruU%HkeX=8CM9(Z~0!1>@_8tA0PtjD#S9P?EV`@kO#i%L=h{(ATX zi8xtC7Tc7Q7RmHE4klNqD^RoG11bmc-g$o@_YMdG`o^4&g4S`wYi@6ATMlG)Uj}w@ zu@ZoNS%Pvb5ujr5#n*NRt)|ier&B$4k!Qav)f=ix-HV( z94y_l&hlw6(0e%c3dYHM^`_&V4I-y_TAt4r35h$aL{P1286_scbgP)Sa*A(X27#_qT4lwOH#S2?v@+vyDdnC=A`zPi>; zy#k*tw~Z41li2JZ04mP!I@Zzy@xfvzh@hT{=`u2|;8~UQQ(iEk9>e#O!g}QGv{O)C z45zYyq+xwz;+WcmV|VGwn2@*~Dz~PVGrV#1aMd}IW~h2aXRe{cx^5+<&dRa%500J8 z*MS%E{?`;}t9({Ob9mVqtd@n$HLTVxyl& zZ`_$6CGh;*S~T?Q4x6K&j)0-diF)dn+Lr1V|)bUTpIt^}wF3GmX9R@n5b4#^VE$aJ4q>qwH#T6wh=M&M%$dM;R7Un%q|7 z(x{+zCEMlGGLG+9xIw(|27@+uc5*e#EFXV2jd8#PyKs1J&EU=%^mT5O<*9pw`0V3y zdH>-dPME>TtaP>I(f6L@ga-cMA0h<%ql~1sp2J2))1BulK;=K6fnRFp zuBhAo%7o9=xopX!tQ>ShlF2rWjC4AZf-E(~qg>9-c2jxS`l$#6HpQMvq(Dv%jEuom zy&u3hI!8M29i55<)d8QsoW)6vA+%MI8g+U6T01wPO>B%Ixz4*Wn*u9GZm8d?=jUW3 z2^b7RX?*Krao8AxHZ~51P$7C97zqMR{Zs9(v}3{<>r|Eh`Z0Kb)W~i+cikYQRTU%Q z+i-9()^WlT6M=IE>WBbcXUs0h+%2Y0`S+%Ch_Qhh?7^n!dlJyWkm_c0UZV!R(%o$I zPgl1e&>vsP7jq}gsY9)KlKa0`TfH`OmQXJ?oR|oZG6;wr#;K0k#Y2z4XK8*^F%(=hS`b9SIQAS3jeeuck$~(%jL) zY>uz$k$UsA>#z2~8Vj`k)y_Lg*>1R^sV)Dc;m-)VU@r2fQSMI<<-O-Mp|H5S!J;ja zI3h9{P~1h>24hI3;`oqqDpHiI)$*0tTF=$wI(76d>lDS1L8nMW2FE_HCQW&aMMyEi zEti%;j(9s04GZqeEt-o8{oNZ?(bUu$1JCdq(}RNbrqB=Jfn)&oXP{^6(2qzd zV_x|236FQNeEb4T=&S#>C*|06;@aFkq;{BNg$tQxY0Z`e1zqS#+nBS21cl3)QuJZ1 zO(kTnO#`*bRr&L@>K<-Nxv~jaNjl`UA zc_~B*5kTCp;xgB@l%S|NEOP{9m8)ZT9bJCv(B^ntpa<|GJ%?gNKx>{LR-rAVNTuIr z&7ZOi&nFGLUJVfYmoh1WQ4)7aGn7T-wU4qUb!6!y(bK$PGgzb(U)Bm+_U14wyBDX? znAbg|iwmKVRbw&=yF5aVl)FVbUn(_ZOmsdAd#kbbo7B>~W3b1L8mBSWtx+V}$PV$L z*mNbxJ^ANx@m~#@@Er10u9(2@HaAb4E>FH z5o*g_+{y)PXDMVYuGpixS%bwYtjq6glqnDdQ)Qp~Q7mo>!&o`tQ| zT~$gy<`TuIps&@rkRc2R7%wSyjJ#b*9(oe?%ijvbBxOsz_tibMiO;K+o?Pd!ia


wr$(?>H7vf>%ki(sSHz<+R0vPec26Z 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 =W{z!T~}_ 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

x2olpx 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 C=&&jP literal 0 HcmV?d00001 From 6a590aa4d478cca7afca553e64a807aff5409cc3 Mon Sep 17 00:00:00 2001 From: mingda Date: Sat, 26 Sep 2020 10:34:28 +0800 Subject: [PATCH 090/118] new oracle --- .../helper/BandBNBBUSDPriceOracleProxy.sol | 30 +++++++++++++++++++ contracts/helper/ConstOracle.sol | 22 ++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 contracts/helper/BandBNBBUSDPriceOracleProxy.sol create mode 100644 contracts/helper/ConstOracle.sol diff --git a/contracts/helper/BandBNBBUSDPriceOracleProxy.sol b/contracts/helper/BandBNBBUSDPriceOracleProxy.sol new file mode 100644 index 0000000..681f31a --- /dev/null +++ b/contracts/helper/BandBNBBUSDPriceOracleProxy.sol @@ -0,0 +1,30 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + + +interface IBandOracleAggregator { + function getReferenceData(string memory base, string memory quote) + external + view + returns (uint256); +} + + +contract BandBNBBUSDPriceOracleProxy { + IBandOracleAggregator public aggregator; + + constructor(IBandOracleAggregator _aggregator) public { + aggregator = _aggregator; + } + + function getPrice() public view returns (uint256) { + return aggregator.getReferenceData("BNB", "USD"); + } +} diff --git a/contracts/helper/ConstOracle.sol b/contracts/helper/ConstOracle.sol new file mode 100644 index 0000000..87181e8 --- /dev/null +++ b/contracts/helper/ConstOracle.sol @@ -0,0 +1,22 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + + +contract ConstOracle { + uint256 public tokenPrice; + + constructor(uint256 _price) public { + tokenPrice = _price; + } + + function getPrice() external view returns (uint256) { + return tokenPrice; + } +} From 433ac0eccb26029e400d2ff93d97a7ed786d7281 Mon Sep 17 00:00:00 2001 From: mingda Date: Sat, 26 Sep 2020 10:34:42 +0800 Subject: [PATCH 091/118] multi sig --- contracts/helper/MultiSig.sol | 440 ++++++++++++++++++++++++++++++++++ 1 file changed, 440 insertions(+) create mode 100644 contracts/helper/MultiSig.sol diff --git a/contracts/helper/MultiSig.sol b/contracts/helper/MultiSig.sol new file mode 100644 index 0000000..ac4b5ce --- /dev/null +++ b/contracts/helper/MultiSig.sol @@ -0,0 +1,440 @@ +/** + *Submitted for verification at Bscscan.com on 2020-09-25 + */ + +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + + +contract MultiSigWalletWithTimelock { + uint256 public constant MAX_OWNER_COUNT = 50; + uint256 public lockSeconds = 86400; + + event Confirmation(address indexed sender, uint256 indexed transactionId); + event Revocation(address indexed sender, uint256 indexed transactionId); + event Submission(uint256 indexed transactionId); + event Execution(uint256 indexed transactionId); + event ExecutionFailure(uint256 indexed transactionId); + event Deposit(address indexed sender, uint256 value); + event OwnerAddition(address indexed owner); + event OwnerRemoval(address indexed owner); + event RequirementChange(uint256 required); + event UnlockTimeSet(uint256 indexed transactionId, uint256 confirmationTime); + event LockSecondsChange(uint256 lockSeconds); + + mapping(uint256 => Transaction) public transactions; + mapping(uint256 => mapping(address => bool)) public confirmations; + mapping(address => bool) public isOwner; + mapping(uint256 => uint256) public unlockTimes; + + address[] public owners; + uint256 public required; + uint256 public transactionCount; + + struct Transaction { + address destination; + uint256 value; + bytes data; + bool executed; + } + + struct EmergencyCall { + bytes32 selector; + uint256 paramsBytesCount; + } + + // Functions bypass the time lock process + EmergencyCall[] public emergencyCalls; + + modifier onlyWallet() { + if (msg.sender != address(this)) revert("ONLY_WALLET_ERROR"); + _; + } + + modifier ownerDoesNotExist(address owner) { + if (isOwner[owner]) revert("OWNER_DOES_NOT_EXIST_ERROR"); + _; + } + + modifier ownerExists(address owner) { + if (!isOwner[owner]) revert("OWNER_EXISTS_ERROR"); + _; + } + + modifier transactionExists(uint256 transactionId) { + if (transactions[transactionId].destination == address(0)) + revert("TRANSACTION_EXISTS_ERROR"); + _; + } + + modifier confirmed(uint256 transactionId, address owner) { + if (!confirmations[transactionId][owner]) revert("CONFIRMED_ERROR"); + _; + } + + modifier notConfirmed(uint256 transactionId, address owner) { + if (confirmations[transactionId][owner]) revert("NOT_CONFIRMED_ERROR"); + _; + } + + modifier notExecuted(uint256 transactionId) { + if (transactions[transactionId].executed) revert("NOT_EXECUTED_ERROR"); + _; + } + + modifier notNull(address _address) { + if (_address == address(0)) revert("NOT_NULL_ERROR"); + _; + } + + modifier validRequirement(uint256 ownerCount, uint256 _required) { + if ( + ownerCount > MAX_OWNER_COUNT || + _required > ownerCount || + _required == 0 || + ownerCount == 0 + ) revert("VALID_REQUIREMENT_ERROR"); + _; + } + + /** @dev Fallback function allows to deposit ether. */ + fallback() external payable { + if (msg.value > 0) { + emit Deposit(msg.sender, msg.value); + } + } + + receive() external payable { + if (msg.value > 0) { + emit Deposit(msg.sender, msg.value); + } + } + + /** @dev Contract constructor sets initial owners and required number of confirmations. + * @param _owners List of initial owners. + * @param _required Number of required confirmations. + */ + constructor(address[] memory _owners, uint256 _required) + public + validRequirement(_owners.length, _required) + { + for (uint256 i = 0; i < _owners.length; i++) { + if (isOwner[_owners[i]] || _owners[i] == address(0)) { + revert("OWNER_ERROR"); + } + + isOwner[_owners[i]] = true; + } + + owners = _owners; + required = _required; + + // initialzie Emergency calls + emergencyCalls.push( + EmergencyCall({ + selector: keccak256(abi.encodePacked("claimOwnership()")), + paramsBytesCount: 0 + }) + ); + emergencyCalls.push( + EmergencyCall({ + selector: keccak256(abi.encodePacked("setK(uint256)")), + paramsBytesCount: 64 + }) + ); + emergencyCalls.push( + EmergencyCall({ + selector: keccak256(abi.encodePacked("setLiquidityProviderFeeRate(uint256)")), + paramsBytesCount: 64 + }) + ); + } + + function getEmergencyCallsCount() external view returns (uint256 count) { + return emergencyCalls.length; + } + + /** @dev Allows to add a new owner. Transaction has to be sent by wallet. + * @param owner Address of new owner. + */ + function addOwner(address owner) + external + onlyWallet + ownerDoesNotExist(owner) + notNull(owner) + validRequirement(owners.length + 1, required) + { + isOwner[owner] = true; + owners.push(owner); + emit OwnerAddition(owner); + } + + /** @dev Allows to remove an owner. Transaction has to be sent by wallet. + * @param owner Address of owner. + */ + function removeOwner(address owner) external onlyWallet ownerExists(owner) { + isOwner[owner] = false; + for (uint256 i = 0; i < owners.length - 1; i++) { + if (owners[i] == owner) { + owners[i] = owners[owners.length - 1]; + break; + } + } + + owners.pop; + + if (required > owners.length) { + changeRequirement(owners.length); + } + + emit OwnerRemoval(owner); + } + + /** @dev Allows to replace an owner with a new owner. Transaction has to be sent by wallet. + * @param owner Address of owner to be replaced. + * @param owner Address of new owner. + */ + function replaceOwner(address owner, address newOwner) + external + onlyWallet + ownerExists(owner) + ownerDoesNotExist(newOwner) + { + for (uint256 i = 0; i < owners.length; i++) { + if (owners[i] == owner) { + owners[i] = newOwner; + break; + } + } + + isOwner[owner] = false; + isOwner[newOwner] = true; + emit OwnerRemoval(owner); + emit OwnerAddition(newOwner); + } + + /** @dev Allows to change the number of required confirmations. Transaction has to be sent by wallet. + * @param _required Number of required confirmations. + */ + function changeRequirement(uint256 _required) + public + onlyWallet + validRequirement(owners.length, _required) + { + required = _required; + emit RequirementChange(_required); + } + + /** @dev Changes the duration of the time lock for transactions. + * @param _lockSeconds Duration needed after a transaction is confirmed and before it becomes executable, in seconds. + */ + function changeLockSeconds(uint256 _lockSeconds) external onlyWallet { + lockSeconds = _lockSeconds; + emit LockSecondsChange(_lockSeconds); + } + + /** @dev Allows an owner to submit and confirm a transaction. + * @param destination Transaction target address. + * @param value Transaction ether value. + * @param data Transaction data payload. + * @return transactionId Returns transaction ID. + */ + function submitTransaction( + address destination, + uint256 value, + bytes calldata data + ) external ownerExists(msg.sender) notNull(destination) returns (uint256 transactionId) { + transactionId = transactionCount; + transactions[transactionId] = Transaction({ + destination: destination, + value: value, + data: data, + executed: false + }); + transactionCount += 1; + emit Submission(transactionId); + confirmTransaction(transactionId); + } + + /** @dev Allows an owner to confirm a transaction. + * @param transactionId Transaction ID. + */ + function confirmTransaction(uint256 transactionId) + public + ownerExists(msg.sender) + transactionExists(transactionId) + notConfirmed(transactionId, msg.sender) + { + confirmations[transactionId][msg.sender] = true; + emit Confirmation(msg.sender, transactionId); + + if ( + isConfirmed(transactionId) && + unlockTimes[transactionId] == 0 && + !isEmergencyCall(transactionId) + ) { + uint256 unlockTime = block.timestamp + lockSeconds; + unlockTimes[transactionId] = unlockTime; + emit UnlockTimeSet(transactionId, unlockTime); + } + } + + function isEmergencyCall(uint256 transactionId) internal view returns (bool) { + bytes memory data = transactions[transactionId].data; + + for (uint256 i = 0; i < emergencyCalls.length; i++) { + EmergencyCall memory emergencyCall = emergencyCalls[i]; + + if ( + data.length == emergencyCall.paramsBytesCount + 4 && + data.length >= 4 && + emergencyCall.selector[0] == data[0] && + emergencyCall.selector[1] == data[1] && + emergencyCall.selector[2] == data[2] && + emergencyCall.selector[3] == data[3] + ) { + return true; + } + } + + return false; + } + + function addEmergencyCall(string memory funcName, uint256 _paramsBytesCount) public onlyWallet { + emergencyCalls.push( + EmergencyCall({ + selector: keccak256(abi.encodePacked(funcName)), + paramsBytesCount: _paramsBytesCount + }) + ); + } + + /** @dev Allows an owner to revoke a confirmation for a transaction. + * @param transactionId Transaction ID. + */ + function revokeConfirmation(uint256 transactionId) + external + ownerExists(msg.sender) + confirmed(transactionId, msg.sender) + notExecuted(transactionId) + { + confirmations[transactionId][msg.sender] = false; + emit Revocation(msg.sender, transactionId); + } + + /** @dev Allows anyone to execute a confirmed transaction. + * @param transactionId Transaction ID. + */ + function executeTransaction(uint256 transactionId) + external + ownerExists(msg.sender) + notExecuted(transactionId) + { + require(block.timestamp >= unlockTimes[transactionId], "TRANSACTION_NEED_TO_UNLOCK"); + + if (isConfirmed(transactionId)) { + Transaction storage transaction = transactions[transactionId]; + transaction.executed = true; + (bool success, ) = transaction.destination.call{value: transaction.value}( + transaction.data + ); + if (success) emit Execution(transactionId); + else { + emit ExecutionFailure(transactionId); + transaction.executed = false; + } + } + } + + /** @dev Returns the confirmation status of a transaction. + * @param transactionId Transaction ID. + * @return Confirmation status. + */ + function isConfirmed(uint256 transactionId) public view returns (bool) { + uint256 count = 0; + + for (uint256 i = 0; i < owners.length; i++) { + if (confirmations[transactionId][owners[i]]) { + count += 1; + } + + if (count >= required) { + return true; + } + } + + return false; + } + + /* Web3 call functions */ + + /** @dev Returns number of confirmations of a transaction. + * @param transactionId Transaction ID. + * @return count Number of confirmations. + */ + function getConfirmationCount(uint256 transactionId) external view returns (uint256 count) { + for (uint256 i = 0; i < owners.length; i++) { + if (confirmations[transactionId][owners[i]]) { + count += 1; + } + } + } + + /** @dev Returns total number of transactions after filers are applied. + * @param pending Include pending transactions. + * @param executed Include executed transactions. + * @return count Total number of transactions after filters are applied. + */ + function getTransactionCount(bool pending, bool executed) + external + view + returns (uint256 count) + { + for (uint256 i = 0; i < transactionCount; i++) { + if ((pending && !transactions[i].executed) || (executed && transactions[i].executed)) { + count += 1; + } + } + } + + /** @dev Returns list of owners. + * @return List of owner addresses. + */ + function getOwners() external view returns (address[] memory) { + return owners; + } + + /** @dev Returns array with owner addresses, which confirmed transaction. + * @param transactionId Transaction ID. + * @return _confirmations Returns array of owner addresses. + */ + function getConfirmations(uint256 transactionId) + external + view + returns (address[] memory _confirmations) + { + address[] memory confirmationsTemp = new address[](owners.length); + uint256 count = 0; + uint256 i; + + for (i = 0; i < owners.length; i++) { + if (confirmations[transactionId][owners[i]]) { + confirmationsTemp[count] = owners[i]; + count += 1; + } + } + + _confirmations = new address[](count); + + for (i = 0; i < count; i++) { + _confirmations[i] = confirmationsTemp[i]; + } + } +} From 88dba8d555d3c6cff49621ad490966aee06a5735 Mon Sep 17 00:00:00 2001 From: mingda Date: Sat, 26 Sep 2020 10:34:57 +0800 Subject: [PATCH 092/118] dodo mine setreward mass update --- contracts/token/DODOMine.sol | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/contracts/token/DODOMine.sol b/contracts/token/DODOMine.sol index c22391d..8734c9f 100644 --- a/contracts/token/DODOMine.sol +++ b/contracts/token/DODOMine.sol @@ -132,7 +132,10 @@ contract DODOMine is Ownable { poolInfos[pid].allocPoint = _allocPoint; } - function setReward(uint256 _dodoPerBlock) external onlyOwner { + function setReward(uint256 _dodoPerBlock, bool _withUpdate) external onlyOwner { + if (_withUpdate) { + massUpdatePools(); + } dodoPerBlock = _dodoPerBlock; } From c3c69cc0d936f7bd72a7c0a2d000b8119cd27012 Mon Sep 17 00:00:00 2001 From: mingda Date: Sat, 26 Sep 2020 10:35:14 +0800 Subject: [PATCH 093/118] fix test --- abi/dodoAbi.json | 947 ++++++++++++++++++++++++++++++++++++++++ package-lock.json | 13 + package.json | 1 + test/Trader.test.ts | 120 ----- test/utils/Contracts.ts | 4 +- 5 files changed, 964 insertions(+), 121 deletions(-) create mode 100644 abi/dodoAbi.json diff --git a/abi/dodoAbi.json b/abi/dodoAbi.json new file mode 100644 index 0000000..5fe6b66 --- /dev/null +++ b/abi/dodoAbi.json @@ -0,0 +1,947 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "buyer", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "receiveBase", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "payQuote", + "type": "uint256" + } + ], + "name": "BuyBaseToken", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "maintainer", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isBaseToken", + "type": "bool" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ChargeMaintainerFee", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isBaseToken", + "type": "bool" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ChargePenalty", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "baseTokenAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "quoteTokenAmount", + "type": "uint256" + } + ], + "name": "ClaimAssets", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "payer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isBaseToken", + "type": "bool" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "lpTokenAmount", + "type": "uint256" + } + ], + "name": "Deposit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isBaseToken", + "type": "bool" + } + ], + "name": "Donate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferPrepared", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "seller", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "payBase", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "receiveQuote", + "type": "uint256" + } + ], + "name": "SellBaseToken", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldGasPriceLimit", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newGasPriceLimit", + "type": "uint256" + } + ], + "name": "UpdateGasPriceLimit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldK", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newK", + "type": "uint256" + } + ], + "name": "UpdateK", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldLiquidityProviderFeeRate", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newLiquidityProviderFeeRate", + "type": "uint256" + } + ], + "name": "UpdateLiquidityProviderFeeRate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldMaintainerFeeRate", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newMaintainerFeeRate", + "type": "uint256" + } + ], + "name": "UpdateMaintainerFeeRate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "payer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isBaseToken", + "type": "bool" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "lpTokenAmount", + "type": "uint256" + } + ], + "name": "Withdraw", + "type": "event" + }, + { + "inputs": [], + "name": "_BASE_BALANCE_", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_BASE_CAPITAL_RECEIVE_QUOTE_", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_BASE_CAPITAL_TOKEN_", + "outputs": [{"internalType": "address", "name": "", "type": "address"}], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_BASE_TOKEN_", + "outputs": [{"internalType": "address", "name": "", "type": "address"}], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{"internalType": "address", "name": "", "type": "address"}], + "name": "_CLAIMED_", + "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_CLOSED_", + "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_DEPOSIT_BASE_ALLOWED_", + "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_DEPOSIT_QUOTE_ALLOWED_", + "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_GAS_PRICE_LIMIT_", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_K_", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_LP_FEE_RATE_", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_MAINTAINER_", + "outputs": [{"internalType": "address", "name": "", "type": "address"}], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_MT_FEE_RATE_", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_NEW_OWNER_", + "outputs": [{"internalType": "address", "name": "", "type": "address"}], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_ORACLE_", + "outputs": [{"internalType": "address", "name": "", "type": "address"}], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_OWNER_", + "outputs": [{"internalType": "address", "name": "", "type": "address"}], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_QUOTE_BALANCE_", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_QUOTE_CAPITAL_RECEIVE_BASE_", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_QUOTE_CAPITAL_TOKEN_", + "outputs": [{"internalType": "address", "name": "", "type": "address"}], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_QUOTE_TOKEN_", + "outputs": [{"internalType": "address", "name": "", "type": "address"}], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_R_STATUS_", + "outputs": [ + {"internalType": "enum Types.RStatus", "name": "", "type": "uint8"} + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_SUPERVISOR_", + "outputs": [{"internalType": "address", "name": "", "type": "address"}], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_TARGET_BASE_TOKEN_AMOUNT_", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_TARGET_QUOTE_TOKEN_AMOUNT_", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_TRADE_ALLOWED_", + "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + {"internalType": "uint256", "name": "amount", "type": "uint256"}, + {"internalType": "uint256", "name": "maxPayQuote", "type": "uint256"}, + {"internalType": "bytes", "name": "data", "type": "bytes"} + ], + "name": "buyBaseToken", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "claimAssets", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "claimOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + {"internalType": "uint256", "name": "amount", "type": "uint256"} + ], + "name": "depositBase", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + {"internalType": "address", "name": "to", "type": "address"}, + {"internalType": "uint256", "name": "amount", "type": "uint256"} + ], + "name": "depositBaseTo", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + {"internalType": "uint256", "name": "amount", "type": "uint256"} + ], + "name": "depositQuote", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + {"internalType": "address", "name": "to", "type": "address"}, + {"internalType": "uint256", "name": "amount", "type": "uint256"} + ], + "name": "depositQuoteTo", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "disableBaseDeposit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "disableQuoteDeposit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "disableTrading", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + {"internalType": "uint256", "name": "amount", "type": "uint256"} + ], + "name": "donateBaseToken", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + {"internalType": "uint256", "name": "amount", "type": "uint256"} + ], + "name": "donateQuoteToken", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "enableBaseDeposit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "enableQuoteDeposit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "enableTrading", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalSettlement", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{"internalType": "address", "name": "lp", "type": "address"}], + "name": "getBaseCapitalBalanceOf", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getExpectedTarget", + "outputs": [ + {"internalType": "uint256", "name": "baseTarget", "type": "uint256"}, + {"internalType": "uint256", "name": "quoteTarget", "type": "uint256"} + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{"internalType": "address", "name": "lp", "type": "address"}], + "name": "getLpBaseBalance", + "outputs": [ + {"internalType": "uint256", "name": "lpBalance", "type": "uint256"} + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{"internalType": "address", "name": "lp", "type": "address"}], + "name": "getLpQuoteBalance", + "outputs": [ + {"internalType": "uint256", "name": "lpBalance", "type": "uint256"} + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getMidPrice", + "outputs": [ + {"internalType": "uint256", "name": "midPrice", "type": "uint256"} + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getOraclePrice", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{"internalType": "address", "name": "lp", "type": "address"}], + "name": "getQuoteCapitalBalanceOf", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getTotalBaseCapital", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getTotalQuoteCapital", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + {"internalType": "uint256", "name": "amount", "type": "uint256"} + ], + "name": "getWithdrawBasePenalty", + "outputs": [ + {"internalType": "uint256", "name": "penalty", "type": "uint256"} + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + {"internalType": "uint256", "name": "amount", "type": "uint256"} + ], + "name": "getWithdrawQuotePenalty", + "outputs": [ + {"internalType": "uint256", "name": "penalty", "type": "uint256"} + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + {"internalType": "address", "name": "owner", "type": "address"}, + {"internalType": "address", "name": "supervisor", "type": "address"}, + {"internalType": "address", "name": "maintainer", "type": "address"}, + {"internalType": "address", "name": "baseToken", "type": "address"}, + {"internalType": "address", "name": "quoteToken", "type": "address"}, + {"internalType": "address", "name": "oracle", "type": "address"}, + {"internalType": "uint256", "name": "lpFeeRate", "type": "uint256"}, + {"internalType": "uint256", "name": "mtFeeRate", "type": "uint256"}, + {"internalType": "uint256", "name": "k", "type": "uint256"}, + {"internalType": "uint256", "name": "gasPriceLimit", "type": "uint256"} + ], + "name": "init", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + {"internalType": "uint256", "name": "amount", "type": "uint256"} + ], + "name": "queryBuyBaseToken", + "outputs": [ + {"internalType": "uint256", "name": "payQuote", "type": "uint256"} + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + {"internalType": "uint256", "name": "amount", "type": "uint256"} + ], + "name": "querySellBaseToken", + "outputs": [ + {"internalType": "uint256", "name": "receiveQuote", "type": "uint256"} + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + {"internalType": "address", "name": "token", "type": "address"}, + {"internalType": "uint256", "name": "amount", "type": "uint256"} + ], + "name": "retrieve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + {"internalType": "uint256", "name": "amount", "type": "uint256"}, + {"internalType": "uint256", "name": "minReceiveQuote", "type": "uint256"}, + {"internalType": "bytes", "name": "data", "type": "bytes"} + ], + "name": "sellBaseToken", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + {"internalType": "uint256", "name": "newGasPriceLimit", "type": "uint256"} + ], + "name": "setGasPriceLimit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{"internalType": "uint256", "name": "newK", "type": "uint256"}], + "name": "setK", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newLiquidityPorviderFeeRate", + "type": "uint256" + } + ], + "name": "setLiquidityProviderFeeRate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + {"internalType": "address", "name": "newMaintainer", "type": "address"} + ], + "name": "setMaintainer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newMaintainerFeeRate", + "type": "uint256" + } + ], + "name": "setMaintainerFeeRate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + {"internalType": "address", "name": "newOracle", "type": "address"} + ], + "name": "setOracle", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + {"internalType": "address", "name": "newSupervisor", "type": "address"} + ], + "name": "setSupervisor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + {"internalType": "address", "name": "newOwner", "type": "address"} + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "withdrawAllBase", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{"internalType": "address", "name": "to", "type": "address"}], + "name": "withdrawAllBaseTo", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "withdrawAllQuote", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{"internalType": "address", "name": "to", "type": "address"}], + "name": "withdrawAllQuoteTo", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + {"internalType": "uint256", "name": "amount", "type": "uint256"} + ], + "name": "withdrawBase", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + {"internalType": "address", "name": "to", "type": "address"}, + {"internalType": "uint256", "name": "amount", "type": "uint256"} + ], + "name": "withdrawBaseTo", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + {"internalType": "uint256", "name": "amount", "type": "uint256"} + ], + "name": "withdrawQuote", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + {"internalType": "address", "name": "to", "type": "address"}, + {"internalType": "uint256", "name": "amount", "type": "uint256"} + ], + "name": "withdrawQuoteTo", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/package-lock.json b/package-lock.json index 14c102b..bc64a18 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1649,6 +1649,14 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.0.tgz", "integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA==" }, + "axios": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.20.0.tgz", + "integrity": "sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA==", + "requires": { + "follow-redirects": "^1.10.0" + } + }, "babel-cli": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-cli/-/babel-cli-6.26.0.tgz", @@ -4339,6 +4347,11 @@ } } }, + "follow-redirects": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", + "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==" + }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", diff --git a/package.json b/package.json index 5ab07b1..4c759df 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "@types/es6-promisify": "^6.0.0", "@types/mocha": "^7.0.2", "assert": "^2.0.0", + "axios": "^0.20.0", "babel-cli": "^6.26.0", "babel-eslint": "^10.1.0", "bignumber.js": "^9.0.0", diff --git a/test/Trader.test.ts b/test/Trader.test.ts index 8591724..5e04c6e 100644 --- a/test/Trader.test.ts +++ b/test/Trader.test.ts @@ -52,15 +52,7 @@ describe("Trader", () => { describe("R goes above ONE", () => { it("buy when R equals ONE", async () => { -<<<<<<< Updated upstream - await logGas( - ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110"), "0x"), - ctx.sendParam(trader), - "buy base token when balanced" - ); -======= await logGas(ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110"), "0x"), ctx.sendParam(trader), "buy base token when balanced") ->>>>>>> Stashed changes // trader balances assert.equal( await ctx.BASE.methods.balanceOf(trader).call(), @@ -96,19 +88,8 @@ describe("Trader", () => { }); it("buy when R is ABOVE ONE", async () => { -<<<<<<< Updated upstream - await ctx.DODO.methods - .buyBaseToken(decimalStr("1"), decimalStr("110"), "0x") - .send(ctx.sendParam(trader)); - await logGas( - ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("130"), "0x"), - ctx.sendParam(trader), - "buy when R is ABOVE ONE" - ); -======= await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110"), "0x").send(ctx.sendParam(trader)) await logGas(ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("130"), "0x"), ctx.sendParam(trader), "buy when R is ABOVE ONE") ->>>>>>> Stashed changes // trader balances assert.equal( await ctx.BASE.methods.balanceOf(trader).call(), @@ -139,23 +120,8 @@ describe("Trader", () => { }); it("sell when R is ABOVE ONE", async () => { -<<<<<<< Updated upstream - await ctx.DODO.methods - .buyBaseToken(decimalStr("1"), decimalStr("110"), "0x") - .send(ctx.sendParam(trader)); - await logGas( - ctx.DODO.methods.sellBaseToken( - decimalStr("0.5"), - decimalStr("40"), - "0x" - ), - ctx.sendParam(trader), - "sell when R is ABOVE ONE" - ); -======= await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110"), "0x").send(ctx.sendParam(trader)) await logGas(ctx.DODO.methods.sellBaseToken(decimalStr("0.5"), decimalStr("40"), "0x"), ctx.sendParam(trader), "sell when R is ABOVE ONE") ->>>>>>> Stashed changes // trader balances assert.equal( await ctx.BASE.methods.balanceOf(trader).call(), @@ -186,23 +152,8 @@ describe("Trader", () => { }); it("sell when R is ABOVE ONE and RStatus back to ONE", async () => { -<<<<<<< Updated upstream - await ctx.DODO.methods - .buyBaseToken(decimalStr("1"), decimalStr("110"), "0x") - .send(ctx.sendParam(trader)); - await logGas( - ctx.DODO.methods.sellBaseToken( - "1003002430889317763", - decimalStr("90"), - "0x" - ), - ctx.sendParam(trader), - "sell when R is ABOVE ONE and RStatus back to ONE" - ); -======= await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110"), "0x").send(ctx.sendParam(trader)) await logGas(ctx.DODO.methods.sellBaseToken("1003002430889317763", decimalStr("90"), "0x"), ctx.sendParam(trader), "sell when R is ABOVE ONE and RStatus back to ONE") ->>>>>>> Stashed changes // R status assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0"); // trader balances @@ -244,19 +195,8 @@ describe("Trader", () => { }); it("sell when R is ABOVE ONE and RStatus becomes BELOW ONE", async () => { -<<<<<<< Updated upstream - await ctx.DODO.methods - .buyBaseToken(decimalStr("1"), decimalStr("110"), "0x") - .send(ctx.sendParam(trader)); - await logGas( - ctx.DODO.methods.sellBaseToken(decimalStr("2"), decimalStr("90"), "0x"), - ctx.sendParam(trader), - "sell when R is ABOVE ONE and RStatus becomes BELOW ONE [gas cost worst case]" - ); -======= await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110"), "0x").send(ctx.sendParam(trader)) await logGas(ctx.DODO.methods.sellBaseToken(decimalStr("2"), decimalStr("90"), "0x"), ctx.sendParam(trader), "sell when R is ABOVE ONE and RStatus becomes BELOW ONE [gas cost worst case]") ->>>>>>> Stashed changes // R status assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "2"); // trader balances @@ -300,15 +240,7 @@ describe("Trader", () => { describe("R goes below ONE", () => { it("sell when R equals ONE", async () => { -<<<<<<< Updated upstream - await logGas( - ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90"), "0x"), - ctx.sendParam(trader), - "sell base token when balanced" - ); -======= await logGas(ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90"), "0x"), ctx.sendParam(trader), "sell base token when balanced") ->>>>>>> Stashed changes // trader balances assert.equal( await ctx.BASE.methods.balanceOf(trader).call(), @@ -344,19 +276,8 @@ describe("Trader", () => { }); it("sell when R is BELOW ONE", async () => { -<<<<<<< Updated upstream - await ctx.DODO.methods - .sellBaseToken(decimalStr("3"), decimalStr("90"), "0x") - .send(ctx.sendParam(trader)); - await logGas( - ctx.DODO.methods.sellBaseToken(decimalStr("3"), decimalStr("90"), "0x"), - ctx.sendParam(trader), - "sell when R is BELOW ONE" - ); -======= await ctx.DODO.methods.sellBaseToken(decimalStr("3"), decimalStr("90"), "0x").send(ctx.sendParam(trader)) await logGas(ctx.DODO.methods.sellBaseToken(decimalStr("3"), decimalStr("90"), "0x"), ctx.sendParam(trader), "sell when R is BELOW ONE") ->>>>>>> Stashed changes // trader balances assert.equal( await ctx.BASE.methods.balanceOf(trader).call(), @@ -387,23 +308,8 @@ describe("Trader", () => { }); it("buy when R is BELOW ONE", async () => { -<<<<<<< Updated upstream - await ctx.DODO.methods - .sellBaseToken(decimalStr("1"), decimalStr("90"), "0x") - .send(ctx.sendParam(trader)); - await logGas( - ctx.DODO.methods.buyBaseToken( - decimalStr("0.5"), - decimalStr("60"), - "0x" - ), - ctx.sendParam(trader), - "buy when R is BELOW ONE" - ); -======= await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90"), "0x").send(ctx.sendParam(trader)) await logGas(ctx.DODO.methods.buyBaseToken(decimalStr("0.5"), decimalStr("60"), "0x"), ctx.sendParam(trader), "buy when R is BELOW ONE") ->>>>>>> Stashed changes // trader balances assert.equal( await ctx.BASE.methods.balanceOf(trader).call(), @@ -434,23 +340,8 @@ describe("Trader", () => { }); it("buy when R is BELOW ONE and RStatus back to ONE", async () => { -<<<<<<< Updated upstream - await ctx.DODO.methods - .sellBaseToken(decimalStr("1"), decimalStr("90"), "0x") - .send(ctx.sendParam(trader)); - await logGas( - ctx.DODO.methods.buyBaseToken( - "997008973080757728", - decimalStr("110"), - "0x" - ), - ctx.sendParam(trader), - "buy when R is BELOW ONE and RStatus back to ONE" - ); -======= await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90"), "0x").send(ctx.sendParam(trader)) await logGas(ctx.DODO.methods.buyBaseToken("997008973080757728", decimalStr("110"), "0x"), ctx.sendParam(trader), "buy when R is BELOW ONE and RStatus back to ONE") ->>>>>>> Stashed changes // R status assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "0"); // trader balances @@ -492,19 +383,8 @@ describe("Trader", () => { }); it("buy when R is BELOW ONE and RStatus becomes ABOVE ONE", async () => { -<<<<<<< Updated upstream - await ctx.DODO.methods - .sellBaseToken(decimalStr("1"), decimalStr("90"), "0x") - .send(ctx.sendParam(trader)); - await logGas( - ctx.DODO.methods.buyBaseToken(decimalStr("2"), decimalStr("220"), "0x"), - ctx.sendParam(trader), - "buy when R is BELOW ONE and RStatus becomes ABOVE ONE [gas cost worst case]" - ); -======= await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90"), "0x").send(ctx.sendParam(trader)) await logGas(ctx.DODO.methods.buyBaseToken(decimalStr("2"), decimalStr("220"), "0x"), ctx.sendParam(trader), "buy when R is BELOW ONE and RStatus becomes ABOVE ONE [gas cost worst case]") ->>>>>>> Stashed changes // R status assert.equal(await ctx.DODO.methods._R_STATUS_().call(), "1"); // trader balances diff --git a/test/utils/Contracts.ts b/test/utils/Contracts.ts index 245f6e3..7a3a01b 100644 --- a/test/utils/Contracts.ts +++ b/test/utils/Contracts.ts @@ -13,7 +13,6 @@ if (process.env["COVERAGE"]) { const CloneFactory = require(`${jsonPath}CloneFactory.json`) const DODO = require(`${jsonPath}DODO.json`) const DODOZoo = require(`${jsonPath}DODOZoo.json`) -// const DODOWild = require(`${jsonPath}DODOWild.json`) const DODOEthProxy = require(`${jsonPath}DODOEthProxy.json`) const WETH = require(`${jsonPath}WETH9.json`) const TestERC20 = require(`${jsonPath}TestERC20.json`) @@ -22,6 +21,7 @@ const DODOLpToken = require(`${jsonPath}DODOLpToken.json`) const Uniswap = require(`${jsonPath}UniswapV2Pair.json`) const UniswapArbitrageur = require(`${jsonPath}UniswapArbitrageur.json`) const DODOToken = require(`${jsonPath}DODOToken.json`) +const DODOMine = require(`${jsonPath}DODOMine.json`) const LockedTokenVault = require(`${jsonPath}LockedTokenVault.json`) import { getDefaultWeb3 } from './EVM'; @@ -40,6 +40,7 @@ export const UNISWAP_CONTRACT_NAME = "Uniswap" export const UNISWAP_ARBITRAGEUR_CONTRACT_NAME = "UniswapArbitrageur" export const DODO_TOKEN_CONTRACT_NAME = "DODOToken" export const LOCKED_TOKEN_VAULT_CONTRACT_NAME = "LockedTokenVault" +export const DODO_MINE_NAME = "DODOMine" var contractMap: { [name: string]: any } = {} contractMap[CLONE_FACTORY_CONTRACT_NAME] = CloneFactory @@ -54,6 +55,7 @@ contractMap[UNISWAP_CONTRACT_NAME] = Uniswap contractMap[UNISWAP_ARBITRAGEUR_CONTRACT_NAME] = UniswapArbitrageur contractMap[DODO_TOKEN_CONTRACT_NAME] = DODOToken contractMap[LOCKED_TOKEN_VAULT_CONTRACT_NAME] = LockedTokenVault +contractMap[DODO_MINE_NAME] = DODOMine interface ContractJson { abi: any; From 5f10f065e461d66517d75f9cdbc57e446327a231 Mon Sep 17 00:00:00 2001 From: mingda Date: Sun, 4 Oct 2020 10:47:47 +0800 Subject: [PATCH 094/118] DODO Mine reward vault & reader --- contracts/intf/IDODO.sol | 7 +++-- contracts/token/DODOMine.sol | 9 +++--- contracts/token/DODOMineReader.sol | 44 +++++++++++++++++++++++++++++ contracts/token/DODORewardVault.sol | 33 ++++++++++++++++++++++ contracts/token/DODOToken.sol | 2 +- test/Mining.test.ts | 18 ++++++++---- test/utils/Contracts.ts | 3 ++ 7 files changed, 104 insertions(+), 12 deletions(-) create mode 100644 contracts/token/DODOMineReader.sol create mode 100644 contracts/token/DODORewardVault.sol diff --git a/contracts/intf/IDODO.sol b/contracts/intf/IDODO.sol index fe273da..4b1f6cc 100644 --- a/contracts/intf/IDODO.sol +++ b/contracts/intf/IDODO.sol @@ -8,6 +8,7 @@ pragma solidity 0.6.9; pragma experimental ABIEncoderV2; + interface IDODO { function init( address owner, @@ -42,6 +43,8 @@ interface IDODO { function queryBuyBaseToken(uint256 amount) external view returns (uint256 payQuote); + function getExpectedTarget() external view returns (uint256 baseTarget, uint256 quoteTarget); + function depositBaseTo(address to, uint256 amount) external returns (uint256); function withdrawBase(uint256 amount) external returns (uint256); @@ -54,9 +57,9 @@ interface IDODO { function withdrawAllQuote() external returns (uint256); - function _BASE_CAPITAL_TOKEN_() external returns (address); + function _BASE_CAPITAL_TOKEN_() external view returns (address); - function _QUOTE_CAPITAL_TOKEN_() external returns (address); + function _QUOTE_CAPITAL_TOKEN_() external view returns (address); function _BASE_TOKEN_() external returns (address); diff --git a/contracts/token/DODOMine.sol b/contracts/token/DODOMine.sol index 8734c9f..699c0fb 100644 --- a/contracts/token/DODOMine.sol +++ b/contracts/token/DODOMine.sol @@ -13,6 +13,7 @@ import {DecimalMath} from "../lib/DecimalMath.sol"; import {SafeERC20} from "../lib/SafeERC20.sol"; import {SafeMath} from "../lib/SafeMath.sol"; import {IERC20} from "../intf/IERC20.sol"; +import {IDODORewardVault, DODORewardVault} from "./DODORewardVault.sol"; contract DODOMine is Ownable { @@ -44,7 +45,7 @@ contract DODOMine is Ownable { uint256 accDODOPerShare; // Accumulated DODOs per share, times 1e12. See below. } - address public dodoToken; + address public dodoRewardVault; uint256 public dodoPerBlock; // Info of each pool. @@ -65,7 +66,7 @@ contract DODOMine is Ownable { event Claim(address indexed user, uint256 amount); constructor(address _dodoToken, uint256 _startBlock) public { - dodoToken = _dodoToken; + dodoRewardVault = address(new DODORewardVault(_dodoToken)); startBlock = _startBlock; } @@ -307,9 +308,9 @@ contract DODOMine is Ownable { safeDODOTransfer(msg.sender, pending); } - // Safe DODO transfer function, just in case if rounding error causes pool to not have enough DODOs. + // Safe DODO transfer function function safeDODOTransfer(address _to, uint256 _amount) internal { - IERC20(dodoToken).safeTransfer(_to, _amount); + IDODORewardVault(dodoRewardVault).reward(_to, _amount); realizedReward[_to] = realizedReward[_to].add(_amount); emit Claim(_to, _amount); } diff --git a/contracts/token/DODOMineReader.sol b/contracts/token/DODOMineReader.sol new file mode 100644 index 0000000..f5ee9a4 --- /dev/null +++ b/contracts/token/DODOMineReader.sol @@ -0,0 +1,44 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {IDODO} from "../intf/IDODO.sol"; +import {IERC20} from "../intf/IERC20.sol"; +import {SafeMath} from "../lib/SafeMath.sol"; + + +interface IDODOMine { + function getUserLpBalance(address _lpToken, address _user) external view returns (uint256); +} + + +contract DODOMineReader { + using SafeMath for uint256; + + function getUserStakedBalance( + address _dodoMine, + address _dodo, + address _user + ) external view returns (uint256 baseBalance, uint256 quoteBalance) { + address baseLpToken = IDODO(_dodo)._BASE_CAPITAL_TOKEN_(); + address quoteLpToken = IDODO(_dodo)._QUOTE_CAPITAL_TOKEN_(); + + uint256 baseLpBalance = IDODOMine(_dodoMine).getUserLpBalance(baseLpToken, _user); + uint256 quoteLpBalance = IDODOMine(_dodoMine).getUserLpBalance(quoteLpToken, _user); + + uint256 baseLpTotalSupply = IERC20(baseLpToken).totalSupply(); + uint256 quoteLpTotalSupply = IERC20(quoteLpToken).totalSupply(); + + (uint256 baseTarget, uint256 quoteTarget) = IDODO(_dodo).getExpectedTarget(); + baseBalance = baseTarget.mul(baseLpBalance).div(baseLpTotalSupply); + quoteBalance = quoteTarget.mul(quoteLpBalance).div(quoteLpTotalSupply); + + return (baseBalance, quoteBalance); + } +} diff --git a/contracts/token/DODORewardVault.sol b/contracts/token/DODORewardVault.sol new file mode 100644 index 0000000..1942c46 --- /dev/null +++ b/contracts/token/DODORewardVault.sol @@ -0,0 +1,33 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {Ownable} from "../lib/Ownable.sol"; +import {SafeERC20} from "../lib/SafeERC20.sol"; +import {IERC20} from "../intf/IERC20.sol"; + + +interface IDODORewardVault { + function reward(address to, uint256 amount) external; +} + + +contract DODORewardVault is Ownable { + using SafeERC20 for IERC20; + + address public dodoToken; + + constructor(address _dodoToken) public { + dodoToken = _dodoToken; + } + + function reward(address to, uint256 amount) external onlyOwner { + IERC20(dodoToken).safeTransfer(to, amount); + } +} diff --git a/contracts/token/DODOToken.sol b/contracts/token/DODOToken.sol index 672611f..da51b1f 100644 --- a/contracts/token/DODOToken.sol +++ b/contracts/token/DODOToken.sol @@ -19,7 +19,7 @@ contract DODOToken { using SafeMath for uint256; string public symbol = "DODO"; - string public name = "DODO bird food"; + string public name = "DODO bird"; uint256 public decimals = 18; uint256 public totalSupply = 1000000000 * 10**18; // 1 Billion diff --git a/test/Mining.test.ts b/test/Mining.test.ts index 917e7c0..9b04679 100644 --- a/test/Mining.test.ts +++ b/test/Mining.test.ts @@ -8,7 +8,7 @@ import { DODOContext, getDODOContext } from './utils/Context'; import { decimalStr, MAX_UINT256 } from './utils/Converter'; // import * as assert from "assert" -import { newContract, DODO_TOKEN_CONTRACT_NAME, DODO_MINE_NAME, TEST_ERC20_CONTRACT_NAME, getContractWithAddress } from './utils/Contracts'; +import { newContract, DODO_TOKEN_CONTRACT_NAME, DODO_MINE_NAME, TEST_ERC20_CONTRACT_NAME, getContractWithAddress, DODO_MINE_READER_NAME } from './utils/Contracts'; import { Contract } from 'web3-eth-contract'; import { assert } from 'chai'; import { logGas } from './utils/Log'; @@ -17,6 +17,7 @@ let BaseDLP: Contract let QuoteDLP: Contract let DODOToken: Contract let DODOMine: Contract +let DODOMineReader: Contract let lp1: string; let lp2: string; @@ -38,6 +39,7 @@ async function init(ctx: DODOContext): Promise { DODOToken = await newContract(DODO_TOKEN_CONTRACT_NAME) DODOMine = await newContract(DODO_MINE_NAME, [DODOToken.options.address, (await ctx.Web3.eth.getBlockNumber()).toString()]) + DODOMineReader = await newContract(DODO_MINE_READER_NAME) BaseDLP = await getContractWithAddress(TEST_ERC20_CONTRACT_NAME, await ctx.DODO.methods._BASE_CAPITAL_TOKEN_().call()) QuoteDLP = await getContractWithAddress(TEST_ERC20_CONTRACT_NAME, await ctx.DODO.methods._QUOTE_CAPITAL_TOKEN_().call()) @@ -48,10 +50,12 @@ async function init(ctx: DODOContext): Promise { await BaseDLP.methods.approve(DODOMine.options.address, MAX_UINT256).send(ctx.sendParam(lp2)) await QuoteDLP.methods.approve(DODOMine.options.address, MAX_UINT256).send(ctx.sendParam(lp2)) - await DODOMine.methods.setReward(decimalStr("100")).send(ctx.sendParam(ctx.Deployer)) + await DODOMine.methods.setReward(decimalStr("100"), true).send(ctx.sendParam(ctx.Deployer)) await DODOMine.methods.addLpToken(BaseDLP.options.address, "1", true).send(ctx.sendParam(ctx.Deployer)) await DODOMine.methods.addLpToken(QuoteDLP.options.address, "2", true).send(ctx.sendParam(ctx.Deployer)) - await DODOToken.methods.transfer(DODOMine.options.address, decimalStr("100000000")).send(ctx.sendParam(ctx.Deployer)) + + const rewardVault = await DODOMine.methods.dodoRewardVault().call() + await DODOToken.methods.transfer(rewardVault, decimalStr("100000000")).send(ctx.sendParam(ctx.Deployer)) } describe("Lock DODO Token", () => { @@ -73,7 +77,7 @@ describe("Lock DODO Token", () => { }); describe("Lp Deposit", () => { - it.only("single lp deposit", async () => { + it("single lp deposit", async () => { await logGas(DODOMine.methods.deposit(BaseDLP.options.address, decimalStr("100")), ctx.sendParam(lp1), "deposit") await ctx.EVM.fastMove(100) assert.equal(await DODOMine.methods.getPendingReward(BaseDLP.options.address, lp1).call(), "3333333333333333333300") @@ -99,7 +103,7 @@ describe("Lock DODO Token", () => { assert.equal(await DODOMine.methods.getAllPendingReward(lp2).call(), "8366666666666666666600") }) - it("lp multi deposit and withdraw", async () => { + it.only("lp multi deposit and withdraw", async () => { await DODOMine.methods.deposit(BaseDLP.options.address, decimalStr("100")).send(ctx.sendParam(lp2)) await DODOMine.methods.deposit(BaseDLP.options.address, decimalStr("100")).send(ctx.sendParam(lp1)) await ctx.EVM.fastMove(100) @@ -112,6 +116,10 @@ describe("Lock DODO Token", () => { assert.equal(await DODOMine.methods.getAllPendingReward(lp1).call(), "0") assert.equal(await DODOToken.methods.balanceOf(lp1).call(), "2805555555555555555500") assert.equal(await DODOMine.methods.getRealizedReward(lp1).call(), "2805555555555555555500") + + var balance = await DODOMineReader.methods.getUserStakedBalance(DODOMine.options.address, ctx.DODO.options.address, lp1).call() + assert.equal(balance.baseBalance, decimalStr("100")) + assert.equal(balance.quoteBalance, decimalStr("0")) }) it("lp claim", async () => { diff --git a/test/utils/Contracts.ts b/test/utils/Contracts.ts index 7a3a01b..d89d28c 100644 --- a/test/utils/Contracts.ts +++ b/test/utils/Contracts.ts @@ -22,6 +22,7 @@ const Uniswap = require(`${jsonPath}UniswapV2Pair.json`) const UniswapArbitrageur = require(`${jsonPath}UniswapArbitrageur.json`) const DODOToken = require(`${jsonPath}DODOToken.json`) const DODOMine = require(`${jsonPath}DODOMine.json`) +const DODOMineReader = require(`${jsonPath}DODOMineReader.json`) const LockedTokenVault = require(`${jsonPath}LockedTokenVault.json`) import { getDefaultWeb3 } from './EVM'; @@ -41,6 +42,7 @@ export const UNISWAP_ARBITRAGEUR_CONTRACT_NAME = "UniswapArbitrageur" export const DODO_TOKEN_CONTRACT_NAME = "DODOToken" export const LOCKED_TOKEN_VAULT_CONTRACT_NAME = "LockedTokenVault" export const DODO_MINE_NAME = "DODOMine" +export const DODO_MINE_READER_NAME = "DODOMineReader" var contractMap: { [name: string]: any } = {} contractMap[CLONE_FACTORY_CONTRACT_NAME] = CloneFactory @@ -56,6 +58,7 @@ contractMap[UNISWAP_ARBITRAGEUR_CONTRACT_NAME] = UniswapArbitrageur contractMap[DODO_TOKEN_CONTRACT_NAME] = DODOToken contractMap[LOCKED_TOKEN_VAULT_CONTRACT_NAME] = LockedTokenVault contractMap[DODO_MINE_NAME] = DODOMine +contractMap[DODO_MINE_READER_NAME] = DODOMineReader interface ContractJson { abi: any; From e8182dd1a13c5505e3edef7f4efe8becbcaab12b Mon Sep 17 00:00:00 2001 From: mingda Date: Fri, 23 Oct 2020 01:16:52 +0800 Subject: [PATCH 095/118] restruct contract repo --- contracts/DODOEthProxy.sol | 303 --------------- contracts/{token => DODOToken}/DODOMine.sol | 0 .../{token => DODOToken}/DODORewardVault.sol | 0 contracts/{token => DODOToken}/DODOToken.sol | 0 .../{token => DODOToken}/LockedTokenVault.sol | 0 contracts/DODOVenderMachine/DVMFactory.sol | 51 +++ contracts/DODOVenderMachine/impl/DVMAdmin.sol | 19 + .../DODOVenderMachine/impl/DVMController.sol | 38 ++ .../DODOVenderMachine/impl/DVMFunding.sol | 69 ++++ .../DODOVenderMachine/impl/DVMStorage.sol | 75 ++++ .../DODOVenderMachine/impl/DVMTrader.sol | 69 ++++ contracts/DODOVenderMachine/impl/DVMVault.sol | 205 +++++++++++ contracts/DODOZoo.sol | 134 ------- contracts/dodo.sol | 74 ---- .../ERC20/NormalERC20.sol} | 2 +- .../{helper => external/ERC20}/TestWETH.sol | 0 .../uniswap}/UniswapV2.sol | 8 +- .../helper/BandBNBBUSDPriceOracleProxy.sol | 30 -- .../ChainlinkCOMPUSDCPriceOracleProxy.sol | 25 -- .../ChainlinkEthUSDCPriceOracleProxy.sol | 25 -- .../ChainlinkEthUSDTPriceOracleProxy.sol | 25 -- .../ChainlinkLENDUSDCPriceOracleProxy.sol | 25 -- .../ChainlinkLINKUSDPriceOracleProxy.sol | 25 -- .../ChainlinkSNXUSDPriceOracleProxy.sol | 25 -- .../ChainlinkWBTCUSDCPriceOracleProxy.sol | 25 -- .../ChainlinkYFIUSDCPriceOracleProxy.sol | 32 -- contracts/helper/ConstFeeRateModel.sol | 23 ++ contracts/helper/ConstOracle.sol | 22 -- contracts/helper/MinimumOracle.sol | 56 --- contracts/helper/NaiveFeeRateModel.sol | 28 ++ contracts/helper/NaiveOracle.sol | 25 -- contracts/helper/UniswapArbitrageur.sol | 165 --------- contracts/impl/Admin.sol | 122 ------- contracts/impl/DODOLpToken.sol | 134 ------- contracts/impl/LiquidityProvider.sol | 345 ------------------ contracts/impl/Pricing.sol | 198 ---------- contracts/impl/Settlement.sol | 163 --------- contracts/impl/Storage.sol | 118 ------ contracts/impl/Trader.sol | 274 -------------- contracts/intf/IDODO.sol | 67 ---- contracts/intf/IDODOCallee.sol | 18 - contracts/intf/IDODOLpToken.sol | 20 - contracts/intf/IERC20.sol | 2 + .../{lib/Types.sol => intf/IFeeRateModel.sol} | 5 +- contracts/intf/IVault.sol | 15 + contracts/{helper => lib}/CloneFactory.sol | 0 contracts/lib/DecimalMath.sol | 4 + contracts/lib/InitializableOwnable.sol | 15 +- contracts/lib/PermissionManager.sol | 53 +++ .../MultiSigWalletWithTimelock.sol} | 0 contracts/token/DODOMineReader.sol | 44 --- test/Rebalance.test.ts | 101 +++++ test/utils/Contracts.ts | 49 +-- 53 files changed, 775 insertions(+), 2575 deletions(-) delete mode 100644 contracts/DODOEthProxy.sol rename contracts/{token => DODOToken}/DODOMine.sol (100%) rename contracts/{token => DODOToken}/DODORewardVault.sol (100%) rename contracts/{token => DODOToken}/DODOToken.sol (100%) rename contracts/{token => DODOToken}/LockedTokenVault.sol (100%) create mode 100644 contracts/DODOVenderMachine/DVMFactory.sol create mode 100644 contracts/DODOVenderMachine/impl/DVMAdmin.sol create mode 100644 contracts/DODOVenderMachine/impl/DVMController.sol create mode 100644 contracts/DODOVenderMachine/impl/DVMFunding.sol create mode 100644 contracts/DODOVenderMachine/impl/DVMStorage.sol create mode 100644 contracts/DODOVenderMachine/impl/DVMTrader.sol create mode 100644 contracts/DODOVenderMachine/impl/DVMVault.sol delete mode 100644 contracts/DODOZoo.sol delete mode 100644 contracts/dodo.sol rename contracts/{helper/TestERC20.sol => external/ERC20/NormalERC20.sol} (97%) rename contracts/{helper => external/ERC20}/TestWETH.sol (100%) rename contracts/{helper => external/uniswap}/UniswapV2.sol (98%) delete mode 100644 contracts/helper/BandBNBBUSDPriceOracleProxy.sol delete mode 100644 contracts/helper/ChainlinkCOMPUSDCPriceOracleProxy.sol delete mode 100644 contracts/helper/ChainlinkEthUSDCPriceOracleProxy.sol delete mode 100644 contracts/helper/ChainlinkEthUSDTPriceOracleProxy.sol delete mode 100644 contracts/helper/ChainlinkLENDUSDCPriceOracleProxy.sol delete mode 100644 contracts/helper/ChainlinkLINKUSDPriceOracleProxy.sol delete mode 100644 contracts/helper/ChainlinkSNXUSDPriceOracleProxy.sol delete mode 100644 contracts/helper/ChainlinkWBTCUSDCPriceOracleProxy.sol delete mode 100644 contracts/helper/ChainlinkYFIUSDCPriceOracleProxy.sol create mode 100644 contracts/helper/ConstFeeRateModel.sol delete mode 100644 contracts/helper/ConstOracle.sol delete mode 100644 contracts/helper/MinimumOracle.sol create mode 100644 contracts/helper/NaiveFeeRateModel.sol delete mode 100644 contracts/helper/NaiveOracle.sol delete mode 100644 contracts/helper/UniswapArbitrageur.sol delete mode 100644 contracts/impl/Admin.sol delete mode 100644 contracts/impl/DODOLpToken.sol delete mode 100644 contracts/impl/LiquidityProvider.sol delete mode 100644 contracts/impl/Pricing.sol delete mode 100644 contracts/impl/Settlement.sol delete mode 100644 contracts/impl/Storage.sol delete mode 100644 contracts/impl/Trader.sol delete mode 100644 contracts/intf/IDODO.sol delete mode 100644 contracts/intf/IDODOCallee.sol delete mode 100644 contracts/intf/IDODOLpToken.sol rename contracts/{lib/Types.sol => intf/IFeeRateModel.sol} (57%) create mode 100644 contracts/intf/IVault.sol rename contracts/{helper => lib}/CloneFactory.sol (100%) create mode 100644 contracts/lib/PermissionManager.sol rename contracts/{helper/MultiSig.sol => multisig/MultiSigWalletWithTimelock.sol} (100%) delete mode 100644 contracts/token/DODOMineReader.sol create mode 100644 test/Rebalance.test.ts diff --git a/contracts/DODOEthProxy.sol b/contracts/DODOEthProxy.sol deleted file mode 100644 index aebaa52..0000000 --- a/contracts/DODOEthProxy.sol +++ /dev/null @@ -1,303 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - -import {ReentrancyGuard} from "./lib/ReentrancyGuard.sol"; -import {SafeERC20} from "./lib/SafeERC20.sol"; -import {SafeMath} from "./lib/SafeMath.sol"; -import {IDODO} from "./intf/IDODO.sol"; -import {IERC20} from "./intf/IERC20.sol"; -import {IWETH} from "./intf/IWETH.sol"; - -interface IDODOZoo { - function getDODO(address baseToken, address quoteToken) external view returns (address); -} - -/** - * @title DODO Eth Proxy - * @author DODO Breeder - * - * @notice Handle ETH-WETH converting for users. - */ -contract DODOEthProxy is ReentrancyGuard { - using SafeERC20 for IERC20; - using SafeMath for uint256; - - address public _DODO_ZOO_; - address payable public _WETH_; - - // ============ Events ============ - - event ProxySellEthToToken( - address indexed seller, - address indexed quoteToken, - uint256 payEth, - uint256 receiveToken - ); - - event ProxyBuyEthWithToken( - address indexed buyer, - address indexed quoteToken, - uint256 receiveEth, - uint256 payToken - ); - - event ProxySellTokenToEth( - address indexed seller, - address indexed baseToken, - uint256 payToken, - uint256 receiveEth - ); - - event ProxyBuyTokenWithEth( - address indexed buyer, - address indexed baseToken, - uint256 receiveToken, - uint256 payEth - ); - - event ProxyDepositEthAsBase(address indexed lp, address indexed DODO, uint256 ethAmount); - - event ProxyWithdrawEthAsBase(address indexed lp, address indexed DODO, uint256 ethAmount); - - event ProxyDepositEthAsQuote(address indexed lp, address indexed DODO, uint256 ethAmount); - - event ProxyWithdrawEthAsQuote(address indexed lp, address indexed DODO, uint256 ethAmount); - - // ============ Functions ============ - - constructor(address dodoZoo, address payable weth) public { - _DODO_ZOO_ = dodoZoo; - _WETH_ = weth; - } - - fallback() external payable { - require(msg.sender == _WETH_, "WE_SAVED_YOUR_ETH_:)"); - } - - receive() external payable { - require(msg.sender == _WETH_, "WE_SAVED_YOUR_ETH_:)"); - } - - function sellEthToToken( - address quoteTokenAddress, - uint256 ethAmount, - uint256 minReceiveTokenAmount - ) external payable preventReentrant returns (uint256 receiveTokenAmount) { - require(msg.value == ethAmount, "ETH_AMOUNT_NOT_MATCH"); - address DODO = IDODOZoo(_DODO_ZOO_).getDODO(_WETH_, quoteTokenAddress); - require(DODO != address(0), "DODO_NOT_EXIST"); - IWETH(_WETH_).deposit{value: ethAmount}(); - IWETH(_WETH_).approve(DODO, ethAmount); - receiveTokenAmount = IDODO(DODO).sellBaseToken(ethAmount, minReceiveTokenAmount, ""); - _transferOut(quoteTokenAddress, msg.sender, receiveTokenAmount); - emit ProxySellEthToToken(msg.sender, quoteTokenAddress, ethAmount, receiveTokenAmount); - return receiveTokenAmount; - } - - function buyEthWithToken( - address quoteTokenAddress, - uint256 ethAmount, - uint256 maxPayTokenAmount - ) external preventReentrant returns (uint256 payTokenAmount) { - address DODO = IDODOZoo(_DODO_ZOO_).getDODO(_WETH_, quoteTokenAddress); - require(DODO != address(0), "DODO_NOT_EXIST"); - payTokenAmount = IDODO(DODO).queryBuyBaseToken(ethAmount); - _transferIn(quoteTokenAddress, msg.sender, payTokenAmount); - IERC20(quoteTokenAddress).safeApprove(DODO, payTokenAmount); - IDODO(DODO).buyBaseToken(ethAmount, maxPayTokenAmount, ""); - IWETH(_WETH_).withdraw(ethAmount); - msg.sender.transfer(ethAmount); - emit ProxyBuyEthWithToken(msg.sender, quoteTokenAddress, ethAmount, payTokenAmount); - return payTokenAmount; - } - - function sellTokenToEth( - address baseTokenAddress, - uint256 tokenAmount, - uint256 minReceiveEthAmount - ) external preventReentrant returns (uint256 receiveEthAmount) { - address DODO = IDODOZoo(_DODO_ZOO_).getDODO(baseTokenAddress, _WETH_); - require(DODO != address(0), "DODO_NOT_EXIST"); - IERC20(baseTokenAddress).safeApprove(DODO, tokenAmount); - _transferIn(baseTokenAddress, msg.sender, tokenAmount); - receiveEthAmount = IDODO(DODO).sellBaseToken(tokenAmount, minReceiveEthAmount, ""); - IWETH(_WETH_).withdraw(receiveEthAmount); - msg.sender.transfer(receiveEthAmount); - emit ProxySellTokenToEth(msg.sender, baseTokenAddress, tokenAmount, receiveEthAmount); - return receiveEthAmount; - } - - function buyTokenWithEth( - address baseTokenAddress, - uint256 tokenAmount, - uint256 maxPayEthAmount - ) external payable preventReentrant returns (uint256 payEthAmount) { - require(msg.value == maxPayEthAmount, "ETH_AMOUNT_NOT_MATCH"); - address DODO = IDODOZoo(_DODO_ZOO_).getDODO(baseTokenAddress, _WETH_); - require(DODO != address(0), "DODO_NOT_EXIST"); - payEthAmount = IDODO(DODO).queryBuyBaseToken(tokenAmount); - IWETH(_WETH_).deposit{value: payEthAmount}(); - IWETH(_WETH_).approve(DODO, payEthAmount); - IDODO(DODO).buyBaseToken(tokenAmount, maxPayEthAmount, ""); - _transferOut(baseTokenAddress, msg.sender, tokenAmount); - uint256 refund = maxPayEthAmount.sub(payEthAmount); - if (refund > 0) { - msg.sender.transfer(refund); - } - emit ProxyBuyTokenWithEth(msg.sender, baseTokenAddress, tokenAmount, payEthAmount); - return payEthAmount; - } - - function depositEthAsBase(uint256 ethAmount, address quoteTokenAddress) - external - payable - preventReentrant - { - require(msg.value == ethAmount, "ETH_AMOUNT_NOT_MATCH"); - address DODO = IDODOZoo(_DODO_ZOO_).getDODO(_WETH_, quoteTokenAddress); - require(DODO != address(0), "DODO_NOT_EXIST"); - IWETH(_WETH_).deposit{value: ethAmount}(); - IWETH(_WETH_).approve(DODO, ethAmount); - IDODO(DODO).depositBaseTo(msg.sender, ethAmount); - emit ProxyDepositEthAsBase(msg.sender, DODO, ethAmount); - } - - function withdrawEthAsBase(uint256 ethAmount, address quoteTokenAddress) - external - preventReentrant - returns (uint256 withdrawAmount) - { - address DODO = IDODOZoo(_DODO_ZOO_).getDODO(_WETH_, quoteTokenAddress); - require(DODO != address(0), "DODO_NOT_EXIST"); - address ethLpToken = IDODO(DODO)._BASE_CAPITAL_TOKEN_(); - - // transfer all pool shares to proxy - uint256 lpBalance = IERC20(ethLpToken).balanceOf(msg.sender); - IERC20(ethLpToken).transferFrom(msg.sender, address(this), lpBalance); - IDODO(DODO).withdrawBase(ethAmount); - - // transfer remain shares back to msg.sender - lpBalance = IERC20(ethLpToken).balanceOf(address(this)); - IERC20(ethLpToken).transfer(msg.sender, lpBalance); - - // because of withdraw penalty, withdrawAmount may not equal to ethAmount - // query weth amount first and than transfer ETH to msg.sender - uint256 wethAmount = IERC20(_WETH_).balanceOf(address(this)); - IWETH(_WETH_).withdraw(wethAmount); - msg.sender.transfer(wethAmount); - emit ProxyWithdrawEthAsBase(msg.sender, DODO, wethAmount); - return wethAmount; - } - - function withdrawAllEthAsBase(address quoteTokenAddress) - external - preventReentrant - returns (uint256 withdrawAmount) - { - address DODO = IDODOZoo(_DODO_ZOO_).getDODO(_WETH_, quoteTokenAddress); - require(DODO != address(0), "DODO_NOT_EXIST"); - address ethLpToken = IDODO(DODO)._BASE_CAPITAL_TOKEN_(); - - // transfer all pool shares to proxy - uint256 lpBalance = IERC20(ethLpToken).balanceOf(msg.sender); - IERC20(ethLpToken).transferFrom(msg.sender, address(this), lpBalance); - IDODO(DODO).withdrawAllBase(); - - // because of withdraw penalty, withdrawAmount may not equal to ethAmount - // query weth amount first and than transfer ETH to msg.sender - uint256 wethAmount = IERC20(_WETH_).balanceOf(address(this)); - IWETH(_WETH_).withdraw(wethAmount); - msg.sender.transfer(wethAmount); - emit ProxyWithdrawEthAsBase(msg.sender, DODO, wethAmount); - return wethAmount; - } - - function depositEthAsQuote(uint256 ethAmount, address baseTokenAddress) - external - payable - preventReentrant - { - require(msg.value == ethAmount, "ETH_AMOUNT_NOT_MATCH"); - address DODO = IDODOZoo(_DODO_ZOO_).getDODO(baseTokenAddress, _WETH_); - require(DODO != address(0), "DODO_NOT_EXIST"); - IWETH(_WETH_).deposit{value: ethAmount}(); - IWETH(_WETH_).approve(DODO, ethAmount); - IDODO(DODO).depositQuoteTo(msg.sender, ethAmount); - emit ProxyDepositEthAsQuote(msg.sender, DODO, ethAmount); - } - - function withdrawEthAsQuote(uint256 ethAmount, address baseTokenAddress) - external - preventReentrant - returns (uint256 withdrawAmount) - { - address DODO = IDODOZoo(_DODO_ZOO_).getDODO(baseTokenAddress, _WETH_); - require(DODO != address(0), "DODO_NOT_EXIST"); - address ethLpToken = IDODO(DODO)._QUOTE_CAPITAL_TOKEN_(); - - // transfer all pool shares to proxy - uint256 lpBalance = IERC20(ethLpToken).balanceOf(msg.sender); - IERC20(ethLpToken).transferFrom(msg.sender, address(this), lpBalance); - IDODO(DODO).withdrawQuote(ethAmount); - - // transfer remain shares back to msg.sender - lpBalance = IERC20(ethLpToken).balanceOf(address(this)); - IERC20(ethLpToken).transfer(msg.sender, lpBalance); - - // because of withdraw penalty, withdrawAmount may not equal to ethAmount - // query weth amount first and than transfer ETH to msg.sender - uint256 wethAmount = IERC20(_WETH_).balanceOf(address(this)); - IWETH(_WETH_).withdraw(wethAmount); - msg.sender.transfer(wethAmount); - emit ProxyWithdrawEthAsQuote(msg.sender, DODO, wethAmount); - return wethAmount; - } - - function withdrawAllEthAsQuote(address baseTokenAddress) - external - preventReentrant - returns (uint256 withdrawAmount) - { - address DODO = IDODOZoo(_DODO_ZOO_).getDODO(baseTokenAddress, _WETH_); - require(DODO != address(0), "DODO_NOT_EXIST"); - address ethLpToken = IDODO(DODO)._QUOTE_CAPITAL_TOKEN_(); - - // transfer all pool shares to proxy - uint256 lpBalance = IERC20(ethLpToken).balanceOf(msg.sender); - IERC20(ethLpToken).transferFrom(msg.sender, address(this), lpBalance); - IDODO(DODO).withdrawAllQuote(); - - // because of withdraw penalty, withdrawAmount may not equal to ethAmount - // query weth amount first and than transfer ETH to msg.sender - uint256 wethAmount = IERC20(_WETH_).balanceOf(address(this)); - IWETH(_WETH_).withdraw(wethAmount); - msg.sender.transfer(wethAmount); - emit ProxyWithdrawEthAsQuote(msg.sender, DODO, wethAmount); - return wethAmount; - } - - // ============ Helper Functions ============ - - function _transferIn( - address tokenAddress, - address from, - uint256 amount - ) internal { - IERC20(tokenAddress).safeTransferFrom(from, address(this), amount); - } - - function _transferOut( - address tokenAddress, - address to, - uint256 amount - ) internal { - IERC20(tokenAddress).safeTransfer(to, amount); - } -} diff --git a/contracts/token/DODOMine.sol b/contracts/DODOToken/DODOMine.sol similarity index 100% rename from contracts/token/DODOMine.sol rename to contracts/DODOToken/DODOMine.sol diff --git a/contracts/token/DODORewardVault.sol b/contracts/DODOToken/DODORewardVault.sol similarity index 100% rename from contracts/token/DODORewardVault.sol rename to contracts/DODOToken/DODORewardVault.sol diff --git a/contracts/token/DODOToken.sol b/contracts/DODOToken/DODOToken.sol similarity index 100% rename from contracts/token/DODOToken.sol rename to contracts/DODOToken/DODOToken.sol diff --git a/contracts/token/LockedTokenVault.sol b/contracts/DODOToken/LockedTokenVault.sol similarity index 100% rename from contracts/token/LockedTokenVault.sol rename to contracts/DODOToken/LockedTokenVault.sol diff --git a/contracts/DODOVenderMachine/DVMFactory.sol b/contracts/DODOVenderMachine/DVMFactory.sol new file mode 100644 index 0000000..178ca7e --- /dev/null +++ b/contracts/DODOVenderMachine/DVMFactory.sol @@ -0,0 +1,51 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {Ownable} from "../lib/Ownable.sol"; +import {ICloneFactory} from "../lib/CloneFactory.sol"; +import {DVMVault} from "./impl/DVMVault.sol"; +import {DVMController} from "./impl/DVMController.sol"; + +contract DVMFactory is Ownable { + address public _CLONE_FACTORY_; + address public _VAULT_TEMPLATE_; + address public _CONTROLLER_TEMPLATE_; + + function createDODOVenderMachine( + address maintainer, + address baseToken, + address quoteToken, + address lpFeeRateModel, + address mtFeeRateModel, + uint256 i, + uint256 k, + uint256 gasPriceLimit + ) external returns (address newVenderMachine) { + DVMController controller = DVMController( + ICloneFactory(_CLONE_FACTORY_).clone(_CONTROLLER_TEMPLATE_) + ); + DVMVault vault = DVMVault(ICloneFactory(_CLONE_FACTORY_).clone(_VAULT_TEMPLATE_)); + vault.init(address(controller), baseToken, quoteToken); // vault owner is controller + + controller.init( + msg.sender, + maintainer, + address(vault), + lpFeeRateModel, + mtFeeRateModel, + i, + k, + gasPriceLimit + ); + + newVenderMachine = address(controller); + return newVenderMachine; + } +} diff --git a/contracts/DODOVenderMachine/impl/DVMAdmin.sol b/contracts/DODOVenderMachine/impl/DVMAdmin.sol new file mode 100644 index 0000000..3738c41 --- /dev/null +++ b/contracts/DODOVenderMachine/impl/DVMAdmin.sol @@ -0,0 +1,19 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {DVMStorage} from "./DVMStorage.sol"; + +contract DVMAdmin is DVMStorage{ + + function setI(uint256 newI) external onlyOwner{} + + function setK(uint256 newK) external onlyOwner{} + +} \ No newline at end of file diff --git a/contracts/DODOVenderMachine/impl/DVMController.sol b/contracts/DODOVenderMachine/impl/DVMController.sol new file mode 100644 index 0000000..26b4920 --- /dev/null +++ b/contracts/DODOVenderMachine/impl/DVMController.sol @@ -0,0 +1,38 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {DVMTrader} from "./DVMTrader.sol"; +import {DVMFunding} from "./DVMFunding.sol"; +import {DVMAdmin} from "./DVMAdmin.sol"; +import {DVMVault} from "./DVMVault.sol"; +import {IFeeRateModel} from "../../intf/IFeeRateModel.sol"; + +contract DVMController is DVMTrader, DVMFunding, DVMAdmin { + function init( + address owner, + address maintainer, + address vault, + address lpFeeRateModel, + address mtFeeRateModel, + uint256 i, + uint256 k, + uint256 gasPriceLimit + ) external { + initOwner(owner); + _MAINTAINER_ = maintainer; + _BASE_TOKEN_ = DVMVault(vault)._BASE_TOKEN_(); + _QUOTE_TOKEN_ = DVMVault(vault)._QUOTE_TOKEN_(); + _LP_FEE_RATE_MODEL_ = IFeeRateModel(lpFeeRateModel); + _MT_FEE_RATE_MODEL_ = IFeeRateModel(mtFeeRateModel); + _I_ = i; + _K_ = k; + _GAS_PRICE_LIMIT_ = gasPriceLimit; + } +} diff --git a/contracts/DODOVenderMachine/impl/DVMFunding.sol b/contracts/DODOVenderMachine/impl/DVMFunding.sol new file mode 100644 index 0000000..34d8f9a --- /dev/null +++ b/contracts/DODOVenderMachine/impl/DVMFunding.sol @@ -0,0 +1,69 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {DVMStorage} from "./DVMStorage.sol"; +import {DecimalMath} from "../../lib/DecimalMath.sol"; + +contract DVMFunding is DVMStorage { + function buyShares(address account) external returns (uint256) { + uint256 baseInput = _VAULT_.getBaseInput(); + uint256 quoteInput = _VAULT_.getQuoteInput(); + + require(baseInput > 0, "NO_BASE_INPUT"); + + uint256 baseReserve = _VAULT_._BASE_RESERVE_(); + uint256 quoteReserve = _VAULT_._QUOTE_RESERVE_(); + uint256 mintAmount; + + // case 1. initial supply + if (baseReserve == 0 && quoteReserve == 0) { + mintAmount = baseInput; + } + + // case 2. supply when quote reserve is 0 + if (baseReserve > 0 && quoteReserve == 0) { + uint256 mintRatio = DecimalMath.divFloor(baseInput, baseReserve); + mintAmount = DecimalMath.mulFloor(_VAULT_.totalSupply(), mintRatio); + } + + // case 3. normal case + if (baseReserve > 0 && quoteReserve > 0) { + uint256 baseInputRatio = DecimalMath.divFloor(baseInput, baseReserve); + uint256 quoteInputRatio = DecimalMath.divFloor(quoteInput, quoteReserve); + uint256 mintRatio = baseInputRatio > quoteInputRatio ? quoteInputRatio : baseInputRatio; + // 在提币的时候向下取整。因此永远不会出现,balance为0但totalsupply不为0的情况 + // 但有可能出现,reserve>0但totalSupply=0的场景 + uint256 totalShare = _VAULT_.totalSupply(); + if (totalShare > 0) { + mintAmount = DecimalMath.mulFloor(totalShare, mintRatio); + } else { + mintAmount = baseInput; + } + } + + _VAULT_.mint(account, mintAmount); + _VAULT_.sync(); + } + + function sellShares( + address account, + address to, + uint256 amount + ) external returns (uint256) { + require(msg.sender == account, "PERMISSION_DENY"); + require(_VAULT_.balanceOf(account) >= amount, "SHARES_NOT_ENOUGH"); + (uint256 baseBalance, uint256 quoteBalance) = _VAULT_.getVaultBalance(); + uint256 totalShares = _VAULT_.totalSupply(); + _VAULT_.burn(account, amount); + _VAULT_.transferBaseOut(to, baseBalance.mul(amount).div(totalShares)); + _VAULT_.transferQuoteOut(to, quoteBalance.mul(amount).div(totalShares)); + _VAULT_.sync(); + } +} diff --git a/contracts/DODOVenderMachine/impl/DVMStorage.sol b/contracts/DODOVenderMachine/impl/DVMStorage.sol new file mode 100644 index 0000000..7be080d --- /dev/null +++ b/contracts/DODOVenderMachine/impl/DVMStorage.sol @@ -0,0 +1,75 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {InitializableOwnable} from "../../lib/InitializableOwnable.sol"; +import {ReentrancyGuard} from "../../lib/ReentrancyGuard.sol"; +import {SafeMath} from "../../lib/SafeMath.sol"; +import {DODOMath} from "../../lib/DODOMath.sol"; +import {DecimalMath} from "../../lib/DecimalMath.sol"; +import {PermissionManager} from "../../lib/PermissionManager.sol"; +import {IFeeRateModel} from "../../intf/IFeeRateModel.sol"; +import {DVMVault} from "./DVMVault.sol"; + +contract DVMStorage is InitializableOwnable, ReentrancyGuard { + using SafeMath for uint256; + + // ============ Variables for Control ============ + + bool public _CLOSED_; + uint256 public _GAS_PRICE_LIMIT_; + + // ============ Advanced Controls ============ + + bool public _BUYING_ALLOWED_; + bool public _SELLING_ALLOWED_; + + PermissionManager public _TRADE_PERMISSION_; + PermissionManager public _FUNDING_PERMISSION_; + + // ============ Core Address ============ + + address public _MAINTAINER_; // collect maintainer fee + + address public _BASE_TOKEN_; + address public _QUOTE_TOKEN_; + + // ============ Variables for Pricing ============ + + IFeeRateModel public _LP_FEE_RATE_MODEL_; + IFeeRateModel public _MT_FEE_RATE_MODEL_; + uint256 public _K_; + uint256 public _I_; + uint256 public _BASE0_; + + DVMVault public _VAULT_; + DVMVault public _PROTECTION_VAULT_; + + // ============ Modifiers ============ + + modifier notClosed() { + require(!_CLOSED_, "DODO_CLOSED"); + _; + } + + // ============ Helper Functions ============ + function _updateBase0() internal { + uint256 fairAmount = DecimalMath.divFloor(_VAULT_._QUOTE_RESERVE_(), _I_); + _BASE0_ = DODOMath._SolveQuadraticFunctionForTarget( + _VAULT_._BASE_RESERVE_(), + _K_, + fairAmount + ); + } + + // ============ Version Control ============ + function version() external pure returns (uint256) { + return 101; // 1.0.1 + } +} diff --git a/contracts/DODOVenderMachine/impl/DVMTrader.sol b/contracts/DODOVenderMachine/impl/DVMTrader.sol new file mode 100644 index 0000000..9a6aea9 --- /dev/null +++ b/contracts/DODOVenderMachine/impl/DVMTrader.sol @@ -0,0 +1,69 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {DVMStorage} from "./DVMStorage.sol"; +import {SafeMath} from "../../lib/SafeMath.sol"; +import {DecimalMath} from "../../lib/DecimalMath.sol"; +import {DODOMath} from "../../lib/DODOMath.sol"; + +contract DVMTrader is DVMStorage { + using SafeMath for uint256; + + function sellBase (address to) external returns(uint256 receiveQuoteAmount){ + uint256 baseInput = _VAULT_.getBaseInput(); + uint256 mtFee; + (receiveQuoteAmount, mtFee) = querySellBase(baseInput); + _VAULT_.transferQuoteOut(to, receiveQuoteAmount); + if (mtFee>0){ + _VAULT_.transferQuoteOut(_MAINTAINER_, mtFee); + } + _VAULT_.sync(); + _updateBase0(); // 这里需要想想,原则上不需要update B0. 但精度问题,或者用户往合约里充值,可能导致需要updateBase0 + return receiveQuoteAmount; + } + + function sellQuote(address to) external returns(uint256 receiveBaseAmount){ + uint256 quoteInput = _VAULT_.getQuoteInput(); + uint256 mtFee; + (receiveBaseAmount, mtFee) = querySellQuote(quoteInput); + _VAULT_.transferBaseOut(to, receiveBaseAmount); + if (mtFee>0){ + _VAULT_.transferBaseOut(_MAINTAINER_, mtFee); + } + _VAULT_.sync(); + _updateBase0(); + return receiveBaseAmount; + } + + function querySellBase(uint256 payBaseAmount) public view returns(uint256 receiveQuoteAmount, uint256 mtFee){ + uint256 B2 = _VAULT_._BASE_RESERVE_(); + uint256 B1 = B2.add(payBaseAmount); + require(_BASE0_>=B1, "DODO_BASE_BALANCE_NOT_ENOUGH"); + uint256 Q = DODOMath._GeneralIntegrate(_BASE0_, B1, B2, _I_, _K_); + uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(Q); + uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(Q); + mtFee = DecimalMath.mulCeil(Q, mtFeeRate); + receiveQuoteAmount = Q.sub(mtFee).sub(DecimalMath.mulCeil(Q, lpFeeRate)); + return (receiveQuoteAmount, mtFee); + } + + function querySellQuote(uint256 payQuoteAmount) public view returns(uint256 receiveBaseAmount, uint256 mtFee){ + uint256 B1 = _VAULT_._BASE_RESERVE_(); + uint256 fairAmount = DecimalMath.divFloor(payQuoteAmount, _I_); + uint256 newBaseReserve = DODOMath._SolveQuadraticFunctionForTrade(_BASE0_,B1,fairAmount,false, _K_); + uint256 deltaBase = B1.sub(newBaseReserve); + uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(payQuoteAmount); + uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(payQuoteAmount); + mtFee = DecimalMath.mulCeil(deltaBase, mtFeeRate); + receiveBaseAmount = deltaBase.sub(mtFee).sub(DecimalMath.mulCeil(deltaBase, lpFeeRate)); + return (receiveBaseAmount, mtFee); + } + +} \ No newline at end of file diff --git a/contracts/DODOVenderMachine/impl/DVMVault.sol b/contracts/DODOVenderMachine/impl/DVMVault.sol new file mode 100644 index 0000000..0461d82 --- /dev/null +++ b/contracts/DODOVenderMachine/impl/DVMVault.sol @@ -0,0 +1,205 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {IERC20} from "../../intf/IERC20.sol"; +import {SafeMath} from "../../lib/SafeMath.sol"; +import {DecimalMath} from "../../lib/DecimalMath.sol"; +import {SafeERC20} from "../../lib/SafeERC20.sol"; +import {Ownable} from "../../lib/Ownable.sol"; +import {InitializableOwnable} from "../../lib/InitializableOwnable.sol"; + +contract DVMVault is InitializableOwnable { + using SafeMath for uint256; + using SafeERC20 for IERC20; + + address public _BASE_TOKEN_; + address public _QUOTE_TOKEN_; + + uint256 public _BASE_RESERVE_; + uint256 public _QUOTE_RESERVE_; + + string public symbol; + uint256 public decimals; + string public name; + + uint256 public totalSupply; + mapping(address => uint256) internal _SHARES_; + mapping(address => mapping(address => uint256)) internal _ALLOWED_; + + // ============ Events ============ + + event Transfer(address indexed from, address indexed to, uint256 amount); + + event Approval(address indexed owner, address indexed spender, uint256 amount); + + event Mint(address indexed user, uint256 value); + + event Burn(address indexed user, uint256 value); + + // init functions + function init( + address owner, + address _baseToken, + address _quoteToken + ) public notInitialized { + initOwner(owner); + string memory connect = "_"; + string memory suffix = "DLP"; + string memory uid = string(abi.encodePacked(address(this))); + name = string( + abi.encodePacked( + suffix, + connect, + IERC20(_baseToken).symbol(), + connect, + IERC20(_quoteToken).symbol(), + connect, + uid + ) + ); + symbol = "DLP"; + decimals = IERC20(_baseToken).decimals(); + } + + // Vault related + + function getVaultBalance() public view returns (uint256 baseBalance, uint256 quoteBalance) { + return ( + IERC20(_BASE_TOKEN_).balanceOf(address(this)), + IERC20(_QUOTE_TOKEN_).balanceOf(address(this)) + ); + } + + function getBaseBalance() public view returns (uint256 baseBalance) { + return IERC20(_BASE_TOKEN_).balanceOf(address(this)); + } + + function getQuoteBalance() public view returns (uint256 quoteBalance) { + return IERC20(_QUOTE_TOKEN_).balanceOf(address(this)); + } + + function getBaseInput() public view returns (uint256 input) { + return IERC20(_BASE_TOKEN_).balanceOf(address(this)).sub(_BASE_RESERVE_); + } + + function getQuoteInput() public view returns (uint256 input) { + return IERC20(_QUOTE_TOKEN_).balanceOf(address(this)).sub(_QUOTE_RESERVE_); + } + + function sync() public onlyOwner { + (uint256 baseBalance, uint256 quoteBalance) = getVaultBalance(); + if (baseBalance != _BASE_RESERVE_) { + _BASE_RESERVE_ = baseBalance; + } + if (quoteBalance != _QUOTE_RESERVE_) { + _QUOTE_RESERVE_ = quoteBalance; + } + } + + function transferOut( + address token, + address to, + uint256 amount + ) public onlyOwner { + IERC20(token).safeTransfer(to, amount); + } + + function transferBaseOut(address to, uint256 amount) public onlyOwner { + IERC20(_BASE_TOKEN_).safeTransfer(to, amount); + } + + function transferQuoteOut(address to, uint256 amount) public onlyOwner { + IERC20(_QUOTE_TOKEN_).safeTransfer(to, amount); + } + + // Shares related + /** + * @dev transfer token for a specified address + * @param to The address to transfer to. + * @param amount The amount to be transferred. + */ + function transfer(address to, uint256 amount) public returns (bool) { + require(amount <= _SHARES_[msg.sender], "BALANCE_NOT_ENOUGH"); + + _SHARES_[msg.sender] = _SHARES_[msg.sender].sub(amount); + _SHARES_[to] = _SHARES_[to].add(amount); + emit Transfer(msg.sender, to, amount); + return true; + } + + /** + * @dev Gets the balance of the specified address. + * @param owner The address to query the the balance of. + * @return balance An uint256 representing the amount owned by the passed address. + */ + function balanceOf(address owner) external view returns (uint256 balance) { + return _SHARES_[owner]; + } + + function shareRatioOf(address owner) external view returns (uint256 shareRatio) { + return DecimalMath.divFloor(_SHARES_[owner], totalSupply); + } + + /** + * @dev Transfer tokens from one address to another + * @param from address The address which you want to send tokens from + * @param to address The address which you want to transfer to + * @param amount uint256 the amount of tokens to be transferred + */ + function transferFrom( + address from, + address to, + uint256 amount + ) public returns (bool) { + require(amount <= _SHARES_[from], "BALANCE_NOT_ENOUGH"); + require(amount <= _ALLOWED_[from][msg.sender], "ALLOWANCE_NOT_ENOUGH"); + + _SHARES_[from] = _SHARES_[from].sub(amount); + _SHARES_[to] = _SHARES_[to].add(amount); + _ALLOWED_[from][msg.sender] = _ALLOWED_[from][msg.sender].sub(amount); + emit Transfer(from, to, amount); + return true; + } + + /** + * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. + * @param spender The address which will spend the funds. + * @param amount The amount of tokens to be spent. + */ + function approve(address spender, uint256 amount) public returns (bool) { + _ALLOWED_[msg.sender][spender] = amount; + emit Approval(msg.sender, spender, amount); + return true; + } + + /** + * @dev Function to check the amount of tokens that an owner _ALLOWED_ to a spender. + * @param owner address The address which owns the funds. + * @param spender address The address which will spend the funds. + * @return A uint256 specifying the amount of tokens still available for the spender. + */ + function allowance(address owner, address spender) public view returns (uint256) { + return _ALLOWED_[owner][spender]; + } + + function mint(address user, uint256 value) external onlyOwner { + _SHARES_[user] = _SHARES_[user].add(value); + totalSupply = totalSupply.add(value); + emit Mint(user, value); + emit Transfer(address(0), user, value); + } + + function burn(address user, uint256 value) external onlyOwner { + _SHARES_[user] = _SHARES_[user].sub(value); + totalSupply = totalSupply.sub(value); + emit Burn(user, value); + emit Transfer(user, address(0), value); + } +} diff --git a/contracts/DODOZoo.sol b/contracts/DODOZoo.sol deleted file mode 100644 index c47cc10..0000000 --- a/contracts/DODOZoo.sol +++ /dev/null @@ -1,134 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - -import {Ownable} from "./lib/Ownable.sol"; -import {IDODO} from "./intf/IDODO.sol"; -import {ICloneFactory} from "./helper/CloneFactory.sol"; - - -/** - * @title DODOZoo - * @author DODO Breeder - * - * @notice Register of All DODO - */ -contract DODOZoo is Ownable { - address public _DODO_LOGIC_; - address public _CLONE_FACTORY_; - - address public _DEFAULT_SUPERVISOR_; - - mapping(address => mapping(address => address)) internal _DODO_REGISTER_; - address[] public _DODOs; - - // ============ Events ============ - - event DODOBirth(address newBorn, address baseToken, address quoteToken); - - // ============ Constructor Function ============ - - constructor( - address _dodoLogic, - address _cloneFactory, - address _defaultSupervisor - ) public { - _DODO_LOGIC_ = _dodoLogic; - _CLONE_FACTORY_ = _cloneFactory; - _DEFAULT_SUPERVISOR_ = _defaultSupervisor; - } - - // ============ Admin Function ============ - - function setDODOLogic(address _dodoLogic) external onlyOwner { - _DODO_LOGIC_ = _dodoLogic; - } - - function setCloneFactory(address _cloneFactory) external onlyOwner { - _CLONE_FACTORY_ = _cloneFactory; - } - - function setDefaultSupervisor(address _defaultSupervisor) external onlyOwner { - _DEFAULT_SUPERVISOR_ = _defaultSupervisor; - } - - function removeDODO(address dodo) external onlyOwner { - address baseToken = IDODO(dodo)._BASE_TOKEN_(); - address quoteToken = IDODO(dodo)._QUOTE_TOKEN_(); - require(isDODORegistered(baseToken, quoteToken), "DODO_NOT_REGISTERED"); - _DODO_REGISTER_[baseToken][quoteToken] = address(0); - for (uint256 i = 0; i <= _DODOs.length - 1; i++) { - if (_DODOs[i] == dodo) { - _DODOs[i] = _DODOs[_DODOs.length - 1]; - _DODOs.pop(); - break; - } - } - } - - function addDODO(address dodo) public onlyOwner { - address baseToken = IDODO(dodo)._BASE_TOKEN_(); - address quoteToken = IDODO(dodo)._QUOTE_TOKEN_(); - require(!isDODORegistered(baseToken, quoteToken), "DODO_REGISTERED"); - _DODO_REGISTER_[baseToken][quoteToken] = dodo; - _DODOs.push(dodo); - } - - // ============ Breed DODO Function ============ - - function breedDODO( - address maintainer, - address baseToken, - address quoteToken, - address oracle, - uint256 lpFeeRate, - uint256 mtFeeRate, - uint256 k, - uint256 gasPriceLimit - ) external onlyOwner returns (address newBornDODO) { - require(!isDODORegistered(baseToken, quoteToken), "DODO_REGISTERED"); - newBornDODO = ICloneFactory(_CLONE_FACTORY_).clone(_DODO_LOGIC_); - IDODO(newBornDODO).init( - _OWNER_, - _DEFAULT_SUPERVISOR_, - maintainer, - baseToken, - quoteToken, - oracle, - lpFeeRate, - mtFeeRate, - k, - gasPriceLimit - ); - addDODO(newBornDODO); - emit DODOBirth(newBornDODO, baseToken, quoteToken); - return newBornDODO; - } - - // ============ View Functions ============ - - function isDODORegistered(address baseToken, address quoteToken) public view returns (bool) { - if ( - _DODO_REGISTER_[baseToken][quoteToken] == address(0) && - _DODO_REGISTER_[quoteToken][baseToken] == address(0) - ) { - return false; - } else { - return true; - } - } - - function getDODO(address baseToken, address quoteToken) external view returns (address) { - return _DODO_REGISTER_[baseToken][quoteToken]; - } - - function getDODOs() external view returns (address[] memory) { - return _DODOs; - } -} diff --git a/contracts/dodo.sol b/contracts/dodo.sol deleted file mode 100644 index 8e63036..0000000 --- a/contracts/dodo.sol +++ /dev/null @@ -1,74 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - -import {Types} from "./lib/Types.sol"; -import {IERC20} from "./intf/IERC20.sol"; -import {Storage} from "./impl/Storage.sol"; -import {Trader} from "./impl/Trader.sol"; -import {LiquidityProvider} from "./impl/LiquidityProvider.sol"; -import {Admin} from "./impl/Admin.sol"; -import {DODOLpToken} from "./impl/DODOLpToken.sol"; - - -/** - * @title DODO - * @author DODO Breeder - * - * @notice Entrance for users - */ -contract DODO is Admin, Trader, LiquidityProvider { - function init( - address owner, - address supervisor, - address maintainer, - address baseToken, - address quoteToken, - address oracle, - uint256 lpFeeRate, - uint256 mtFeeRate, - uint256 k, - uint256 gasPriceLimit - ) external { - require(!_INITIALIZED_, "DODO_INITIALIZED"); - _INITIALIZED_ = true; - - // constructor - _OWNER_ = owner; - emit OwnershipTransferred(address(0), _OWNER_); - - _SUPERVISOR_ = supervisor; - _MAINTAINER_ = maintainer; - _BASE_TOKEN_ = baseToken; - _QUOTE_TOKEN_ = quoteToken; - _ORACLE_ = oracle; - - _DEPOSIT_BASE_ALLOWED_ = false; - _DEPOSIT_QUOTE_ALLOWED_ = false; - _TRADE_ALLOWED_ = false; - _GAS_PRICE_LIMIT_ = gasPriceLimit; - - // Advanced controls are disabled by default - _BUYING_ALLOWED_ = true; - _SELLING_ALLOWED_ = true; - uint256 MAX_INT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; - _BASE_BALANCE_LIMIT_ = MAX_INT; - _QUOTE_BALANCE_LIMIT_ = MAX_INT; - - _LP_FEE_RATE_ = lpFeeRate; - _MT_FEE_RATE_ = mtFeeRate; - _K_ = k; - _R_STATUS_ = Types.RStatus.ONE; - - _BASE_CAPITAL_TOKEN_ = address(new DODOLpToken(_BASE_TOKEN_)); - _QUOTE_CAPITAL_TOKEN_ = address(new DODOLpToken(_QUOTE_TOKEN_)); - - _checkDODOParameters(); - } -} diff --git a/contracts/helper/TestERC20.sol b/contracts/external/ERC20/NormalERC20.sol similarity index 97% rename from contracts/helper/TestERC20.sol rename to contracts/external/ERC20/NormalERC20.sol index 5d02d72..416b1e8 100644 --- a/contracts/helper/TestERC20.sol +++ b/contracts/external/ERC20/NormalERC20.sol @@ -7,7 +7,7 @@ pragma solidity 0.6.9; -import {SafeMath} from "../lib/SafeMath.sol"; +import {SafeMath} from "../../lib/SafeMath.sol"; contract TestERC20 { using SafeMath for uint256; diff --git a/contracts/helper/TestWETH.sol b/contracts/external/ERC20/TestWETH.sol similarity index 100% rename from contracts/helper/TestWETH.sol rename to contracts/external/ERC20/TestWETH.sol diff --git a/contracts/helper/UniswapV2.sol b/contracts/external/uniswap/UniswapV2.sol similarity index 98% rename from contracts/helper/UniswapV2.sol rename to contracts/external/uniswap/UniswapV2.sol index 282d07b..6e1b28c 100644 --- a/contracts/helper/UniswapV2.sol +++ b/contracts/external/uniswap/UniswapV2.sol @@ -1,5 +1,6 @@ -/** - *Submitted for verification at Etherscan.io on 2020-05-05 +/* + Submitted for verification at Etherscan.io on 2020-05-05 + SPDX-License-Identifier: Apache-2.0 */ // File: contracts/interfaces/IUniswapV2Pair.sol @@ -184,7 +185,8 @@ contract UniswapV2ERC20 { bytes32 public DOMAIN_SEPARATOR; // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); - bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; + bytes32 + public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; mapping(address => uint256) public nonces; event Approval(address indexed owner, address indexed spender, uint256 value); diff --git a/contracts/helper/BandBNBBUSDPriceOracleProxy.sol b/contracts/helper/BandBNBBUSDPriceOracleProxy.sol deleted file mode 100644 index 681f31a..0000000 --- a/contracts/helper/BandBNBBUSDPriceOracleProxy.sol +++ /dev/null @@ -1,30 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - - -interface IBandOracleAggregator { - function getReferenceData(string memory base, string memory quote) - external - view - returns (uint256); -} - - -contract BandBNBBUSDPriceOracleProxy { - IBandOracleAggregator public aggregator; - - constructor(IBandOracleAggregator _aggregator) public { - aggregator = _aggregator; - } - - function getPrice() public view returns (uint256) { - return aggregator.getReferenceData("BNB", "USD"); - } -} diff --git a/contracts/helper/ChainlinkCOMPUSDCPriceOracleProxy.sol b/contracts/helper/ChainlinkCOMPUSDCPriceOracleProxy.sol deleted file mode 100644 index 6f9bce8..0000000 --- a/contracts/helper/ChainlinkCOMPUSDCPriceOracleProxy.sol +++ /dev/null @@ -1,25 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - - -interface IChainlink { - function latestAnswer() external view returns (uint256); -} - - -// for COMP-USDC(decimals=6) price convert - -contract ChainlinkCOMPUSDCPriceOracleProxy { - address public chainlink = 0xdbd020CAeF83eFd542f4De03e3cF0C28A4428bd5; - - function getPrice() external view returns (uint256) { - return IChainlink(chainlink).latestAnswer() / 100; - } -} diff --git a/contracts/helper/ChainlinkEthUSDCPriceOracleProxy.sol b/contracts/helper/ChainlinkEthUSDCPriceOracleProxy.sol deleted file mode 100644 index 53036a7..0000000 --- a/contracts/helper/ChainlinkEthUSDCPriceOracleProxy.sol +++ /dev/null @@ -1,25 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - - -interface IChainlink { - function latestAnswer() external view returns (uint256); -} - - -// for WETH-USDC(decimals=6) price convert - -contract ChainlinkETHPriceOracleProxy { - address public chainlink = 0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419; - - function getPrice() external view returns (uint256) { - return IChainlink(chainlink).latestAnswer() / 100; - } -} diff --git a/contracts/helper/ChainlinkEthUSDTPriceOracleProxy.sol b/contracts/helper/ChainlinkEthUSDTPriceOracleProxy.sol deleted file mode 100644 index 6d27f7a..0000000 --- a/contracts/helper/ChainlinkEthUSDTPriceOracleProxy.sol +++ /dev/null @@ -1,25 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - - -interface IChainlink { - function latestAnswer() external view returns (uint256); -} - - -// for WETH-USDT(decimals=6) price convert - -contract ChainlinkETHUSDTPriceOracleProxy { - address public chainlink = 0xEe9F2375b4bdF6387aa8265dD4FB8F16512A1d46; - - function getPrice() external view returns (uint256) { - return 10**24 / IChainlink(chainlink).latestAnswer(); - } -} diff --git a/contracts/helper/ChainlinkLENDUSDCPriceOracleProxy.sol b/contracts/helper/ChainlinkLENDUSDCPriceOracleProxy.sol deleted file mode 100644 index c338136..0000000 --- a/contracts/helper/ChainlinkLENDUSDCPriceOracleProxy.sol +++ /dev/null @@ -1,25 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - - -interface IChainlink { - function latestAnswer() external view returns (uint256); -} - - -// for LEND-USDC(decimals=6) price convert - -contract ChainlinkLENDUSDCPriceOracleProxy { - address public chainlink = 0x4aB81192BB75474Cf203B56c36D6a13623270A67; - - function getPrice() external view returns (uint256) { - return IChainlink(chainlink).latestAnswer() / 100; - } -} diff --git a/contracts/helper/ChainlinkLINKUSDPriceOracleProxy.sol b/contracts/helper/ChainlinkLINKUSDPriceOracleProxy.sol deleted file mode 100644 index fe6615d..0000000 --- a/contracts/helper/ChainlinkLINKUSDPriceOracleProxy.sol +++ /dev/null @@ -1,25 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - - -interface IChainlink { - function latestAnswer() external view returns (uint256); -} - - -// for LINK-USDC(decimals=6) price convert - -contract ChainlinkLINKUSDCPriceOracleProxy { - address public chainlink = 0x2c1d072e956AFFC0D435Cb7AC38EF18d24d9127c; - - function getPrice() external view returns (uint256) { - return IChainlink(chainlink).latestAnswer() / 100; - } -} diff --git a/contracts/helper/ChainlinkSNXUSDPriceOracleProxy.sol b/contracts/helper/ChainlinkSNXUSDPriceOracleProxy.sol deleted file mode 100644 index e3d478c..0000000 --- a/contracts/helper/ChainlinkSNXUSDPriceOracleProxy.sol +++ /dev/null @@ -1,25 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - - -interface IChainlink { - function latestAnswer() external view returns (uint256); -} - - -// for SNX-USDC(decimals=6) price convert - -contract ChainlinkSNXUSDCPriceOracleProxy { - address public chainlink = 0xDC3EA94CD0AC27d9A86C180091e7f78C683d3699; - - function getPrice() external view returns (uint256) { - return IChainlink(chainlink).latestAnswer() / 100; - } -} diff --git a/contracts/helper/ChainlinkWBTCUSDCPriceOracleProxy.sol b/contracts/helper/ChainlinkWBTCUSDCPriceOracleProxy.sol deleted file mode 100644 index ae78ebd..0000000 --- a/contracts/helper/ChainlinkWBTCUSDCPriceOracleProxy.sol +++ /dev/null @@ -1,25 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - - -interface IChainlink { - function latestAnswer() external view returns (uint256); -} - - -// for WBTC(decimals=8)-USDC(decimals=6) price convert - -contract ChainlinkWBTCUSDCPriceOracleProxy { - address public chainlink = 0xF4030086522a5bEEa4988F8cA5B36dbC97BeE88c; - - function getPrice() external view returns (uint256) { - return IChainlink(chainlink).latestAnswer() * (10**8); - } -} diff --git a/contracts/helper/ChainlinkYFIUSDCPriceOracleProxy.sol b/contracts/helper/ChainlinkYFIUSDCPriceOracleProxy.sol deleted file mode 100644 index b2d071d..0000000 --- a/contracts/helper/ChainlinkYFIUSDCPriceOracleProxy.sol +++ /dev/null @@ -1,32 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - -import {SafeMath} from "../lib/SafeMath.sol"; - - -interface IChainlink { - function latestAnswer() external view returns (uint256); -} - - -// for YFI-USDC(decimals=6) price convert - -contract ChainlinkYFIUSDCPriceOracleProxy { - using SafeMath for uint256; - - address public yfiEth = 0x7c5d4F8345e66f68099581Db340cd65B078C41f4; - address public EthUsd = 0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419; - - function getPrice() external view returns (uint256) { - uint256 yfiEthPrice = IChainlink(yfiEth).latestAnswer(); - uint256 EthUsdPrice = IChainlink(EthUsd).latestAnswer(); - return yfiEthPrice.mul(EthUsdPrice).div(10**20); - } -} diff --git a/contracts/helper/ConstFeeRateModel.sol b/contracts/helper/ConstFeeRateModel.sol new file mode 100644 index 0000000..a3afd17 --- /dev/null +++ b/contracts/helper/ConstFeeRateModel.sol @@ -0,0 +1,23 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {IFeeRateModel} from "../intf/IFeeRateModel.sol"; + +contract ConstFeeRateModel is IFeeRateModel { + uint256 public _FEE_RATE_; + + constructor(uint256 feeRate) public { + feeRate = _FEE_RATE_; + } + + function getFeeRate(uint256) external override view returns (uint256) { + return _FEE_RATE_; + } +} diff --git a/contracts/helper/ConstOracle.sol b/contracts/helper/ConstOracle.sol deleted file mode 100644 index 87181e8..0000000 --- a/contracts/helper/ConstOracle.sol +++ /dev/null @@ -1,22 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - - -contract ConstOracle { - uint256 public tokenPrice; - - constructor(uint256 _price) public { - tokenPrice = _price; - } - - function getPrice() external view returns (uint256) { - return tokenPrice; - } -} diff --git a/contracts/helper/MinimumOracle.sol b/contracts/helper/MinimumOracle.sol deleted file mode 100644 index 0056add..0000000 --- a/contracts/helper/MinimumOracle.sol +++ /dev/null @@ -1,56 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - - -interface IMinimumOracle { - function getPrice() external view returns (uint256); - - function setPrice(uint256 newPrice) external; - - function transferOwnership(address newOwner) external; -} - - -contract MinimumOracle { - address public _OWNER_; - uint256 public tokenPrice; - - // ============ Events ============ - - event OwnershipTransfer(address indexed previousOwner, address indexed newOwner); - - // ============ Modifiers ============ - - modifier onlyOwner() { - require(msg.sender == _OWNER_, "NOT_OWNER"); - _; - } - - // ============ Functions ============ - - constructor() public { - _OWNER_ = msg.sender; - emit OwnershipTransfer(address(0), _OWNER_); - } - - function transferOwnership(address newOwner) external onlyOwner { - require(newOwner != address(0), "INVALID_OWNER"); - emit OwnershipTransfer(_OWNER_, newOwner); - _OWNER_ = newOwner; - } - - function setPrice(uint256 newPrice) external onlyOwner { - tokenPrice = newPrice; - } - - function getPrice() external view returns (uint256) { - return tokenPrice; - } -} diff --git a/contracts/helper/NaiveFeeRateModel.sol b/contracts/helper/NaiveFeeRateModel.sol new file mode 100644 index 0000000..1a244e1 --- /dev/null +++ b/contracts/helper/NaiveFeeRateModel.sol @@ -0,0 +1,28 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {IFeeRateModel} from "../intf/IFeeRateModel.sol"; +import {Ownable} from "../lib/Ownable.sol"; + +contract ConstFeeRateModel is Ownable, IFeeRateModel { + uint256 public _FEE_RATE_; + + constructor(uint256 feeRate) public { + feeRate = _FEE_RATE_; + } + + function setFeeRate(uint256 newFeeRate) external { + _FEE_RATE_ = newFeeRate; + } + + function getFeeRate(uint256) external override view returns (uint256) { + return _FEE_RATE_; + } +} diff --git a/contracts/helper/NaiveOracle.sol b/contracts/helper/NaiveOracle.sol deleted file mode 100644 index b472960..0000000 --- a/contracts/helper/NaiveOracle.sol +++ /dev/null @@ -1,25 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - -import {Ownable} from "../lib/Ownable.sol"; - - -// Oracle only for test -contract NaiveOracle is Ownable { - uint256 public tokenPrice; - - function setPrice(uint256 newPrice) external onlyOwner { - tokenPrice = newPrice; - } - - function getPrice() external view returns (uint256) { - return tokenPrice; - } -} diff --git a/contracts/helper/UniswapArbitrageur.sol b/contracts/helper/UniswapArbitrageur.sol deleted file mode 100644 index a67433e..0000000 --- a/contracts/helper/UniswapArbitrageur.sol +++ /dev/null @@ -1,165 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - -import {Ownable} from "../lib/Ownable.sol"; -import {IDODO} from "../intf/IDODO.sol"; -import {IERC20} from "../intf/IERC20.sol"; -import {SafeERC20} from "../lib/SafeERC20.sol"; -import {SafeMath} from "../lib/SafeMath.sol"; - -interface IUniswapV2Pair { - function token0() external view returns (address); - - function token1() external view returns (address); - - function getReserves() - external - view - returns ( - uint112 reserve0, - uint112 reserve1, - uint32 blockTimestampLast - ); - - function swap( - uint256 amount0Out, - uint256 amount1Out, - address to, - bytes calldata data - ) external; -} - -contract UniswapArbitrageur { - using SafeMath for uint256; - using SafeERC20 for IERC20; - - address public _UNISWAP_; - address public _DODO_; - address public _BASE_; - address public _QUOTE_; - - bool public _REVERSE_; // true if dodo.baseToken=uniswap.token0 - - constructor(address _uniswap, address _dodo) public { - _UNISWAP_ = _uniswap; - _DODO_ = _dodo; - - _BASE_ = IDODO(_DODO_)._BASE_TOKEN_(); - _QUOTE_ = IDODO(_DODO_)._QUOTE_TOKEN_(); - - address token0 = IUniswapV2Pair(_UNISWAP_).token0(); - address token1 = IUniswapV2Pair(_UNISWAP_).token1(); - - if (token0 == _BASE_ && token1 == _QUOTE_) { - _REVERSE_ = false; - } else if (token0 == _QUOTE_ && token1 == _BASE_) { - _REVERSE_ = true; - } else { - require(true, "DODO_UNISWAP_NOT_MATCH"); - } - - IERC20(_BASE_).approve(_DODO_, uint256(-1)); - IERC20(_QUOTE_).approve(_DODO_, uint256(-1)); - } - - function executeBuyArbitrage(uint256 baseAmount) external returns (uint256 quoteProfit) { - IDODO(_DODO_).buyBaseToken(baseAmount, uint256(-1), "0xd"); - quoteProfit = IERC20(_QUOTE_).balanceOf(address(this)); - IERC20(_QUOTE_).transfer(msg.sender, quoteProfit); - return quoteProfit; - } - - function executeSellArbitrage(uint256 baseAmount) external returns (uint256 baseProfit) { - IDODO(_DODO_).sellBaseToken(baseAmount, 0, "0xd"); - baseProfit = IERC20(_BASE_).balanceOf(address(this)); - IERC20(_BASE_).transfer(msg.sender, baseProfit); - return baseProfit; - } - - function dodoCall( - bool isDODOBuy, - uint256 baseAmount, - uint256 quoteAmount, - bytes calldata - ) external { - require(msg.sender == _DODO_, "WRONG_DODO"); - if (_REVERSE_) { - _inverseArbitrage(isDODOBuy, baseAmount, quoteAmount); - } else { - _arbitrage(isDODOBuy, baseAmount, quoteAmount); - } - } - - function _inverseArbitrage( - bool isDODOBuy, - uint256 baseAmount, - uint256 quoteAmount - ) internal { - (uint112 _reserve0, uint112 _reserve1, ) = IUniswapV2Pair(_UNISWAP_).getReserves(); - uint256 token0Balance = uint256(_reserve0); - uint256 token1Balance = uint256(_reserve1); - uint256 token0Amount; - uint256 token1Amount; - if (isDODOBuy) { - IERC20(_BASE_).transfer(_UNISWAP_, baseAmount); - // transfer token1 into uniswap - uint256 newToken0Balance = token0Balance.mul(token1Balance).div( - token1Balance.add(baseAmount) - ); - token0Amount = token0Balance.sub(newToken0Balance).mul(9969).div(10000); // mul 0.9969 - require(token0Amount > quoteAmount, "NOT_PROFITABLE"); - IUniswapV2Pair(_UNISWAP_).swap(token0Amount, token1Amount, address(this), ""); - } else { - IERC20(_QUOTE_).transfer(_UNISWAP_, quoteAmount); - // transfer token0 into uniswap - uint256 newToken1Balance = token0Balance.mul(token1Balance).div( - token0Balance.add(quoteAmount) - ); - token1Amount = token1Balance.sub(newToken1Balance).mul(9969).div(10000); // mul 0.9969 - require(token1Amount > baseAmount, "NOT_PROFITABLE"); - IUniswapV2Pair(_UNISWAP_).swap(token0Amount, token1Amount, address(this), ""); - } - } - - function _arbitrage( - bool isDODOBuy, - uint256 baseAmount, - uint256 quoteAmount - ) internal { - (uint112 _reserve0, uint112 _reserve1, ) = IUniswapV2Pair(_UNISWAP_).getReserves(); - uint256 token0Balance = uint256(_reserve0); - uint256 token1Balance = uint256(_reserve1); - uint256 token0Amount; - uint256 token1Amount; - if (isDODOBuy) { - IERC20(_BASE_).transfer(_UNISWAP_, baseAmount); - // transfer token0 into uniswap - uint256 newToken1Balance = token1Balance.mul(token0Balance).div( - token0Balance.add(baseAmount) - ); - token1Amount = token1Balance.sub(newToken1Balance).mul(9969).div(10000); // mul 0.9969 - require(token1Amount > quoteAmount, "NOT_PROFITABLE"); - IUniswapV2Pair(_UNISWAP_).swap(token0Amount, token1Amount, address(this), ""); - } else { - IERC20(_QUOTE_).transfer(_UNISWAP_, quoteAmount); - // transfer token1 into uniswap - uint256 newToken0Balance = token1Balance.mul(token0Balance).div( - token1Balance.add(quoteAmount) - ); - token0Amount = token0Balance.sub(newToken0Balance).mul(9969).div(10000); // mul 0.9969 - require(token0Amount > baseAmount, "NOT_PROFITABLE"); - IUniswapV2Pair(_UNISWAP_).swap(token0Amount, token1Amount, address(this), ""); - } - } - - function retrieve(address token, uint256 amount) external { - IERC20(token).safeTransfer(msg.sender, amount); - } -} diff --git a/contracts/impl/Admin.sol b/contracts/impl/Admin.sol deleted file mode 100644 index 2e5edf7..0000000 --- a/contracts/impl/Admin.sol +++ /dev/null @@ -1,122 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - -import {Storage} from "./Storage.sol"; - - -/** - * @title Admin - * @author DODO Breeder - * - * @notice Functions for admin operations - */ -contract Admin is Storage { - // ============ Events ============ - - event UpdateGasPriceLimit(uint256 oldGasPriceLimit, uint256 newGasPriceLimit); - - event UpdateLiquidityProviderFeeRate( - uint256 oldLiquidityProviderFeeRate, - uint256 newLiquidityProviderFeeRate - ); - - event UpdateMaintainerFeeRate(uint256 oldMaintainerFeeRate, uint256 newMaintainerFeeRate); - - event UpdateK(uint256 oldK, uint256 newK); - - // ============ Params Setting Functions ============ - - function setOracle(address newOracle) external onlyOwner { - _ORACLE_ = newOracle; - } - - function setSupervisor(address newSupervisor) external onlyOwner { - _SUPERVISOR_ = newSupervisor; - } - - function setMaintainer(address newMaintainer) external onlyOwner { - _MAINTAINER_ = newMaintainer; - } - - function setLiquidityProviderFeeRate(uint256 newLiquidityPorviderFeeRate) external onlyOwner { - emit UpdateLiquidityProviderFeeRate(_LP_FEE_RATE_, newLiquidityPorviderFeeRate); - _LP_FEE_RATE_ = newLiquidityPorviderFeeRate; - _checkDODOParameters(); - } - - function setMaintainerFeeRate(uint256 newMaintainerFeeRate) external onlyOwner { - emit UpdateMaintainerFeeRate(_MT_FEE_RATE_, newMaintainerFeeRate); - _MT_FEE_RATE_ = newMaintainerFeeRate; - _checkDODOParameters(); - } - - function setK(uint256 newK) external onlyOwner { - emit UpdateK(_K_, newK); - _K_ = newK; - _checkDODOParameters(); - } - - function setGasPriceLimit(uint256 newGasPriceLimit) external onlySupervisorOrOwner { - emit UpdateGasPriceLimit(_GAS_PRICE_LIMIT_, newGasPriceLimit); - _GAS_PRICE_LIMIT_ = newGasPriceLimit; - } - - // ============ System Control Functions ============ - - function disableTrading() external onlySupervisorOrOwner { - _TRADE_ALLOWED_ = false; - } - - function enableTrading() external onlyOwner notClosed { - _TRADE_ALLOWED_ = true; - } - - function disableQuoteDeposit() external onlySupervisorOrOwner { - _DEPOSIT_QUOTE_ALLOWED_ = false; - } - - function enableQuoteDeposit() external onlyOwner notClosed { - _DEPOSIT_QUOTE_ALLOWED_ = true; - } - - function disableBaseDeposit() external onlySupervisorOrOwner { - _DEPOSIT_BASE_ALLOWED_ = false; - } - - function enableBaseDeposit() external onlyOwner notClosed { - _DEPOSIT_BASE_ALLOWED_ = true; - } - - // ============ Advanced Control Functions ============ - - function disableBuying() external onlySupervisorOrOwner { - _BUYING_ALLOWED_ = false; - } - - function enableBuying() external onlyOwner notClosed { - _BUYING_ALLOWED_ = true; - } - - function disableSelling() external onlySupervisorOrOwner { - _SELLING_ALLOWED_ = false; - } - - function enableSelling() external onlyOwner notClosed { - _SELLING_ALLOWED_ = true; - } - - function setBaseBalanceLimit(uint256 newBaseBalanceLimit) external onlyOwner notClosed { - _BASE_BALANCE_LIMIT_ = newBaseBalanceLimit; - } - - function setQuoteBalanceLimit(uint256 newQuoteBalanceLimit) external onlyOwner notClosed { - _QUOTE_BALANCE_LIMIT_ = newQuoteBalanceLimit; - } -} diff --git a/contracts/impl/DODOLpToken.sol b/contracts/impl/DODOLpToken.sol deleted file mode 100644 index 33e47b7..0000000 --- a/contracts/impl/DODOLpToken.sol +++ /dev/null @@ -1,134 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - -import {IERC20} from "../intf/IERC20.sol"; -import {SafeMath} from "../lib/SafeMath.sol"; -import {Ownable} from "../lib/Ownable.sol"; - -/** - * @title DODOLpToken - * @author DODO Breeder - * - * @notice Tokenize liquidity pool assets. An ordinary ERC20 contract with mint and burn functions - */ -contract DODOLpToken is Ownable { - using SafeMath for uint256; - - string public symbol = "DLP"; - address public originToken; - - uint256 public totalSupply; - mapping(address => uint256) internal balances; - mapping(address => mapping(address => uint256)) internal allowed; - - // ============ Events ============ - - event Transfer(address indexed from, address indexed to, uint256 amount); - - event Approval(address indexed owner, address indexed spender, uint256 amount); - - event Mint(address indexed user, uint256 value); - - event Burn(address indexed user, uint256 value); - - // ============ Functions ============ - - constructor(address _originToken) public { - originToken = _originToken; - } - - function name() public view returns (string memory) { - string memory lpTokenSuffix = "_DODO_LP_TOKEN_"; - return string(abi.encodePacked(IERC20(originToken).name(), lpTokenSuffix)); - } - - function decimals() public view returns (uint8) { - return IERC20(originToken).decimals(); - } - - /** - * @dev transfer token for a specified address - * @param to The address to transfer to. - * @param amount The amount to be transferred. - */ - function transfer(address to, uint256 amount) public returns (bool) { - require(amount <= balances[msg.sender], "BALANCE_NOT_ENOUGH"); - - balances[msg.sender] = balances[msg.sender].sub(amount); - balances[to] = balances[to].add(amount); - emit Transfer(msg.sender, to, amount); - return true; - } - - /** - * @dev Gets the balance of the specified address. - * @param owner The address to query the the balance of. - * @return balance An uint256 representing the amount owned by the passed address. - */ - function balanceOf(address owner) external view returns (uint256 balance) { - return balances[owner]; - } - - /** - * @dev Transfer tokens from one address to another - * @param from address The address which you want to send tokens from - * @param to address The address which you want to transfer to - * @param amount uint256 the amount of tokens to be transferred - */ - function transferFrom( - address from, - address to, - uint256 amount - ) public returns (bool) { - require(amount <= balances[from], "BALANCE_NOT_ENOUGH"); - require(amount <= allowed[from][msg.sender], "ALLOWANCE_NOT_ENOUGH"); - - balances[from] = balances[from].sub(amount); - balances[to] = balances[to].add(amount); - allowed[from][msg.sender] = allowed[from][msg.sender].sub(amount); - emit Transfer(from, to, amount); - return true; - } - - /** - * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. - * @param spender The address which will spend the funds. - * @param amount The amount of tokens to be spent. - */ - function approve(address spender, uint256 amount) public returns (bool) { - allowed[msg.sender][spender] = amount; - emit Approval(msg.sender, spender, amount); - return true; - } - - /** - * @dev Function to check the amount of tokens that an owner allowed to a spender. - * @param owner address The address which owns the funds. - * @param spender address The address which will spend the funds. - * @return A uint256 specifying the amount of tokens still available for the spender. - */ - function allowance(address owner, address spender) public view returns (uint256) { - return allowed[owner][spender]; - } - - function mint(address user, uint256 value) external onlyOwner { - balances[user] = balances[user].add(value); - totalSupply = totalSupply.add(value); - emit Mint(user, value); - emit Transfer(address(0), user, value); - } - - function burn(address user, uint256 value) external onlyOwner { - balances[user] = balances[user].sub(value); - totalSupply = totalSupply.sub(value); - emit Burn(user, value); - emit Transfer(user, address(0), value); - } -} diff --git a/contracts/impl/LiquidityProvider.sol b/contracts/impl/LiquidityProvider.sol deleted file mode 100644 index 237209d..0000000 --- a/contracts/impl/LiquidityProvider.sol +++ /dev/null @@ -1,345 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - -import {SafeMath} from "../lib/SafeMath.sol"; -import {DecimalMath} from "../lib/DecimalMath.sol"; -import {DODOMath} from "../lib/DODOMath.sol"; -import {Types} from "../lib/Types.sol"; -import {IDODOLpToken} from "../intf/IDODOLpToken.sol"; -import {Storage} from "./Storage.sol"; -import {Settlement} from "./Settlement.sol"; -import {Pricing} from "./Pricing.sol"; - - -/** - * @title LiquidityProvider - * @author DODO Breeder - * - * @notice Functions for liquidity provider operations - */ -contract LiquidityProvider is Storage, Pricing, Settlement { - using SafeMath for uint256; - - // ============ Events ============ - - event Deposit( - address indexed payer, - address indexed receiver, - bool isBaseToken, - uint256 amount, - uint256 lpTokenAmount - ); - - event Withdraw( - address indexed payer, - address indexed receiver, - bool isBaseToken, - uint256 amount, - uint256 lpTokenAmount - ); - - event ChargePenalty(address indexed payer, bool isBaseToken, uint256 amount); - - // ============ Modifiers ============ - - modifier depositQuoteAllowed() { - require(_DEPOSIT_QUOTE_ALLOWED_, "DEPOSIT_QUOTE_NOT_ALLOWED"); - _; - } - - modifier depositBaseAllowed() { - require(_DEPOSIT_BASE_ALLOWED_, "DEPOSIT_BASE_NOT_ALLOWED"); - _; - } - - modifier dodoNotClosed() { - require(!_CLOSED_, "DODO_CLOSED"); - _; - } - - // ============ Routine Functions ============ - - function withdrawBase(uint256 amount) external returns (uint256) { - return withdrawBaseTo(msg.sender, amount); - } - - function depositBase(uint256 amount) external returns (uint256) { - return depositBaseTo(msg.sender, amount); - } - - function withdrawQuote(uint256 amount) external returns (uint256) { - return withdrawQuoteTo(msg.sender, amount); - } - - function depositQuote(uint256 amount) external returns (uint256) { - return depositQuoteTo(msg.sender, amount); - } - - function withdrawAllBase() external returns (uint256) { - return withdrawAllBaseTo(msg.sender); - } - - function withdrawAllQuote() external returns (uint256) { - return withdrawAllQuoteTo(msg.sender); - } - - // ============ Deposit Functions ============ - - function depositQuoteTo(address to, uint256 amount) - public - preventReentrant - depositQuoteAllowed - returns (uint256) - { - (, uint256 quoteTarget) = getExpectedTarget(); - uint256 totalQuoteCapital = getTotalQuoteCapital(); - uint256 capital = amount; - if (totalQuoteCapital == 0) { - // give remaining quote token to lp as a gift - capital = amount.add(quoteTarget); - } else if (quoteTarget > 0) { - capital = amount.mul(totalQuoteCapital).div(quoteTarget); - } - - // settlement - _quoteTokenTransferIn(msg.sender, amount); - _mintQuoteCapital(to, capital); - _TARGET_QUOTE_TOKEN_AMOUNT_ = _TARGET_QUOTE_TOKEN_AMOUNT_.add(amount); - - emit Deposit(msg.sender, to, false, amount, capital); - return capital; - } - - function depositBaseTo(address to, uint256 amount) - public - preventReentrant - depositBaseAllowed - returns (uint256) - { - (uint256 baseTarget, ) = getExpectedTarget(); - uint256 totalBaseCapital = getTotalBaseCapital(); - uint256 capital = amount; - if (totalBaseCapital == 0) { - // give remaining base token to lp as a gift - capital = amount.add(baseTarget); - } else if (baseTarget > 0) { - capital = amount.mul(totalBaseCapital).div(baseTarget); - } - - // settlement - _baseTokenTransferIn(msg.sender, amount); - _mintBaseCapital(to, capital); - _TARGET_BASE_TOKEN_AMOUNT_ = _TARGET_BASE_TOKEN_AMOUNT_.add(amount); - - emit Deposit(msg.sender, to, true, amount, capital); - return capital; - } - - // ============ Withdraw Functions ============ - - function withdrawQuoteTo(address to, uint256 amount) - public - preventReentrant - dodoNotClosed - returns (uint256) - { - // calculate capital - (, uint256 quoteTarget) = getExpectedTarget(); - uint256 totalQuoteCapital = getTotalQuoteCapital(); - require(totalQuoteCapital > 0, "NO_QUOTE_LP"); - - uint256 requireQuoteCapital = amount.mul(totalQuoteCapital).divCeil(quoteTarget); - require( - requireQuoteCapital <= getQuoteCapitalBalanceOf(msg.sender), - "LP_QUOTE_CAPITAL_BALANCE_NOT_ENOUGH" - ); - - // handle penalty, penalty may exceed amount - uint256 penalty = getWithdrawQuotePenalty(amount); - require(penalty < amount, "PENALTY_EXCEED"); - - // settlement - _TARGET_QUOTE_TOKEN_AMOUNT_ = _TARGET_QUOTE_TOKEN_AMOUNT_.sub(amount); - _burnQuoteCapital(msg.sender, requireQuoteCapital); - _quoteTokenTransferOut(to, amount.sub(penalty)); - _donateQuoteToken(penalty); - - emit Withdraw(msg.sender, to, false, amount.sub(penalty), requireQuoteCapital); - emit ChargePenalty(msg.sender, false, penalty); - - return amount.sub(penalty); - } - - function withdrawBaseTo(address to, uint256 amount) - public - preventReentrant - dodoNotClosed - returns (uint256) - { - // calculate capital - (uint256 baseTarget, ) = getExpectedTarget(); - uint256 totalBaseCapital = getTotalBaseCapital(); - require(totalBaseCapital > 0, "NO_BASE_LP"); - - uint256 requireBaseCapital = amount.mul(totalBaseCapital).divCeil(baseTarget); - require( - requireBaseCapital <= getBaseCapitalBalanceOf(msg.sender), - "LP_BASE_CAPITAL_BALANCE_NOT_ENOUGH" - ); - - // handle penalty, penalty may exceed amount - uint256 penalty = getWithdrawBasePenalty(amount); - require(penalty <= amount, "PENALTY_EXCEED"); - - // settlement - _TARGET_BASE_TOKEN_AMOUNT_ = _TARGET_BASE_TOKEN_AMOUNT_.sub(amount); - _burnBaseCapital(msg.sender, requireBaseCapital); - _baseTokenTransferOut(to, amount.sub(penalty)); - _donateBaseToken(penalty); - - emit Withdraw(msg.sender, to, true, amount.sub(penalty), requireBaseCapital); - emit ChargePenalty(msg.sender, true, penalty); - - return amount.sub(penalty); - } - - // ============ Withdraw all Functions ============ - - function withdrawAllQuoteTo(address to) - public - preventReentrant - dodoNotClosed - returns (uint256) - { - uint256 withdrawAmount = getLpQuoteBalance(msg.sender); - uint256 capital = getQuoteCapitalBalanceOf(msg.sender); - - // handle penalty, penalty may exceed amount - uint256 penalty = getWithdrawQuotePenalty(withdrawAmount); - require(penalty <= withdrawAmount, "PENALTY_EXCEED"); - - // settlement - _TARGET_QUOTE_TOKEN_AMOUNT_ = _TARGET_QUOTE_TOKEN_AMOUNT_.sub(withdrawAmount); - _burnQuoteCapital(msg.sender, capital); - _quoteTokenTransferOut(to, withdrawAmount.sub(penalty)); - _donateQuoteToken(penalty); - - emit Withdraw(msg.sender, to, false, withdrawAmount, capital); - emit ChargePenalty(msg.sender, false, penalty); - - return withdrawAmount.sub(penalty); - } - - function withdrawAllBaseTo(address to) public preventReentrant dodoNotClosed returns (uint256) { - uint256 withdrawAmount = getLpBaseBalance(msg.sender); - uint256 capital = getBaseCapitalBalanceOf(msg.sender); - - // handle penalty, penalty may exceed amount - uint256 penalty = getWithdrawBasePenalty(withdrawAmount); - require(penalty <= withdrawAmount, "PENALTY_EXCEED"); - - // settlement - _TARGET_BASE_TOKEN_AMOUNT_ = _TARGET_BASE_TOKEN_AMOUNT_.sub(withdrawAmount); - _burnBaseCapital(msg.sender, capital); - _baseTokenTransferOut(to, withdrawAmount.sub(penalty)); - _donateBaseToken(penalty); - - emit Withdraw(msg.sender, to, true, withdrawAmount, capital); - emit ChargePenalty(msg.sender, true, penalty); - - return withdrawAmount.sub(penalty); - } - - // ============ Helper Functions ============ - - function _mintBaseCapital(address user, uint256 amount) internal { - IDODOLpToken(_BASE_CAPITAL_TOKEN_).mint(user, amount); - } - - function _mintQuoteCapital(address user, uint256 amount) internal { - IDODOLpToken(_QUOTE_CAPITAL_TOKEN_).mint(user, amount); - } - - function _burnBaseCapital(address user, uint256 amount) internal { - IDODOLpToken(_BASE_CAPITAL_TOKEN_).burn(user, amount); - } - - function _burnQuoteCapital(address user, uint256 amount) internal { - IDODOLpToken(_QUOTE_CAPITAL_TOKEN_).burn(user, amount); - } - - // ============ Getter Functions ============ - - function getLpBaseBalance(address lp) public view returns (uint256 lpBalance) { - uint256 totalBaseCapital = getTotalBaseCapital(); - (uint256 baseTarget, ) = getExpectedTarget(); - if (totalBaseCapital == 0) { - return 0; - } - lpBalance = getBaseCapitalBalanceOf(lp).mul(baseTarget).div(totalBaseCapital); - return lpBalance; - } - - function getLpQuoteBalance(address lp) public view returns (uint256 lpBalance) { - uint256 totalQuoteCapital = getTotalQuoteCapital(); - (, uint256 quoteTarget) = getExpectedTarget(); - if (totalQuoteCapital == 0) { - return 0; - } - lpBalance = getQuoteCapitalBalanceOf(lp).mul(quoteTarget).div(totalQuoteCapital); - return lpBalance; - } - - function getWithdrawQuotePenalty(uint256 amount) public view returns (uint256 penalty) { - require(amount <= _QUOTE_BALANCE_, "DODO_QUOTE_BALANCE_NOT_ENOUGH"); - if (_R_STATUS_ == Types.RStatus.BELOW_ONE) { - uint256 spareBase = _BASE_BALANCE_.sub(_TARGET_BASE_TOKEN_AMOUNT_); - uint256 price = getOraclePrice(); - uint256 fairAmount = DecimalMath.mul(spareBase, price); - uint256 targetQuote = DODOMath._SolveQuadraticFunctionForTarget( - _QUOTE_BALANCE_, - _K_, - fairAmount - ); - // if amount = _QUOTE_BALANCE_, div error - uint256 targetQuoteWithWithdraw = DODOMath._SolveQuadraticFunctionForTarget( - _QUOTE_BALANCE_.sub(amount), - _K_, - fairAmount - ); - return targetQuote.sub(targetQuoteWithWithdraw.add(amount)); - } else { - return 0; - } - } - - function getWithdrawBasePenalty(uint256 amount) public view returns (uint256 penalty) { - require(amount <= _BASE_BALANCE_, "DODO_BASE_BALANCE_NOT_ENOUGH"); - if (_R_STATUS_ == Types.RStatus.ABOVE_ONE) { - uint256 spareQuote = _QUOTE_BALANCE_.sub(_TARGET_QUOTE_TOKEN_AMOUNT_); - uint256 price = getOraclePrice(); - uint256 fairAmount = DecimalMath.divFloor(spareQuote, price); - uint256 targetBase = DODOMath._SolveQuadraticFunctionForTarget( - _BASE_BALANCE_, - _K_, - fairAmount - ); - // if amount = _BASE_BALANCE_, div error - uint256 targetBaseWithWithdraw = DODOMath._SolveQuadraticFunctionForTarget( - _BASE_BALANCE_.sub(amount), - _K_, - fairAmount - ); - return targetBase.sub(targetBaseWithWithdraw.add(amount)); - } else { - return 0; - } - } -} diff --git a/contracts/impl/Pricing.sol b/contracts/impl/Pricing.sol deleted file mode 100644 index ce45235..0000000 --- a/contracts/impl/Pricing.sol +++ /dev/null @@ -1,198 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - -import {SafeMath} from "../lib/SafeMath.sol"; -import {DecimalMath} from "../lib/DecimalMath.sol"; -import {DODOMath} from "../lib/DODOMath.sol"; -import {Types} from "../lib/Types.sol"; -import {Storage} from "./Storage.sol"; - - -/** - * @title Pricing - * @author DODO Breeder - * - * @notice DODO Pricing model - */ -contract Pricing is Storage { - using SafeMath for uint256; - - // ============ R = 1 cases ============ - - function _ROneSellBaseToken(uint256 amount, uint256 targetQuoteTokenAmount) - internal - view - returns (uint256 receiveQuoteToken) - { - uint256 i = getOraclePrice(); - uint256 Q2 = DODOMath._SolveQuadraticFunctionForTrade( - targetQuoteTokenAmount, - targetQuoteTokenAmount, - DecimalMath.mul(i, amount), - false, - _K_ - ); - // in theory Q2 <= targetQuoteTokenAmount - // however when amount is close to 0, precision problems may cause Q2 > targetQuoteTokenAmount - return targetQuoteTokenAmount.sub(Q2); - } - - function _ROneBuyBaseToken(uint256 amount, uint256 targetBaseTokenAmount) - internal - view - returns (uint256 payQuoteToken) - { - require(amount < targetBaseTokenAmount, "DODO_BASE_BALANCE_NOT_ENOUGH"); - uint256 B2 = targetBaseTokenAmount.sub(amount); - payQuoteToken = _RAboveIntegrate(targetBaseTokenAmount, targetBaseTokenAmount, B2); - return payQuoteToken; - } - - // ============ R < 1 cases ============ - - function _RBelowSellBaseToken( - uint256 amount, - uint256 quoteBalance, - uint256 targetQuoteAmount - ) internal view returns (uint256 receieQuoteToken) { - uint256 i = getOraclePrice(); - uint256 Q2 = DODOMath._SolveQuadraticFunctionForTrade( - targetQuoteAmount, - quoteBalance, - DecimalMath.mul(i, amount), - false, - _K_ - ); - return quoteBalance.sub(Q2); - } - - function _RBelowBuyBaseToken( - uint256 amount, - uint256 quoteBalance, - uint256 targetQuoteAmount - ) internal view returns (uint256 payQuoteToken) { - // Here we don't require amount less than some value - // Because it is limited at upper function - // See Trader.queryBuyBaseToken - uint256 i = getOraclePrice(); - uint256 Q2 = DODOMath._SolveQuadraticFunctionForTrade( - targetQuoteAmount, - quoteBalance, - DecimalMath.mulCeil(i, amount), - true, - _K_ - ); - return Q2.sub(quoteBalance); - } - - function _RBelowBackToOne() internal view returns (uint256 payQuoteToken) { - // important: carefully design the system to make sure spareBase always greater than or equal to 0 - uint256 spareBase = _BASE_BALANCE_.sub(_TARGET_BASE_TOKEN_AMOUNT_); - uint256 price = getOraclePrice(); - uint256 fairAmount = DecimalMath.mul(spareBase, price); - uint256 newTargetQuote = DODOMath._SolveQuadraticFunctionForTarget( - _QUOTE_BALANCE_, - _K_, - fairAmount - ); - return newTargetQuote.sub(_QUOTE_BALANCE_); - } - - // ============ R > 1 cases ============ - - function _RAboveBuyBaseToken( - uint256 amount, - uint256 baseBalance, - uint256 targetBaseAmount - ) internal view returns (uint256 payQuoteToken) { - require(amount < baseBalance, "DODO_BASE_BALANCE_NOT_ENOUGH"); - uint256 B2 = baseBalance.sub(amount); - return _RAboveIntegrate(targetBaseAmount, baseBalance, B2); - } - - function _RAboveSellBaseToken( - uint256 amount, - uint256 baseBalance, - uint256 targetBaseAmount - ) internal view returns (uint256 receiveQuoteToken) { - // here we don't require B1 <= targetBaseAmount - // Because it is limited at upper function - // See Trader.querySellBaseToken - uint256 B1 = baseBalance.add(amount); - return _RAboveIntegrate(targetBaseAmount, B1, baseBalance); - } - - function _RAboveBackToOne() internal view returns (uint256 payBaseToken) { - // important: carefully design the system to make sure spareBase always greater than or equal to 0 - uint256 spareQuote = _QUOTE_BALANCE_.sub(_TARGET_QUOTE_TOKEN_AMOUNT_); - uint256 price = getOraclePrice(); - uint256 fairAmount = DecimalMath.divFloor(spareQuote, price); - uint256 newTargetBase = DODOMath._SolveQuadraticFunctionForTarget( - _BASE_BALANCE_, - _K_, - fairAmount - ); - return newTargetBase.sub(_BASE_BALANCE_); - } - - // ============ Helper functions ============ - - function getExpectedTarget() public view returns (uint256 baseTarget, uint256 quoteTarget) { - uint256 Q = _QUOTE_BALANCE_; - uint256 B = _BASE_BALANCE_; - if (_R_STATUS_ == Types.RStatus.ONE) { - return (_TARGET_BASE_TOKEN_AMOUNT_, _TARGET_QUOTE_TOKEN_AMOUNT_); - } else if (_R_STATUS_ == Types.RStatus.BELOW_ONE) { - uint256 payQuoteToken = _RBelowBackToOne(); - return (_TARGET_BASE_TOKEN_AMOUNT_, Q.add(payQuoteToken)); - } else if (_R_STATUS_ == Types.RStatus.ABOVE_ONE) { - uint256 payBaseToken = _RAboveBackToOne(); - return (B.add(payBaseToken), _TARGET_QUOTE_TOKEN_AMOUNT_); - } - } - - function getMidPrice() public view returns (uint256 midPrice) { - (uint256 baseTarget, uint256 quoteTarget) = getExpectedTarget(); - if (_R_STATUS_ == Types.RStatus.BELOW_ONE) { - uint256 R = DecimalMath.divFloor( - quoteTarget.mul(quoteTarget).div(_QUOTE_BALANCE_), - _QUOTE_BALANCE_ - ); - R = DecimalMath.ONE.sub(_K_).add(DecimalMath.mul(_K_, R)); - return DecimalMath.divFloor(getOraclePrice(), R); - } else { - uint256 R = DecimalMath.divFloor( - baseTarget.mul(baseTarget).div(_BASE_BALANCE_), - _BASE_BALANCE_ - ); - R = DecimalMath.ONE.sub(_K_).add(DecimalMath.mul(_K_, R)); - return DecimalMath.mul(getOraclePrice(), R); - } - } - - function _RAboveIntegrate( - uint256 B0, - uint256 B1, - uint256 B2 - ) internal view returns (uint256) { - uint256 i = getOraclePrice(); - return DODOMath._GeneralIntegrate(B0, B1, B2, i, _K_); - } - - // function _RBelowIntegrate( - // uint256 Q0, - // uint256 Q1, - // uint256 Q2 - // ) internal view returns (uint256) { - // uint256 i = getOraclePrice(); - // i = DecimalMath.divFloor(DecimalMath.ONE, i); // 1/i - // return DODOMath._GeneralIntegrate(Q0, Q1, Q2, i, _K_); - // } -} diff --git a/contracts/impl/Settlement.sol b/contracts/impl/Settlement.sol deleted file mode 100644 index ac6e2bd..0000000 --- a/contracts/impl/Settlement.sol +++ /dev/null @@ -1,163 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - -import {SafeMath} from "../lib/SafeMath.sol"; -import {SafeERC20} from "../lib/SafeERC20.sol"; -import {DecimalMath} from "../lib/DecimalMath.sol"; -import {Types} from "../lib/Types.sol"; -import {IDODOLpToken} from "../intf/IDODOLpToken.sol"; -import {IERC20} from "../intf/IERC20.sol"; -import {Storage} from "./Storage.sol"; - - -/** - * @title Settlement - * @author DODO Breeder - * - * @notice Functions for assets settlement - */ -contract Settlement is Storage { - using SafeMath for uint256; - using SafeERC20 for IERC20; - - // ============ Events ============ - - event Donate(uint256 amount, bool isBaseToken); - - event ClaimAssets(address indexed user, uint256 baseTokenAmount, uint256 quoteTokenAmount); - - // ============ Assets IN/OUT Functions ============ - - function _baseTokenTransferIn(address from, uint256 amount) internal { - require(_BASE_BALANCE_.add(amount) <= _BASE_BALANCE_LIMIT_, "BASE_BALANCE_LIMIT_EXCEEDED"); - IERC20(_BASE_TOKEN_).safeTransferFrom(from, address(this), amount); - _BASE_BALANCE_ = _BASE_BALANCE_.add(amount); - } - - function _quoteTokenTransferIn(address from, uint256 amount) internal { - require( - _QUOTE_BALANCE_.add(amount) <= _QUOTE_BALANCE_LIMIT_, - "QUOTE_BALANCE_LIMIT_EXCEEDED" - ); - IERC20(_QUOTE_TOKEN_).safeTransferFrom(from, address(this), amount); - _QUOTE_BALANCE_ = _QUOTE_BALANCE_.add(amount); - } - - function _baseTokenTransferOut(address to, uint256 amount) internal { - IERC20(_BASE_TOKEN_).safeTransfer(to, amount); - _BASE_BALANCE_ = _BASE_BALANCE_.sub(amount); - } - - function _quoteTokenTransferOut(address to, uint256 amount) internal { - IERC20(_QUOTE_TOKEN_).safeTransfer(to, amount); - _QUOTE_BALANCE_ = _QUOTE_BALANCE_.sub(amount); - } - - // ============ Donate to Liquidity Pool Functions ============ - - function _donateBaseToken(uint256 amount) internal { - _TARGET_BASE_TOKEN_AMOUNT_ = _TARGET_BASE_TOKEN_AMOUNT_.add(amount); - emit Donate(amount, true); - } - - function _donateQuoteToken(uint256 amount) internal { - _TARGET_QUOTE_TOKEN_AMOUNT_ = _TARGET_QUOTE_TOKEN_AMOUNT_.add(amount); - emit Donate(amount, false); - } - - function donateBaseToken(uint256 amount) external preventReentrant { - _baseTokenTransferIn(msg.sender, amount); - _donateBaseToken(amount); - } - - function donateQuoteToken(uint256 amount) external preventReentrant { - _quoteTokenTransferIn(msg.sender, amount); - _donateQuoteToken(amount); - } - - // ============ Final Settlement Functions ============ - - // last step to shut down dodo - function finalSettlement() external onlyOwner notClosed { - _CLOSED_ = true; - _DEPOSIT_QUOTE_ALLOWED_ = false; - _DEPOSIT_BASE_ALLOWED_ = false; - _TRADE_ALLOWED_ = false; - uint256 totalBaseCapital = getTotalBaseCapital(); - uint256 totalQuoteCapital = getTotalQuoteCapital(); - - if (_QUOTE_BALANCE_ > _TARGET_QUOTE_TOKEN_AMOUNT_) { - uint256 spareQuote = _QUOTE_BALANCE_.sub(_TARGET_QUOTE_TOKEN_AMOUNT_); - _BASE_CAPITAL_RECEIVE_QUOTE_ = DecimalMath.divFloor(spareQuote, totalBaseCapital); - } else { - _TARGET_QUOTE_TOKEN_AMOUNT_ = _QUOTE_BALANCE_; - } - - if (_BASE_BALANCE_ > _TARGET_BASE_TOKEN_AMOUNT_) { - uint256 spareBase = _BASE_BALANCE_.sub(_TARGET_BASE_TOKEN_AMOUNT_); - _QUOTE_CAPITAL_RECEIVE_BASE_ = DecimalMath.divFloor(spareBase, totalQuoteCapital); - } else { - _TARGET_BASE_TOKEN_AMOUNT_ = _BASE_BALANCE_; - } - - _R_STATUS_ = Types.RStatus.ONE; - } - - // claim remaining assets after final settlement - function claimAssets() external preventReentrant { - require(_CLOSED_, "DODO_NOT_CLOSED"); - require(!_CLAIMED_[msg.sender], "ALREADY_CLAIMED"); - _CLAIMED_[msg.sender] = true; - - uint256 quoteCapital = getQuoteCapitalBalanceOf(msg.sender); - uint256 baseCapital = getBaseCapitalBalanceOf(msg.sender); - - uint256 quoteAmount = 0; - if (quoteCapital > 0) { - quoteAmount = _TARGET_QUOTE_TOKEN_AMOUNT_.mul(quoteCapital).div(getTotalQuoteCapital()); - } - uint256 baseAmount = 0; - if (baseCapital > 0) { - baseAmount = _TARGET_BASE_TOKEN_AMOUNT_.mul(baseCapital).div(getTotalBaseCapital()); - } - - _TARGET_QUOTE_TOKEN_AMOUNT_ = _TARGET_QUOTE_TOKEN_AMOUNT_.sub(quoteAmount); - _TARGET_BASE_TOKEN_AMOUNT_ = _TARGET_BASE_TOKEN_AMOUNT_.sub(baseAmount); - - quoteAmount = quoteAmount.add(DecimalMath.mul(baseCapital, _BASE_CAPITAL_RECEIVE_QUOTE_)); - baseAmount = baseAmount.add(DecimalMath.mul(quoteCapital, _QUOTE_CAPITAL_RECEIVE_BASE_)); - - _baseTokenTransferOut(msg.sender, baseAmount); - _quoteTokenTransferOut(msg.sender, quoteAmount); - - IDODOLpToken(_BASE_CAPITAL_TOKEN_).burn(msg.sender, baseCapital); - IDODOLpToken(_QUOTE_CAPITAL_TOKEN_).burn(msg.sender, quoteCapital); - - emit ClaimAssets(msg.sender, baseAmount, quoteAmount); - return; - } - - // in case someone transfer to contract directly - function retrieve(address token, uint256 amount) external onlyOwner { - if (token == _BASE_TOKEN_) { - require( - IERC20(_BASE_TOKEN_).balanceOf(address(this)) >= _BASE_BALANCE_.add(amount), - "DODO_BASE_BALANCE_NOT_ENOUGH" - ); - } - if (token == _QUOTE_TOKEN_) { - require( - IERC20(_QUOTE_TOKEN_).balanceOf(address(this)) >= _QUOTE_BALANCE_.add(amount), - "DODO_QUOTE_BALANCE_NOT_ENOUGH" - ); - } - IERC20(token).safeTransfer(msg.sender, amount); - } -} diff --git a/contracts/impl/Storage.sol b/contracts/impl/Storage.sol deleted file mode 100644 index 7828bde..0000000 --- a/contracts/impl/Storage.sol +++ /dev/null @@ -1,118 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - -import {InitializableOwnable} from "../lib/InitializableOwnable.sol"; -import {SafeMath} from "../lib/SafeMath.sol"; -import {DecimalMath} from "../lib/DecimalMath.sol"; -import {ReentrancyGuard} from "../lib/ReentrancyGuard.sol"; -import {IOracle} from "../intf/IOracle.sol"; -import {IDODOLpToken} from "../intf/IDODOLpToken.sol"; -import {Types} from "../lib/Types.sol"; - - -/** - * @title Storage - * @author DODO Breeder - * - * @notice Local Variables - */ -contract Storage is InitializableOwnable, ReentrancyGuard { - using SafeMath for uint256; - - // ============ Variables for Control ============ - - bool internal _INITIALIZED_; - bool public _CLOSED_; - bool public _DEPOSIT_QUOTE_ALLOWED_; - bool public _DEPOSIT_BASE_ALLOWED_; - bool public _TRADE_ALLOWED_; - uint256 public _GAS_PRICE_LIMIT_; - - // ============ Advanced Controls ============ - bool public _BUYING_ALLOWED_; - bool public _SELLING_ALLOWED_; - uint256 public _BASE_BALANCE_LIMIT_; - uint256 public _QUOTE_BALANCE_LIMIT_; - - // ============ Core Address ============ - - address public _SUPERVISOR_; // could freeze system in emergency - address public _MAINTAINER_; // collect maintainer fee to buy food for DODO - - address public _BASE_TOKEN_; - address public _QUOTE_TOKEN_; - address public _ORACLE_; - - // ============ Variables for PMM Algorithm ============ - - uint256 public _LP_FEE_RATE_; - uint256 public _MT_FEE_RATE_; - uint256 public _K_; - - Types.RStatus public _R_STATUS_; - uint256 public _TARGET_BASE_TOKEN_AMOUNT_; - uint256 public _TARGET_QUOTE_TOKEN_AMOUNT_; - uint256 public _BASE_BALANCE_; - uint256 public _QUOTE_BALANCE_; - - address public _BASE_CAPITAL_TOKEN_; - address public _QUOTE_CAPITAL_TOKEN_; - - // ============ Variables for Final Settlement ============ - - uint256 public _BASE_CAPITAL_RECEIVE_QUOTE_; - uint256 public _QUOTE_CAPITAL_RECEIVE_BASE_; - mapping(address => bool) public _CLAIMED_; - - // ============ Modifiers ============ - - modifier onlySupervisorOrOwner() { - require(msg.sender == _SUPERVISOR_ || msg.sender == _OWNER_, "NOT_SUPERVISOR_OR_OWNER"); - _; - } - - modifier notClosed() { - require(!_CLOSED_, "DODO_CLOSED"); - _; - } - - // ============ Helper Functions ============ - - function _checkDODOParameters() internal view returns (uint256) { - require(_K_ < DecimalMath.ONE, "K>=1"); - require(_K_ > 0, "K=0"); - require(_LP_FEE_RATE_.add(_MT_FEE_RATE_) < DecimalMath.ONE, "FEE_RATE>=1"); - } - - function getOraclePrice() public view returns (uint256) { - return IOracle(_ORACLE_).getPrice(); - } - - function getBaseCapitalBalanceOf(address lp) public view returns (uint256) { - return IDODOLpToken(_BASE_CAPITAL_TOKEN_).balanceOf(lp); - } - - function getTotalBaseCapital() public view returns (uint256) { - return IDODOLpToken(_BASE_CAPITAL_TOKEN_).totalSupply(); - } - - function getQuoteCapitalBalanceOf(address lp) public view returns (uint256) { - return IDODOLpToken(_QUOTE_CAPITAL_TOKEN_).balanceOf(lp); - } - - function getTotalQuoteCapital() public view returns (uint256) { - return IDODOLpToken(_QUOTE_CAPITAL_TOKEN_).totalSupply(); - } - - // ============ Version Control ============ - function version() external pure returns (uint256) { - return 101; // 1.0.1 - } -} diff --git a/contracts/impl/Trader.sol b/contracts/impl/Trader.sol deleted file mode 100644 index 36d00d9..0000000 --- a/contracts/impl/Trader.sol +++ /dev/null @@ -1,274 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - -import {SafeMath} from "../lib/SafeMath.sol"; -import {DecimalMath} from "../lib/DecimalMath.sol"; -import {Types} from "../lib/Types.sol"; -import {IDODOCallee} from "../intf/IDODOCallee.sol"; -import {Storage} from "./Storage.sol"; -import {Pricing} from "./Pricing.sol"; -import {Settlement} from "./Settlement.sol"; - - -/** - * @title Trader - * @author DODO Breeder - * - * @notice Functions for trader operations - */ -contract Trader is Storage, Pricing, Settlement { - using SafeMath for uint256; - - // ============ Events ============ - - event SellBaseToken(address indexed seller, uint256 payBase, uint256 receiveQuote); - - event BuyBaseToken(address indexed buyer, uint256 receiveBase, uint256 payQuote); - - event ChargeMaintainerFee(address indexed maintainer, bool isBaseToken, uint256 amount); - - // ============ Modifiers ============ - - modifier tradeAllowed() { - require(_TRADE_ALLOWED_, "TRADE_NOT_ALLOWED"); - _; - } - - modifier buyingAllowed() { - require(_BUYING_ALLOWED_, "BUYING_NOT_ALLOWED"); - _; - } - - modifier sellingAllowed() { - require(_SELLING_ALLOWED_, "SELLING_NOT_ALLOWED"); - _; - } - - modifier gasPriceLimit() { - require(tx.gasprice <= _GAS_PRICE_LIMIT_, "GAS_PRICE_EXCEED"); - _; - } - - // ============ Trade Functions ============ - - function sellBaseToken( - uint256 amount, - uint256 minReceiveQuote, - bytes calldata data - ) external tradeAllowed sellingAllowed gasPriceLimit preventReentrant returns (uint256) { - // query price - ( - uint256 receiveQuote, - uint256 lpFeeQuote, - uint256 mtFeeQuote, - Types.RStatus newRStatus, - uint256 newQuoteTarget, - uint256 newBaseTarget - ) = _querySellBaseToken(amount); - require(receiveQuote >= minReceiveQuote, "SELL_BASE_RECEIVE_NOT_ENOUGH"); - - // settle assets - _quoteTokenTransferOut(msg.sender, receiveQuote); - if (data.length > 0) { - IDODOCallee(msg.sender).dodoCall(false, amount, receiveQuote, data); - } - _baseTokenTransferIn(msg.sender, amount); - if (mtFeeQuote != 0) { - _quoteTokenTransferOut(_MAINTAINER_, mtFeeQuote); - emit ChargeMaintainerFee(_MAINTAINER_, false, mtFeeQuote); - } - - // update TARGET - if (_TARGET_QUOTE_TOKEN_AMOUNT_ != newQuoteTarget) { - _TARGET_QUOTE_TOKEN_AMOUNT_ = newQuoteTarget; - } - if (_TARGET_BASE_TOKEN_AMOUNT_ != newBaseTarget) { - _TARGET_BASE_TOKEN_AMOUNT_ = newBaseTarget; - } - if (_R_STATUS_ != newRStatus) { - _R_STATUS_ = newRStatus; - } - - _donateQuoteToken(lpFeeQuote); - emit SellBaseToken(msg.sender, amount, receiveQuote); - - return receiveQuote; - } - - function buyBaseToken( - uint256 amount, - uint256 maxPayQuote, - bytes calldata data - ) external tradeAllowed buyingAllowed gasPriceLimit preventReentrant returns (uint256) { - // query price - ( - uint256 payQuote, - uint256 lpFeeBase, - uint256 mtFeeBase, - Types.RStatus newRStatus, - uint256 newQuoteTarget, - uint256 newBaseTarget - ) = _queryBuyBaseToken(amount); - require(payQuote <= maxPayQuote, "BUY_BASE_COST_TOO_MUCH"); - - // settle assets - _baseTokenTransferOut(msg.sender, amount); - if (data.length > 0) { - IDODOCallee(msg.sender).dodoCall(true, amount, payQuote, data); - } - _quoteTokenTransferIn(msg.sender, payQuote); - if (mtFeeBase != 0) { - _baseTokenTransferOut(_MAINTAINER_, mtFeeBase); - emit ChargeMaintainerFee(_MAINTAINER_, true, mtFeeBase); - } - - // update TARGET - if (_TARGET_QUOTE_TOKEN_AMOUNT_ != newQuoteTarget) { - _TARGET_QUOTE_TOKEN_AMOUNT_ = newQuoteTarget; - } - if (_TARGET_BASE_TOKEN_AMOUNT_ != newBaseTarget) { - _TARGET_BASE_TOKEN_AMOUNT_ = newBaseTarget; - } - if (_R_STATUS_ != newRStatus) { - _R_STATUS_ = newRStatus; - } - - _donateBaseToken(lpFeeBase); - emit BuyBaseToken(msg.sender, amount, payQuote); - - return payQuote; - } - - // ============ Query Functions ============ - - function querySellBaseToken(uint256 amount) external view returns (uint256 receiveQuote) { - (receiveQuote, , , , , ) = _querySellBaseToken(amount); - return receiveQuote; - } - - function queryBuyBaseToken(uint256 amount) external view returns (uint256 payQuote) { - (payQuote, , , , , ) = _queryBuyBaseToken(amount); - return payQuote; - } - - function _querySellBaseToken(uint256 amount) - internal - view - returns ( - uint256 receiveQuote, - uint256 lpFeeQuote, - uint256 mtFeeQuote, - Types.RStatus newRStatus, - uint256 newQuoteTarget, - uint256 newBaseTarget - ) - { - (newBaseTarget, newQuoteTarget) = getExpectedTarget(); - - uint256 sellBaseAmount = amount; - - if (_R_STATUS_ == Types.RStatus.ONE) { - // case 1: R=1 - // R falls below one - receiveQuote = _ROneSellBaseToken(sellBaseAmount, newQuoteTarget); - newRStatus = Types.RStatus.BELOW_ONE; - } else if (_R_STATUS_ == Types.RStatus.ABOVE_ONE) { - uint256 backToOnePayBase = newBaseTarget.sub(_BASE_BALANCE_); - uint256 backToOneReceiveQuote = _QUOTE_BALANCE_.sub(newQuoteTarget); - // case 2: R>1 - // complex case, R status depends on trading amount - if (sellBaseAmount < backToOnePayBase) { - // case 2.1: R status do not change - receiveQuote = _RAboveSellBaseToken(sellBaseAmount, _BASE_BALANCE_, newBaseTarget); - newRStatus = Types.RStatus.ABOVE_ONE; - if (receiveQuote > backToOneReceiveQuote) { - // [Important corner case!] may enter this branch when some precision problem happens. And consequently contribute to negative spare quote amount - // to make sure spare quote>=0, mannually set receiveQuote=backToOneReceiveQuote - receiveQuote = backToOneReceiveQuote; - } - } else if (sellBaseAmount == backToOnePayBase) { - // case 2.2: R status changes to ONE - receiveQuote = backToOneReceiveQuote; - newRStatus = Types.RStatus.ONE; - } else { - // case 2.3: R status changes to BELOW_ONE - receiveQuote = backToOneReceiveQuote.add( - _ROneSellBaseToken(sellBaseAmount.sub(backToOnePayBase), newQuoteTarget) - ); - newRStatus = Types.RStatus.BELOW_ONE; - } - } else { - // _R_STATUS_ == Types.RStatus.BELOW_ONE - // case 3: R<1 - receiveQuote = _RBelowSellBaseToken(sellBaseAmount, _QUOTE_BALANCE_, newQuoteTarget); - newRStatus = Types.RStatus.BELOW_ONE; - } - - // count fees - lpFeeQuote = DecimalMath.mul(receiveQuote, _LP_FEE_RATE_); - mtFeeQuote = DecimalMath.mul(receiveQuote, _MT_FEE_RATE_); - receiveQuote = receiveQuote.sub(lpFeeQuote).sub(mtFeeQuote); - - return (receiveQuote, lpFeeQuote, mtFeeQuote, newRStatus, newQuoteTarget, newBaseTarget); - } - - function _queryBuyBaseToken(uint256 amount) - internal - view - returns ( - uint256 payQuote, - uint256 lpFeeBase, - uint256 mtFeeBase, - Types.RStatus newRStatus, - uint256 newQuoteTarget, - uint256 newBaseTarget - ) - { - (newBaseTarget, newQuoteTarget) = getExpectedTarget(); - - // charge fee from user receive amount - lpFeeBase = DecimalMath.mul(amount, _LP_FEE_RATE_); - mtFeeBase = DecimalMath.mul(amount, _MT_FEE_RATE_); - uint256 buyBaseAmount = amount.add(lpFeeBase).add(mtFeeBase); - - if (_R_STATUS_ == Types.RStatus.ONE) { - // case 1: R=1 - payQuote = _ROneBuyBaseToken(buyBaseAmount, newBaseTarget); - newRStatus = Types.RStatus.ABOVE_ONE; - } else if (_R_STATUS_ == Types.RStatus.ABOVE_ONE) { - // case 2: R>1 - payQuote = _RAboveBuyBaseToken(buyBaseAmount, _BASE_BALANCE_, newBaseTarget); - newRStatus = Types.RStatus.ABOVE_ONE; - } else if (_R_STATUS_ == Types.RStatus.BELOW_ONE) { - uint256 backToOnePayQuote = newQuoteTarget.sub(_QUOTE_BALANCE_); - uint256 backToOneReceiveBase = _BASE_BALANCE_.sub(newBaseTarget); - // case 3: R<1 - // complex case, R status may change - if (buyBaseAmount < backToOneReceiveBase) { - // case 3.1: R status do not change - // no need to check payQuote because spare base token must be greater than zero - payQuote = _RBelowBuyBaseToken(buyBaseAmount, _QUOTE_BALANCE_, newQuoteTarget); - newRStatus = Types.RStatus.BELOW_ONE; - } else if (buyBaseAmount == backToOneReceiveBase) { - // case 3.2: R status changes to ONE - payQuote = backToOnePayQuote; - newRStatus = Types.RStatus.ONE; - } else { - // case 3.3: R status changes to ABOVE_ONE - payQuote = backToOnePayQuote.add( - _ROneBuyBaseToken(buyBaseAmount.sub(backToOneReceiveBase), newBaseTarget) - ); - newRStatus = Types.RStatus.ABOVE_ONE; - } - } - - return (payQuote, lpFeeBase, mtFeeBase, newRStatus, newQuoteTarget, newBaseTarget); - } -} diff --git a/contracts/intf/IDODO.sol b/contracts/intf/IDODO.sol deleted file mode 100644 index 4b1f6cc..0000000 --- a/contracts/intf/IDODO.sol +++ /dev/null @@ -1,67 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - - -interface IDODO { - function init( - address owner, - address supervisor, - address maintainer, - address baseToken, - address quoteToken, - address oracle, - uint256 lpFeeRate, - uint256 mtFeeRate, - uint256 k, - uint256 gasPriceLimit - ) external; - - function transferOwnership(address newOwner) external; - - function claimOwnership() external; - - function sellBaseToken( - uint256 amount, - uint256 minReceiveQuote, - bytes calldata data - ) external returns (uint256); - - function buyBaseToken( - uint256 amount, - uint256 maxPayQuote, - bytes calldata data - ) external returns (uint256); - - function querySellBaseToken(uint256 amount) external view returns (uint256 receiveQuote); - - function queryBuyBaseToken(uint256 amount) external view returns (uint256 payQuote); - - function getExpectedTarget() external view returns (uint256 baseTarget, uint256 quoteTarget); - - function depositBaseTo(address to, uint256 amount) external returns (uint256); - - function withdrawBase(uint256 amount) external returns (uint256); - - function withdrawAllBase() external returns (uint256); - - function depositQuoteTo(address to, uint256 amount) external returns (uint256); - - function withdrawQuote(uint256 amount) external returns (uint256); - - function withdrawAllQuote() external returns (uint256); - - function _BASE_CAPITAL_TOKEN_() external view returns (address); - - function _QUOTE_CAPITAL_TOKEN_() external view returns (address); - - function _BASE_TOKEN_() external returns (address); - - function _QUOTE_TOKEN_() external returns (address); -} diff --git a/contracts/intf/IDODOCallee.sol b/contracts/intf/IDODOCallee.sol deleted file mode 100644 index 3b9b70d..0000000 --- a/contracts/intf/IDODOCallee.sol +++ /dev/null @@ -1,18 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - -interface IDODOCallee { - function dodoCall( - bool isBuyBaseToken, - uint256 baseAmount, - uint256 quoteAmount, - bytes calldata data - ) external; -} diff --git a/contracts/intf/IDODOLpToken.sol b/contracts/intf/IDODOLpToken.sol deleted file mode 100644 index f1b5383..0000000 --- a/contracts/intf/IDODOLpToken.sol +++ /dev/null @@ -1,20 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity ^0.6.9; -pragma experimental ABIEncoderV2; - - -interface IDODOLpToken { - function mint(address user, uint256 value) external; - - function burn(address user, uint256 value) external; - - function balanceOf(address owner) external view returns (uint256); - - function totalSupply() external view returns (uint256); -} diff --git a/contracts/intf/IERC20.sol b/contracts/intf/IERC20.sol index 252e1f5..c1a98ed 100644 --- a/contracts/intf/IERC20.sol +++ b/contracts/intf/IERC20.sol @@ -17,6 +17,8 @@ interface IERC20 { function name() external view returns (string memory); + function symbol() external view returns (string memory); + /** * @dev Returns the amount of tokens owned by `account`. */ diff --git a/contracts/lib/Types.sol b/contracts/intf/IFeeRateModel.sol similarity index 57% rename from contracts/lib/Types.sol rename to contracts/intf/IFeeRateModel.sol index 0892400..81c3fdd 100644 --- a/contracts/lib/Types.sol +++ b/contracts/intf/IFeeRateModel.sol @@ -8,6 +8,7 @@ pragma solidity 0.6.9; pragma experimental ABIEncoderV2; -library Types { - enum RStatus {ONE, ABOVE_ONE, BELOW_ONE} + +interface IFeeRateModel { + function getFeeRate(uint256 amount) external view returns (uint256); } diff --git a/contracts/intf/IVault.sol b/contracts/intf/IVault.sol new file mode 100644 index 0000000..f616820 --- /dev/null +++ b/contracts/intf/IVault.sol @@ -0,0 +1,15 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +interface IBasicVault { + function controller() external view returns(address); + function getReserve(address token) external view returns(address); + function transferOut(address token, address to, uint256 amount) external; +} \ No newline at end of file diff --git a/contracts/helper/CloneFactory.sol b/contracts/lib/CloneFactory.sol similarity index 100% rename from contracts/helper/CloneFactory.sol rename to contracts/lib/CloneFactory.sol diff --git a/contracts/lib/DecimalMath.sol b/contracts/lib/DecimalMath.sol index 99debb1..0a406a4 100644 --- a/contracts/lib/DecimalMath.sol +++ b/contracts/lib/DecimalMath.sol @@ -26,6 +26,10 @@ library DecimalMath { return target.mul(d) / ONE; } + function mulFloor(uint256 target, uint256 d) internal pure returns (uint256) { + return target.mul(d) / ONE; + } + function mulCeil(uint256 target, uint256 d) internal pure returns (uint256) { return target.mul(d).divCeil(ONE); } diff --git a/contracts/lib/InitializableOwnable.sol b/contracts/lib/InitializableOwnable.sol index c90dde0..7d70838 100644 --- a/contracts/lib/InitializableOwnable.sol +++ b/contracts/lib/InitializableOwnable.sol @@ -17,6 +17,7 @@ pragma experimental ABIEncoderV2; contract InitializableOwnable { address public _OWNER_; address public _NEW_OWNER_; + bool internal _INITIALIZED_; // ============ Events ============ @@ -26,6 +27,11 @@ contract InitializableOwnable { // ============ Modifiers ============ + modifier notInitialized() { + require(!_INITIALIZED_, "DODO_INITIALIZED"); + _; + } + modifier onlyOwner() { require(msg.sender == _OWNER_, "NOT_OWNER"); _; @@ -33,13 +39,18 @@ contract InitializableOwnable { // ============ Functions ============ - function transferOwnership(address newOwner) external onlyOwner { + function initOwner(address newOwner) public notInitialized{ + _INITIALIZED_ = true; + _OWNER_ = newOwner; + } + + function transferOwnership(address newOwner) public onlyOwner { require(newOwner != address(0), "INVALID_OWNER"); emit OwnershipTransferPrepared(_OWNER_, newOwner); _NEW_OWNER_ = newOwner; } - function claimOwnership() external { + function claimOwnership() public { require(msg.sender == _NEW_OWNER_, "INVALID_CLAIM"); emit OwnershipTransferred(_OWNER_, _NEW_OWNER_); _OWNER_ = _NEW_OWNER_; diff --git a/contracts/lib/PermissionManager.sol b/contracts/lib/PermissionManager.sol new file mode 100644 index 0000000..e813039 --- /dev/null +++ b/contracts/lib/PermissionManager.sol @@ -0,0 +1,53 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {InitializableOwnable} from "./InitializableOwnable.sol"; + +contract PermissionManager is InitializableOwnable { + + bool public _BLACKLIST_MODE_ON_; + + mapping(address => bool) internal _whitelist_; + mapping(address => bool) internal _blacklist_; + + function isAllowed(address account) external view returns(bool){ + if (_BLACKLIST_MODE_ON_) { + return !_blacklist_[account]; + } else { + return _whitelist_[account]; + } + } + + function openBlacklist() external onlyOwner { + _BLACKLIST_MODE_ON_ = true; + } + + function openWhitelist() external onlyOwner { + _BLACKLIST_MODE_ON_ = true; + + } + + function addToWhitelist(address account) external onlyOwner{ + _whitelist_[account] = true; + } + + function removeFromWhitelist(address account) external onlyOwner{ + _whitelist_[account] = false; + } + + function addToBlacklist(address account) external onlyOwner{ + _blacklist_[account] = true; + } + + function removeFromBlacklist(address account) external onlyOwner{ + _blacklist_[account] = false; + } + +} \ No newline at end of file diff --git a/contracts/helper/MultiSig.sol b/contracts/multisig/MultiSigWalletWithTimelock.sol similarity index 100% rename from contracts/helper/MultiSig.sol rename to contracts/multisig/MultiSigWalletWithTimelock.sol diff --git a/contracts/token/DODOMineReader.sol b/contracts/token/DODOMineReader.sol deleted file mode 100644 index f5ee9a4..0000000 --- a/contracts/token/DODOMineReader.sol +++ /dev/null @@ -1,44 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - -import {IDODO} from "../intf/IDODO.sol"; -import {IERC20} from "../intf/IERC20.sol"; -import {SafeMath} from "../lib/SafeMath.sol"; - - -interface IDODOMine { - function getUserLpBalance(address _lpToken, address _user) external view returns (uint256); -} - - -contract DODOMineReader { - using SafeMath for uint256; - - function getUserStakedBalance( - address _dodoMine, - address _dodo, - address _user - ) external view returns (uint256 baseBalance, uint256 quoteBalance) { - address baseLpToken = IDODO(_dodo)._BASE_CAPITAL_TOKEN_(); - address quoteLpToken = IDODO(_dodo)._QUOTE_CAPITAL_TOKEN_(); - - uint256 baseLpBalance = IDODOMine(_dodoMine).getUserLpBalance(baseLpToken, _user); - uint256 quoteLpBalance = IDODOMine(_dodoMine).getUserLpBalance(quoteLpToken, _user); - - uint256 baseLpTotalSupply = IERC20(baseLpToken).totalSupply(); - uint256 quoteLpTotalSupply = IERC20(quoteLpToken).totalSupply(); - - (uint256 baseTarget, uint256 quoteTarget) = IDODO(_dodo).getExpectedTarget(); - baseBalance = baseTarget.mul(baseLpBalance).div(baseLpTotalSupply); - quoteBalance = quoteTarget.mul(quoteLpBalance).div(quoteLpTotalSupply); - - return (baseBalance, quoteBalance); - } -} diff --git a/test/Rebalance.test.ts b/test/Rebalance.test.ts new file mode 100644 index 0000000..a99b4ce --- /dev/null +++ b/test/Rebalance.test.ts @@ -0,0 +1,101 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +import * as assert from 'assert'; +import { Contract } from 'web3-eth-contract'; + +import { DODOContext, getDODOContext } from './utils/Context'; +import { DODO_REBALANCER_NAME, newContract } from './utils/Contracts'; +import { decimalStr } from './utils/Converter'; + +let lp: string; +let trader: string; +let rebalancer: Contract; + +async function init(ctx: DODOContext): Promise { + await ctx.setOraclePrice(decimalStr("100")); + + lp = ctx.spareAccounts[0]; + trader = ctx.spareAccounts[1]; + await ctx.approveDODO(lp); + await ctx.approveDODO(trader); + + await ctx.mintTestToken(lp, decimalStr("10"), decimalStr("1000")); + await ctx.mintTestToken(trader, decimalStr("10"), decimalStr("1000")); + + await ctx.DODO.methods + .depositBaseTo(lp, decimalStr("10")) + .send(ctx.sendParam(lp)); + await ctx.DODO.methods + .depositQuoteTo(lp, decimalStr("1000")) + .send(ctx.sendParam(lp)); + + rebalancer = await newContract(DODO_REBALANCER_NAME) +} + +describe("Trader", () => { + let snapshotId: string; + let ctx: DODOContext; + + before(async () => { + ctx = await getDODOContext(); + await init(ctx); + }); + + beforeEach(async () => { + snapshotId = await ctx.EVM.snapshot(); + }); + + afterEach(async () => { + await ctx.EVM.reset(snapshotId); + }); + + describe("rebalance", () => { + it("R above ONE rebalance", async () => { + await ctx.DODO.methods.buyBaseToken(decimalStr("1"), decimalStr("110"), "0x").send(ctx.sendParam(trader)) + await ctx.DODO.methods.disableTrading().send(ctx.sendParam(ctx.Deployer)) + await ctx.DODO.methods.transferOwnership(rebalancer.options.address).send(ctx.sendParam(ctx.Deployer)) + await rebalancer.methods.claimOwnership(ctx.DODO.options.address).send(ctx.sendParam(ctx.Deployer)) + + await ctx.BASE.methods.transfer(rebalancer.options.address, decimalStr("2")).send(ctx.sendParam(trader)) + await rebalancer.methods.rebalance(ctx.DODO.options.address).send(ctx.sendParam(ctx.Deployer)); + + assert.equal(await ctx.DODO.methods.getMidPrice().call(), await ctx.DODO.methods.getOraclePrice().call()) + + await rebalancer.methods.transferOwnership(ctx.DODO.options.address, ctx.Deployer).send(ctx.sendParam(ctx.Deployer)) + await ctx.DODO.methods.claimOwnership().send(ctx.sendParam(ctx.Deployer)) + + await rebalancer.methods.retrieve(ctx.BASE.options.address).send(ctx.sendParam(ctx.Deployer)) + await rebalancer.methods.retrieve(ctx.QUOTE.options.address).send(ctx.sendParam(ctx.Deployer)) + + assert.equal(await ctx.BASE.methods.balanceOf(ctx.Deployer).call(), "996997569110682237") + assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Deployer).call(), "101113906016449927750") + }); + + it("R below ONE rebalance", async () => { + await ctx.DODO.methods.sellBaseToken(decimalStr("1"), decimalStr("90"), "0x").send(ctx.sendParam(trader)) + await ctx.DODO.methods.disableTrading().send(ctx.sendParam(ctx.Deployer)) + await ctx.DODO.methods.transferOwnership(rebalancer.options.address).send(ctx.sendParam(ctx.Deployer)) + await rebalancer.methods.claimOwnership(ctx.DODO.options.address).send(ctx.sendParam(ctx.Deployer)) + + await ctx.QUOTE.methods.transfer(rebalancer.options.address, decimalStr("200")).send(ctx.sendParam(trader)) + await rebalancer.methods.rebalance(ctx.DODO.options.address).send(ctx.sendParam(ctx.Deployer)); + + assert.equal(await ctx.DODO.methods.getMidPrice().call(), await ctx.DODO.methods.getOraclePrice().call()) + + await rebalancer.methods.transferOwnership(ctx.DODO.options.address, ctx.Deployer).send(ctx.sendParam(ctx.Deployer)) + await ctx.DODO.methods.claimOwnership().send(ctx.sendParam(ctx.Deployer)) + + await rebalancer.methods.retrieve(ctx.BASE.options.address).send(ctx.sendParam(ctx.Deployer)) + await rebalancer.methods.retrieve(ctx.QUOTE.options.address).send(ctx.sendParam(ctx.Deployer)) + + assert.equal(await ctx.BASE.methods.balanceOf(ctx.Deployer).call(), "997008973080757726") + assert.equal(await ctx.QUOTE.methods.balanceOf(ctx.Deployer).call(), "101085569972088780856") + }); + + }); +}); diff --git a/test/utils/Contracts.ts b/test/utils/Contracts.ts index d89d28c..cc68264 100644 --- a/test/utils/Contracts.ts +++ b/test/utils/Contracts.ts @@ -10,56 +10,9 @@ if (process.env["COVERAGE"]) { jsonPath = "../../.coverage_artifacts/contracts/" } -const CloneFactory = require(`${jsonPath}CloneFactory.json`) -const DODO = require(`${jsonPath}DODO.json`) -const DODOZoo = require(`${jsonPath}DODOZoo.json`) -const DODOEthProxy = require(`${jsonPath}DODOEthProxy.json`) -const WETH = require(`${jsonPath}WETH9.json`) -const TestERC20 = require(`${jsonPath}TestERC20.json`) -const NaiveOracle = require(`${jsonPath}NaiveOracle.json`) -const DODOLpToken = require(`${jsonPath}DODOLpToken.json`) -const Uniswap = require(`${jsonPath}UniswapV2Pair.json`) -const UniswapArbitrageur = require(`${jsonPath}UniswapArbitrageur.json`) -const DODOToken = require(`${jsonPath}DODOToken.json`) -const DODOMine = require(`${jsonPath}DODOMine.json`) -const DODOMineReader = require(`${jsonPath}DODOMineReader.json`) -const LockedTokenVault = require(`${jsonPath}LockedTokenVault.json`) - import { getDefaultWeb3 } from './EVM'; import { Contract } from 'web3-eth-contract'; -export const CLONE_FACTORY_CONTRACT_NAME = "CloneFactory" -export const DODO_CONTRACT_NAME = "DODO" -export const TEST_ERC20_CONTRACT_NAME = "TestERC20" -export const NAIVE_ORACLE_CONTRACT_NAME = "NaiveOracle" -export const DODO_LP_TOKEN_CONTRACT_NAME = "DODOLpToken" -export const DODO_ZOO_CONTRACT_NAME = "DOOZoo" -export const DODO_WILD_CONTRACT_NAME = "DOOWild" -export const DODO_ETH_PROXY_CONTRACT_NAME = "DODOEthProxy" -export const WETH_CONTRACT_NAME = "WETH" -export const UNISWAP_CONTRACT_NAME = "Uniswap" -export const UNISWAP_ARBITRAGEUR_CONTRACT_NAME = "UniswapArbitrageur" -export const DODO_TOKEN_CONTRACT_NAME = "DODOToken" -export const LOCKED_TOKEN_VAULT_CONTRACT_NAME = "LockedTokenVault" -export const DODO_MINE_NAME = "DODOMine" -export const DODO_MINE_READER_NAME = "DODOMineReader" - -var contractMap: { [name: string]: any } = {} -contractMap[CLONE_FACTORY_CONTRACT_NAME] = CloneFactory -contractMap[DODO_CONTRACT_NAME] = DODO -contractMap[TEST_ERC20_CONTRACT_NAME] = TestERC20 -contractMap[NAIVE_ORACLE_CONTRACT_NAME] = NaiveOracle -contractMap[DODO_LP_TOKEN_CONTRACT_NAME] = DODOLpToken -contractMap[DODO_ZOO_CONTRACT_NAME] = DODOZoo -contractMap[DODO_ETH_PROXY_CONTRACT_NAME] = DODOEthProxy -contractMap[WETH_CONTRACT_NAME] = WETH -contractMap[UNISWAP_CONTRACT_NAME] = Uniswap -contractMap[UNISWAP_ARBITRAGEUR_CONTRACT_NAME] = UniswapArbitrageur -contractMap[DODO_TOKEN_CONTRACT_NAME] = DODOToken -contractMap[LOCKED_TOKEN_VAULT_CONTRACT_NAME] = LockedTokenVault -contractMap[DODO_MINE_NAME] = DODOMine -contractMap[DODO_MINE_READER_NAME] = DODOMineReader - interface ContractJson { abi: any; networks: { [network: number]: any }; @@ -67,7 +20,7 @@ interface ContractJson { } export function getContractJSON(contractName: string): ContractJson { - var info = contractMap[contractName] + var info = require(`${jsonPath}${contractName}.json`) return { abi: info.abi, networks: info.networks, From 299b67b972a875f324faf07c928c0521209584e1 Mon Sep 17 00:00:00 2001 From: mingda Date: Fri, 23 Oct 2020 17:11:50 +0800 Subject: [PATCH 096/118] dvm init commit --- contracts/DODOVenderMachine/DVMFactory.sol | 14 +++ .../DODOVenderMachine/impl/DVMTrader.sol | 109 ++++++++++-------- contracts/DODOVenderMachine/impl/DVMVault.sol | 4 + contracts/SmartRoute/SmartRoute.sol | 83 +++++++++++++ test/Admin.test.ts | 2 +- test/Attacks.test.ts | 2 +- test/DODOEthProxyAsBase.test.ts | 2 +- test/DODOEthProxyAsQuote.test.ts | 2 +- test/DODOZoo.test.ts | 2 +- test/LiquidityProvider.test.ts | 2 +- test/LongTailTokenlMode.test.ts | 2 +- test/Mining.test.ts | 2 +- test/Rebalance.test.ts | 2 +- test/StableCoinMode.test.ts | 2 +- test/TokenLock.test.ts | 2 +- test/Trader.test.ts | 2 +- test/UniswapArbitrageur.test.ts | 2 +- test/utils/{Context.ts => DVMContext.ts} | 6 +- 18 files changed, 179 insertions(+), 63 deletions(-) create mode 100644 contracts/SmartRoute/SmartRoute.sol rename test/utils/{Context.ts => DVMContext.ts} (98%) diff --git a/contracts/DODOVenderMachine/DVMFactory.sol b/contracts/DODOVenderMachine/DVMFactory.sol index 178ca7e..5218a23 100644 --- a/contracts/DODOVenderMachine/DVMFactory.sol +++ b/contracts/DODOVenderMachine/DVMFactory.sol @@ -18,6 +18,19 @@ contract DVMFactory is Ownable { address public _VAULT_TEMPLATE_; address public _CONTROLLER_TEMPLATE_; + // base -> quote -> DVM address list + mapping(address => mapping(address => address[])) _REGISTRY_; + + constructor( + address cloneFactory, + address vaultTemplate, + address controllerTemplate + ) public { + _CLONE_FACTORY_ = cloneFactory; + _VAULT_TEMPLATE_ = vaultTemplate; + _CONTROLLER_TEMPLATE_ = controllerTemplate; + } + function createDODOVenderMachine( address maintainer, address baseToken, @@ -46,6 +59,7 @@ contract DVMFactory is Ownable { ); newVenderMachine = address(controller); + _REGISTRY_[baseToken][quoteToken].push(newVenderMachine); return newVenderMachine; } } diff --git a/contracts/DODOVenderMachine/impl/DVMTrader.sol b/contracts/DODOVenderMachine/impl/DVMTrader.sol index 9a6aea9..6fd4ab0 100644 --- a/contracts/DODOVenderMachine/impl/DVMTrader.sol +++ b/contracts/DODOVenderMachine/impl/DVMTrader.sol @@ -12,58 +12,71 @@ import {DVMStorage} from "./DVMStorage.sol"; import {SafeMath} from "../../lib/SafeMath.sol"; import {DecimalMath} from "../../lib/DecimalMath.sol"; import {DODOMath} from "../../lib/DODOMath.sol"; - + contract DVMTrader is DVMStorage { - using SafeMath for uint256; + using SafeMath for uint256; - function sellBase (address to) external returns(uint256 receiveQuoteAmount){ - uint256 baseInput = _VAULT_.getBaseInput(); - uint256 mtFee; - (receiveQuoteAmount, mtFee) = querySellBase(baseInput); - _VAULT_.transferQuoteOut(to, receiveQuoteAmount); - if (mtFee>0){ - _VAULT_.transferQuoteOut(_MAINTAINER_, mtFee); + function sellBase(address to) external returns (uint256 receiveQuoteAmount) { + uint256 baseInput = _VAULT_.getBaseInput(); + uint256 mtFee; + (receiveQuoteAmount, mtFee) = querySellBase(baseInput); + _VAULT_.transferQuoteOut(to, receiveQuoteAmount); + if (mtFee > 0) { + _VAULT_.transferQuoteOut(_MAINTAINER_, mtFee); + } + _VAULT_.sync(); + _updateBase0(); // 这里需要想想,原则上不需要update B0. 但精度问题,或者用户往合约里充值,可能导致需要updateBase0 + return receiveQuoteAmount; } - _VAULT_.sync(); - _updateBase0(); // 这里需要想想,原则上不需要update B0. 但精度问题,或者用户往合约里充值,可能导致需要updateBase0 - return receiveQuoteAmount; - } - function sellQuote(address to) external returns(uint256 receiveBaseAmount){ - uint256 quoteInput = _VAULT_.getQuoteInput(); - uint256 mtFee; - (receiveBaseAmount, mtFee) = querySellQuote(quoteInput); - _VAULT_.transferBaseOut(to, receiveBaseAmount); - if (mtFee>0){ - _VAULT_.transferBaseOut(_MAINTAINER_, mtFee); + function sellQuote(address to) external returns (uint256 receiveBaseAmount) { + uint256 quoteInput = _VAULT_.getQuoteInput(); + uint256 mtFee; + (receiveBaseAmount, mtFee) = querySellQuote(quoteInput); + _VAULT_.transferBaseOut(to, receiveBaseAmount); + if (mtFee > 0) { + _VAULT_.transferBaseOut(_MAINTAINER_, mtFee); + } + _VAULT_.sync(); + _updateBase0(); + return receiveBaseAmount; } - _VAULT_.sync(); - _updateBase0(); - return receiveBaseAmount; - } - function querySellBase(uint256 payBaseAmount) public view returns(uint256 receiveQuoteAmount, uint256 mtFee){ - uint256 B2 = _VAULT_._BASE_RESERVE_(); - uint256 B1 = B2.add(payBaseAmount); - require(_BASE0_>=B1, "DODO_BASE_BALANCE_NOT_ENOUGH"); - uint256 Q = DODOMath._GeneralIntegrate(_BASE0_, B1, B2, _I_, _K_); - uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(Q); - uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(Q); - mtFee = DecimalMath.mulCeil(Q, mtFeeRate); - receiveQuoteAmount = Q.sub(mtFee).sub(DecimalMath.mulCeil(Q, lpFeeRate)); - return (receiveQuoteAmount, mtFee); - } + function querySellBase(uint256 payBaseAmount) + public + view + returns (uint256 receiveQuoteAmount, uint256 mtFee) + { + uint256 B2 = _VAULT_._BASE_RESERVE_(); + uint256 B1 = B2.add(payBaseAmount); + require(_BASE0_ >= B1, "DODO_BASE_BALANCE_NOT_ENOUGH"); + uint256 Q = DODOMath._GeneralIntegrate(_BASE0_, B1, B2, _I_, _K_); + uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(Q); + uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(Q); + mtFee = DecimalMath.mulCeil(Q, mtFeeRate); + receiveQuoteAmount = Q.sub(mtFee).sub(DecimalMath.mulCeil(Q, lpFeeRate)); + return (receiveQuoteAmount, mtFee); + } - function querySellQuote(uint256 payQuoteAmount) public view returns(uint256 receiveBaseAmount, uint256 mtFee){ - uint256 B1 = _VAULT_._BASE_RESERVE_(); - uint256 fairAmount = DecimalMath.divFloor(payQuoteAmount, _I_); - uint256 newBaseReserve = DODOMath._SolveQuadraticFunctionForTrade(_BASE0_,B1,fairAmount,false, _K_); - uint256 deltaBase = B1.sub(newBaseReserve); - uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(payQuoteAmount); - uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(payQuoteAmount); - mtFee = DecimalMath.mulCeil(deltaBase, mtFeeRate); - receiveBaseAmount = deltaBase.sub(mtFee).sub(DecimalMath.mulCeil(deltaBase, lpFeeRate)); - return (receiveBaseAmount, mtFee); - } - -} \ No newline at end of file + function querySellQuote(uint256 payQuoteAmount) + public + view + returns (uint256 receiveBaseAmount, uint256 mtFee) + { + uint256 B1 = _VAULT_._BASE_RESERVE_(); + uint256 fairAmount = DecimalMath.divFloor(payQuoteAmount, _I_); + uint256 newBaseReserve = DODOMath._SolveQuadraticFunctionForTrade( + _BASE0_, + B1, + fairAmount, + false, + _K_ + ); + uint256 deltaBase = B1.sub(newBaseReserve); + uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(payQuoteAmount); + uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(payQuoteAmount); + mtFee = DecimalMath.mulCeil(deltaBase, mtFeeRate); + receiveBaseAmount = deltaBase.sub(mtFee).sub(DecimalMath.mulCeil(deltaBase, lpFeeRate)); + return (receiveBaseAmount, mtFee); + } +} diff --git a/contracts/DODOVenderMachine/impl/DVMVault.sol b/contracts/DODOVenderMachine/impl/DVMVault.sol index 0461d82..2f6c968 100644 --- a/contracts/DODOVenderMachine/impl/DVMVault.sol +++ b/contracts/DODOVenderMachine/impl/DVMVault.sol @@ -77,6 +77,10 @@ contract DVMVault is InitializableOwnable { ); } + function getVaultReserve() public view returns (uint256 baseReserve, uint256 quoteReserve) { + return (_BASE_RESERVE_, _QUOTE_RESERVE_); + } + function getBaseBalance() public view returns (uint256 baseBalance) { return IERC20(_BASE_TOKEN_).balanceOf(address(this)); } diff --git a/contracts/SmartRoute/SmartRoute.sol b/contracts/SmartRoute/SmartRoute.sol new file mode 100644 index 0000000..f4fa579 --- /dev/null +++ b/contracts/SmartRoute/SmartRoute.sol @@ -0,0 +1,83 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; + +import {Ownable} from "../lib/Ownable.sol"; +import {DVMController} from "../DODOVenderMachine/impl/DVMController.sol"; +import {DVMVault} from "../DODOVenderMachine/impl/DVMVault.sol"; +import {IERC20} from "../intf/IERC20.sol"; +import {SafeERC20} from "../lib/SafeERC20.sol"; +import {SafeMath} from "../lib/SafeMath.sol"; +import {DecimalMath} from "../lib/DecimalMath.sol"; + +contract SmartRoute is Ownable { + using SafeMath for uint256; + using SafeERC20 for IERC20; + + function sellBaseOnDVM( + address DVM, + address to, + uint256 baseAmount, + uint256 minReceive + ) public returns (uint256 receiveAmount) { + IERC20(DVMController(DVM)._BASE_TOKEN_()).safeTransferFrom( + msg.sender, + address(DVMController(DVM)._VAULT_()), + baseAmount + ); + receiveAmount = DVMController(DVM).sellBase(to); + require(receiveAmount >= minReceive, "RECEIVE_NOT_ENOUGH"); + return receiveAmount; + } + + function sellQuoteOnDVM( + address DVM, + address to, + uint256 quoteAmount, + uint256 minReceive + ) public returns (uint256 receiveAmount) { + IERC20(DVMController(DVM)._QUOTE_TOKEN_()).safeTransferFrom( + msg.sender, + address(DVMController(DVM)._VAULT_()), + quoteAmount + ); + receiveAmount = DVMController(DVM).sellBase(to); + require(receiveAmount >= minReceive, "RECEIVE_NOT_ENOUGU"); + return receiveAmount; + } + + function depositToDVM( + address DVM, + uint256 baseAmount, + uint256 quoteAmount + ) public returns (uint256 shares) { + uint256 adjustedBaseAmount; + uint256 adjustedQuoteAmount; + (uint256 baseReserve, uint256 quoteReserve) = DVMController(DVM) + ._VAULT_() + .getVaultReserve(); + + if (quoteReserve == 0 && baseReserve == 0) { + adjustedBaseAmount = baseAmount; + adjustedQuoteAmount = quoteAmount; + } + + if (quoteReserve == 0 && baseReserve > 0) { + adjustedBaseAmount = baseAmount; + adjustedQuoteAmount = 0; + } + + if (quoteReserve > 0 && baseReserve > 0) { + uint256 baseIncreaseRatio = DecimalMath.divFloor(baseAmount, baseReserve); + uint256 quoteIncreaseRatio = DecimalMath.divFloor(quoteAmount, quoteReserve); + uint256 increaseRatio = baseIncreaseRatio>quoteIncreaseRatio?quoteIncreaseRatio:baseIncreaseRatio + adjustedBaseAmount = baseAmount; + adjustedQuoteAmount = 0; + } + } +} diff --git a/test/Admin.test.ts b/test/Admin.test.ts index 491f335..4d750ef 100644 --- a/test/Admin.test.ts +++ b/test/Admin.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; -import { DODOContext, getDODOContext } from './utils/Context'; +import { DODOContext, getDODOContext } from './utils/DVMContext'; import { decimalStr } from './utils/Converter'; let lp1: string; diff --git a/test/Attacks.test.ts b/test/Attacks.test.ts index 21552bb..8bb42b5 100644 --- a/test/Attacks.test.ts +++ b/test/Attacks.test.ts @@ -5,7 +5,7 @@ */ -import { DODOContext, getDODOContext } from './utils/Context'; +import { DODOContext, getDODOContext } from './utils/DVMContext'; import { decimalStr, gweiStr } from './utils/Converter'; import BigNumber from "bignumber.js"; import * as assert from "assert" diff --git a/test/DODOEthProxyAsBase.test.ts b/test/DODOEthProxyAsBase.test.ts index 85d674b..06c6a8d 100644 --- a/test/DODOEthProxyAsBase.test.ts +++ b/test/DODOEthProxyAsBase.test.ts @@ -13,7 +13,7 @@ import { DefaultDODOContextInitConfig, DODOContext, getDODOContext, -} from './utils/Context'; +} from './utils/DVMContext'; import * as contracts from './utils/Contracts'; import { decimalStr, MAX_UINT256 } from './utils/Converter'; import { logGas } from './utils/Log'; diff --git a/test/DODOEthProxyAsQuote.test.ts b/test/DODOEthProxyAsQuote.test.ts index 1941803..9345c96 100644 --- a/test/DODOEthProxyAsQuote.test.ts +++ b/test/DODOEthProxyAsQuote.test.ts @@ -13,7 +13,7 @@ import { DefaultDODOContextInitConfig, DODOContext, getDODOContext, -} from './utils/Context'; +} from './utils/DVMContext'; import * as contracts from './utils/Contracts'; import { decimalStr, MAX_UINT256 } from './utils/Converter'; import { logGas } from './utils/Log'; diff --git a/test/DODOZoo.test.ts b/test/DODOZoo.test.ts index eca2bac..f4a5a3a 100644 --- a/test/DODOZoo.test.ts +++ b/test/DODOZoo.test.ts @@ -5,7 +5,7 @@ */ -import { DODOContext, getDODOContext } from './utils/Context'; +import { DODOContext, getDODOContext } from './utils/DVMContext'; import * as assert from "assert" import { newContract, TEST_ERC20_CONTRACT_NAME, getContractWithAddress, DODO_CONTRACT_NAME } from './utils/Contracts'; diff --git a/test/LiquidityProvider.test.ts b/test/LiquidityProvider.test.ts index 6ba239b..fbda240 100644 --- a/test/LiquidityProvider.test.ts +++ b/test/LiquidityProvider.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; -import { DODOContext, getDODOContext } from './utils/Context'; +import { DODOContext, getDODOContext } from './utils/DVMContext'; import { decimalStr } from './utils/Converter'; import { logGas } from './utils/Log'; diff --git a/test/LongTailTokenlMode.test.ts b/test/LongTailTokenlMode.test.ts index 152b6dc..284c95c 100644 --- a/test/LongTailTokenlMode.test.ts +++ b/test/LongTailTokenlMode.test.ts @@ -5,7 +5,7 @@ */ -import { DODOContext, getDODOContext } from './utils/Context'; +import { DODOContext, getDODOContext } from './utils/DVMContext'; import { decimalStr, gweiStr } from './utils/Converter'; import * as assert from "assert" diff --git a/test/Mining.test.ts b/test/Mining.test.ts index 9b04679..70436bb 100644 --- a/test/Mining.test.ts +++ b/test/Mining.test.ts @@ -5,7 +5,7 @@ */ -import { DODOContext, getDODOContext } from './utils/Context'; +import { DODOContext, getDODOContext } from './utils/DVMContext'; import { decimalStr, MAX_UINT256 } from './utils/Converter'; // import * as assert from "assert" import { newContract, DODO_TOKEN_CONTRACT_NAME, DODO_MINE_NAME, TEST_ERC20_CONTRACT_NAME, getContractWithAddress, DODO_MINE_READER_NAME } from './utils/Contracts'; diff --git a/test/Rebalance.test.ts b/test/Rebalance.test.ts index a99b4ce..5d953cf 100644 --- a/test/Rebalance.test.ts +++ b/test/Rebalance.test.ts @@ -8,7 +8,7 @@ import * as assert from 'assert'; import { Contract } from 'web3-eth-contract'; -import { DODOContext, getDODOContext } from './utils/Context'; +import { DODOContext, getDODOContext } from './utils/DVMContext'; import { DODO_REBALANCER_NAME, newContract } from './utils/Contracts'; import { decimalStr } from './utils/Converter'; diff --git a/test/StableCoinMode.test.ts b/test/StableCoinMode.test.ts index 2373ec7..84c5514 100644 --- a/test/StableCoinMode.test.ts +++ b/test/StableCoinMode.test.ts @@ -5,7 +5,7 @@ */ -import { DODOContext, getDODOContext } from './utils/Context'; +import { DODOContext, getDODOContext } from './utils/DVMContext'; import { decimalStr, gweiStr } from './utils/Converter'; import * as assert from "assert" diff --git a/test/TokenLock.test.ts b/test/TokenLock.test.ts index b82e52b..6cd6f05 100644 --- a/test/TokenLock.test.ts +++ b/test/TokenLock.test.ts @@ -5,7 +5,7 @@ */ -import { DODOContext, getDODOContext } from './utils/Context'; +import { DODOContext, getDODOContext } from './utils/DVMContext'; import { decimalStr, MAX_UINT256 } from './utils/Converter'; // import * as assert from "assert" import { newContract, DODO_TOKEN_CONTRACT_NAME, LOCKED_TOKEN_VAULT_CONTRACT_NAME } from './utils/Contracts'; diff --git a/test/Trader.test.ts b/test/Trader.test.ts index 5e04c6e..fecc73c 100644 --- a/test/Trader.test.ts +++ b/test/Trader.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; -import { DODOContext, getDODOContext } from './utils/Context'; +import { DODOContext, getDODOContext } from './utils/DVMContext'; import { decimalStr } from './utils/Converter'; import { logGas } from './utils/Log'; diff --git a/test/UniswapArbitrageur.test.ts b/test/UniswapArbitrageur.test.ts index eae0670..19e2ffe 100644 --- a/test/UniswapArbitrageur.test.ts +++ b/test/UniswapArbitrageur.test.ts @@ -8,7 +8,7 @@ import * as assert from 'assert'; import { Contract } from 'web3-eth-contract'; -import { DODOContext, getDODOContext } from './utils/Context'; +import { DODOContext, getDODOContext } from './utils/DVMContext'; import { newContract, UNISWAP_ARBITRAGEUR_CONTRACT_NAME, diff --git a/test/utils/Context.ts b/test/utils/DVMContext.ts similarity index 98% rename from test/utils/Context.ts rename to test/utils/DVMContext.ts index 2bf61ae..3ee430f 100644 --- a/test/utils/Context.ts +++ b/test/utils/DVMContext.ts @@ -19,10 +19,11 @@ BigNumber.config({ DECIMAL_PLACES: 80, }); -export interface DODOContextInitConfig { +export interface DVMContextInitConfig { lpFeeRate: string; mtFeeRate: string; k: string; + i: string; gasPriceLimit: string; } @@ -43,6 +44,7 @@ export let DefaultDODOContextInitConfig = { lpFeeRate: decimalStr("0.002"), mtFeeRate: decimalStr("0.001"), k: decimalStr("0.1"), + i: decimalStr("100"), gasPriceLimit: gweiStr("100"), }; @@ -61,7 +63,7 @@ export class DODOContext { Maintainer: string; spareAccounts: string[]; - constructor() {} + constructor() { } async init(config: DODOContextInitConfig) { this.EVM = new EVM(); From dd1cb18cc4f510434fa4a52ea764cce0b62da2ce Mon Sep 17 00:00:00 2001 From: mingda Date: Sat, 24 Oct 2020 12:44:51 +0800 Subject: [PATCH 097/118] init dvm context --- contracts/SmartRoute/SmartRoute.sol | 25 +++++- contracts/helper/NaiveFeeRateModel.sol | 2 +- test/utils/Contracts.ts | 21 +++++ test/utils/DVMContext.ts | 110 ++++++++----------------- 4 files changed, 79 insertions(+), 79 deletions(-) diff --git a/contracts/SmartRoute/SmartRoute.sol b/contracts/SmartRoute/SmartRoute.sol index f4fa579..26f2eb1 100644 --- a/contracts/SmartRoute/SmartRoute.sol +++ b/contracts/SmartRoute/SmartRoute.sol @@ -53,9 +53,11 @@ contract SmartRoute is Ownable { function depositToDVM( address DVM, + address to, uint256 baseAmount, uint256 quoteAmount ) public returns (uint256 shares) { + address vault = address(DVMController(DVM)._VAULT_()); uint256 adjustedBaseAmount; uint256 adjustedQuoteAmount; (uint256 baseReserve, uint256 quoteReserve) = DVMController(DVM) @@ -75,9 +77,26 @@ contract SmartRoute is Ownable { if (quoteReserve > 0 && baseReserve > 0) { uint256 baseIncreaseRatio = DecimalMath.divFloor(baseAmount, baseReserve); uint256 quoteIncreaseRatio = DecimalMath.divFloor(quoteAmount, quoteReserve); - uint256 increaseRatio = baseIncreaseRatio>quoteIncreaseRatio?quoteIncreaseRatio:baseIncreaseRatio - adjustedBaseAmount = baseAmount; - adjustedQuoteAmount = 0; + if (baseIncreaseRatio <= quoteIncreaseRatio) { + adjustedBaseAmount = baseAmount; + adjustedQuoteAmount = DecimalMath.mulFloor(quoteReserve, baseIncreaseRatio); + } else { + adjustedQuoteAmount = quoteAmount; + adjustedBaseAmount = DecimalMath.mulFloor(baseReserve, quoteIncreaseRatio); + } } + + IERC20(DVMController(DVM)._BASE_TOKEN_()).safeTransferFrom( + msg.sender, + vault, + adjustedBaseAmount + ); + IERC20(DVMController(DVM)._QUOTE_TOKEN_()).safeTransferFrom( + msg.sender, + vault, + adjustedQuoteAmount + ); + + return DVMController(DVM).buyShares(to); } } diff --git a/contracts/helper/NaiveFeeRateModel.sol b/contracts/helper/NaiveFeeRateModel.sol index 1a244e1..eff1ea2 100644 --- a/contracts/helper/NaiveFeeRateModel.sol +++ b/contracts/helper/NaiveFeeRateModel.sol @@ -11,7 +11,7 @@ pragma experimental ABIEncoderV2; import {IFeeRateModel} from "../intf/IFeeRateModel.sol"; import {Ownable} from "../lib/Ownable.sol"; -contract ConstFeeRateModel is Ownable, IFeeRateModel { +contract NaiveFeeRateModel is Ownable, IFeeRateModel { uint256 public _FEE_RATE_; constructor(uint256 feeRate) public { diff --git a/test/utils/Contracts.ts b/test/utils/Contracts.ts index cc68264..fabcb07 100644 --- a/test/utils/Contracts.ts +++ b/test/utils/Contracts.ts @@ -13,6 +13,27 @@ if (process.env["COVERAGE"]) { import { getDefaultWeb3 } from './EVM'; import { Contract } from 'web3-eth-contract'; +export const CLONE_FACTORY_CONTRACT_NAME = "CloneFactory" +export const DODO_CONTRACT_NAME = "DODO" +export const TEST_ERC20_CONTRACT_NAME = "TestERC20" +export const NAIVE_ORACLE_CONTRACT_NAME = "NaiveOracle" +export const DODO_LP_TOKEN_CONTRACT_NAME = "DODOLpToken" +export const DODO_ZOO_CONTRACT_NAME = "DOOZoo" +export const DODO_WILD_CONTRACT_NAME = "DOOWild" +export const DODO_ETH_PROXY_CONTRACT_NAME = "DODOEthProxy" +export const WETH_CONTRACT_NAME = "WETH" +export const UNISWAP_CONTRACT_NAME = "Uniswap" +export const UNISWAP_ARBITRAGEUR_CONTRACT_NAME = "UniswapArbitrageur" +export const DODO_TOKEN_CONTRACT_NAME = "DODOToken" +export const LOCKED_TOKEN_VAULT_CONTRACT_NAME = "LockedTokenVault" +export const DODO_MINE_NAME = "DODOMine" +export const DODO_MINE_READER_NAME = "DODOMineReader" +export const DVM_VAULT_NAME = "DVMVault" +export const DVM_CONTROLLER_NAME = "DVMController" +export const DVM_FACTORY_NAME = "DVMFactory" +export const SMART_ROUTE_NAME = "SmartRoute" +export const NAIVE_FEE_RATE_MODEL_NAME = "NaiveFeeRateModel" + interface ContractJson { abi: any; networks: { [network: number]: any }; diff --git a/test/utils/DVMContext.ts b/test/utils/DVMContext.ts index 3ee430f..4c9c539 100644 --- a/test/utils/DVMContext.ts +++ b/test/utils/DVMContext.ts @@ -40,7 +40,7 @@ export interface DVMContextInitConfig { | 70% | 23.3% | +──────────────────────+───────────────+ */ -export let DefaultDODOContextInitConfig = { +export let DefaultDVMContextInitConfig = { lpFeeRate: decimalStr("0.002"), mtFeeRate: decimalStr("0.001"), k: decimalStr("0.1"), @@ -48,29 +48,33 @@ export let DefaultDODOContextInitConfig = { gasPriceLimit: gweiStr("100"), }; -export class DODOContext { +export class DVMContext { EVM: EVM; Web3: Web3; - DODO: Contract; - DODOZoo: Contract; + Route: Contract; + DVMFactory: Contract; + DVM: Contract; + Vault: Contract; BASE: Contract; - BaseCapital: Contract; QUOTE: Contract; - QuoteCapital: Contract; - ORACLE: Contract; Deployer: string; - Supervisor: string; Maintainer: string; - spareAccounts: string[]; + SpareAccounts: string[]; constructor() { } - async init(config: DODOContextInitConfig) { + async init(config: DVMContextInitConfig) { this.EVM = new EVM(); this.Web3 = getDefaultWeb3(); + this.Route = await contracts.newContract(contracts.SMART_ROUTE_NAME) + var cloneFactory = await contracts.newContract( contracts.CLONE_FACTORY_CONTRACT_NAME ); + var vaultTemplate = await contracts.newContract(contracts.DVM_VAULT_NAME) + var controllerTemplate = await contracts.newContract(contracts.DVM_CONTROLLER_NAME) + + this.DVMFactory = await contracts.newContract(contracts.DVM_FACTORY_NAME, [cloneFactory.options.address, vaultTemplate.options.address, controllerTemplate.options.address]) this.BASE = await contracts.newContract( contracts.TEST_ERC20_CONTRACT_NAME, @@ -80,65 +84,27 @@ export class DODOContext { contracts.TEST_ERC20_CONTRACT_NAME, ["TestQuote", 18] ); - this.ORACLE = await contracts.newContract( - contracts.NAIVE_ORACLE_CONTRACT_NAME - ); const allAccounts = await this.Web3.eth.getAccounts(); this.Deployer = allAccounts[0]; - this.Supervisor = allAccounts[1]; - this.Maintainer = allAccounts[2]; - this.spareAccounts = allAccounts.slice(3, 10); + this.Maintainer = allAccounts[1]; + this.SpareAccounts = allAccounts.slice(2, 10); - var DODOTemplate = await contracts.newContract( - contracts.DODO_CONTRACT_NAME - ); - this.DODOZoo = await contracts.newContract( - contracts.DODO_ZOO_CONTRACT_NAME, - [ - DODOTemplate.options.address, - cloneFactory.options.address, - this.Supervisor, - ] - ); + var lpFeeRateModel = await contracts.newContract(contracts.NAIVE_FEE_RATE_MODEL_NAME, [config.lpFeeRate]) + var mtFeeRateModel = await contracts.newContract(contracts.NAIVE_FEE_RATE_MODEL_NAME, [config.mtFeeRate]) + var DVMAddress = this.DVMFactory.methods.createDODOVenderMachine( + this.Maintainer, + this.BASE.options.address, + this.QUOTE.options.address, + lpFeeRateModel.options.address, + mtFeeRateModel.options.address, + config.i, + config.k, + config.gasPriceLimit).send(this.sendParam(this.Deployer)) - await this.DODOZoo.methods - .breedDODO( - this.Maintainer, - this.BASE.options.address, - this.QUOTE.options.address, - this.ORACLE.options.address, - config.lpFeeRate, - config.mtFeeRate, - config.k, - config.gasPriceLimit - ) - .send(this.sendParam(this.Deployer)); + this.DVM = contracts.getContractWithAddress(contracts.DVM_CONTROLLER_NAME, DVMAddress) - this.DODO = contracts.getContractWithAddress( - contracts.DODO_CONTRACT_NAME, - await this.DODOZoo.methods - .getDODO(this.BASE.options.address, this.QUOTE.options.address) - .call() - ); - await this.DODO.methods - .enableBaseDeposit() - .send(this.sendParam(this.Deployer)); - await this.DODO.methods - .enableQuoteDeposit() - .send(this.sendParam(this.Deployer)); - await this.DODO.methods.enableTrading().send(this.sendParam(this.Deployer)); - - this.BaseCapital = contracts.getContractWithAddress( - contracts.DODO_LP_TOKEN_CONTRACT_NAME, - await this.DODO.methods._BASE_CAPITAL_TOKEN_().call() - ); - this.QuoteCapital = contracts.getContractWithAddress( - contracts.DODO_LP_TOKEN_CONTRACT_NAME, - await this.DODO.methods._QUOTE_CAPITAL_TOKEN_().call() - ); - - console.log(log.blueText("[Init dodo context]")); + console.log(log.blueText("[Init DVM context]")); } sendParam(sender, value = "0") { @@ -150,12 +116,6 @@ export class DODOContext { }; } - async setOraclePrice(price: string) { - await this.ORACLE.methods - .setPrice(price) - .send(this.sendParam(this.Deployer)); - } - async mintTestToken(to: string, base: string, quote: string) { await this.BASE.methods.mint(to, base).send(this.sendParam(this.Deployer)); await this.QUOTE.methods @@ -163,20 +123,20 @@ export class DODOContext { .send(this.sendParam(this.Deployer)); } - async approveDODO(account: string) { + async approveRoute(account: string) { await this.BASE.methods - .approve(this.DODO.options.address, MAX_UINT256) + .approve(this.Route.options.address, MAX_UINT256) .send(this.sendParam(account)); await this.QUOTE.methods - .approve(this.DODO.options.address, MAX_UINT256) + .approve(this.Route.options.address, MAX_UINT256) .send(this.sendParam(account)); } } export async function getDODOContext( - config: DODOContextInitConfig = DefaultDODOContextInitConfig -): Promise { - var context = new DODOContext(); + config: DVMContextInitConfig = DefaultDVMContextInitConfig +): Promise { + var context = new DVMContext(); await context.init(config); return context; } From a61bdad9596ed2dbdf0959d4ff666349dbba8061 Mon Sep 17 00:00:00 2001 From: mingda Date: Mon, 26 Oct 2020 19:19:10 +0800 Subject: [PATCH 098/118] init test env --- .../DVMFactory.sol | 29 ++++--- .../impl/DVMAdmin.sol | 0 .../impl/DVMController.sol | 5 +- .../impl/DVMFunding.sol | 48 +++++------ .../impl/DVMStorage.sol | 0 .../impl/DVMTrader.sol | 0 .../impl/DVMVault.sol | 2 + contracts/SmartRoute/SmartRoute.sol | 4 +- .../{NormalERC20.sol => MintableERC20.sol} | 10 ++- migrations/2_deploy.js | 2 - test/DVM/trader.ts | 85 +++++++++++++++++++ test/{ => V1}/Admin.test.ts | 0 test/{ => V1}/Attacks.test.ts | 0 test/{ => V1}/DODOEthProxyAsBase.test.ts | 0 test/{ => V1}/DODOEthProxyAsQuote.test.ts | 0 test/{ => V1}/DODOZoo.test.ts | 0 test/{ => V1}/LiquidityProvider.test.ts | 0 test/{ => V1}/LongTailTokenlMode.test.ts | 0 test/{ => V1}/Mining.test.ts | 0 test/{ => V1}/Rebalance.test.ts | 0 test/{ => V1}/StableCoinMode.test.ts | 0 test/{ => V1}/TokenLock.test.ts | 0 test/{ => V1}/Trader.test.ts | 0 test/{ => V1}/UniswapArbitrageur.test.ts | 0 test/utils/Contracts.ts | 2 +- test/utils/DVMContext.ts | 15 ++-- 26 files changed, 147 insertions(+), 55 deletions(-) rename contracts/{DODOVenderMachine => DODOVendorMachine}/DVMFactory.sol (63%) rename contracts/{DODOVenderMachine => DODOVendorMachine}/impl/DVMAdmin.sol (100%) rename contracts/{DODOVenderMachine => DODOVendorMachine}/impl/DVMController.sol (87%) rename contracts/{DODOVenderMachine => DODOVendorMachine}/impl/DVMFunding.sol (54%) rename contracts/{DODOVenderMachine => DODOVendorMachine}/impl/DVMStorage.sol (100%) rename contracts/{DODOVenderMachine => DODOVendorMachine}/impl/DVMTrader.sol (100%) rename contracts/{DODOVenderMachine => DODOVendorMachine}/impl/DVMVault.sol (98%) rename contracts/external/ERC20/{NormalERC20.sol => MintableERC20.sol} (91%) create mode 100644 test/DVM/trader.ts rename test/{ => V1}/Admin.test.ts (100%) rename test/{ => V1}/Attacks.test.ts (100%) rename test/{ => V1}/DODOEthProxyAsBase.test.ts (100%) rename test/{ => V1}/DODOEthProxyAsQuote.test.ts (100%) rename test/{ => V1}/DODOZoo.test.ts (100%) rename test/{ => V1}/LiquidityProvider.test.ts (100%) rename test/{ => V1}/LongTailTokenlMode.test.ts (100%) rename test/{ => V1}/Mining.test.ts (100%) rename test/{ => V1}/Rebalance.test.ts (100%) rename test/{ => V1}/StableCoinMode.test.ts (100%) rename test/{ => V1}/TokenLock.test.ts (100%) rename test/{ => V1}/Trader.test.ts (100%) rename test/{ => V1}/UniswapArbitrageur.test.ts (100%) diff --git a/contracts/DODOVenderMachine/DVMFactory.sol b/contracts/DODOVendorMachine/DVMFactory.sol similarity index 63% rename from contracts/DODOVenderMachine/DVMFactory.sol rename to contracts/DODOVendorMachine/DVMFactory.sol index 5218a23..4d5623a 100644 --- a/contracts/DODOVenderMachine/DVMFactory.sol +++ b/contracts/DODOVendorMachine/DVMFactory.sol @@ -31,7 +31,7 @@ contract DVMFactory is Ownable { _CONTROLLER_TEMPLATE_ = controllerTemplate; } - function createDODOVenderMachine( + function createDODOVendorMachine( address maintainer, address baseToken, address quoteToken, @@ -40,17 +40,15 @@ contract DVMFactory is Ownable { uint256 i, uint256 k, uint256 gasPriceLimit - ) external returns (address newVenderMachine) { - DVMController controller = DVMController( - ICloneFactory(_CLONE_FACTORY_).clone(_CONTROLLER_TEMPLATE_) - ); - DVMVault vault = DVMVault(ICloneFactory(_CLONE_FACTORY_).clone(_VAULT_TEMPLATE_)); - vault.init(address(controller), baseToken, quoteToken); // vault owner is controller + ) external returns (address newVendorMachine) { + newVendorMachine = ICloneFactory(_CLONE_FACTORY_).clone(_CONTROLLER_TEMPLATE_); + address vault = ICloneFactory(_CLONE_FACTORY_).clone(_VAULT_TEMPLATE_); + DVMVault(vault).init(newVendorMachine, baseToken, quoteToken); // vault owner is controller - controller.init( + DVMController(newVendorMachine).init( msg.sender, maintainer, - address(vault), + vault, lpFeeRateModel, mtFeeRateModel, i, @@ -58,8 +56,15 @@ contract DVMFactory is Ownable { gasPriceLimit ); - newVenderMachine = address(controller); - _REGISTRY_[baseToken][quoteToken].push(newVenderMachine); - return newVenderMachine; + _REGISTRY_[baseToken][quoteToken].push(newVendorMachine); + return newVendorMachine; + } + + function getVendorMachine(address baseToken, address quoteToken) + external + view + returns (address[] memory machines) + { + return _REGISTRY_[baseToken][quoteToken]; } } diff --git a/contracts/DODOVenderMachine/impl/DVMAdmin.sol b/contracts/DODOVendorMachine/impl/DVMAdmin.sol similarity index 100% rename from contracts/DODOVenderMachine/impl/DVMAdmin.sol rename to contracts/DODOVendorMachine/impl/DVMAdmin.sol diff --git a/contracts/DODOVenderMachine/impl/DVMController.sol b/contracts/DODOVendorMachine/impl/DVMController.sol similarity index 87% rename from contracts/DODOVenderMachine/impl/DVMController.sol rename to contracts/DODOVendorMachine/impl/DVMController.sol index 26b4920..5abb225 100644 --- a/contracts/DODOVenderMachine/impl/DVMController.sol +++ b/contracts/DODOVendorMachine/impl/DVMController.sol @@ -27,8 +27,9 @@ contract DVMController is DVMTrader, DVMFunding, DVMAdmin { ) external { initOwner(owner); _MAINTAINER_ = maintainer; - _BASE_TOKEN_ = DVMVault(vault)._BASE_TOKEN_(); - _QUOTE_TOKEN_ = DVMVault(vault)._QUOTE_TOKEN_(); + _VAULT_ = DVMVault(vault); + _BASE_TOKEN_ = _VAULT_._BASE_TOKEN_(); + _QUOTE_TOKEN_ = _VAULT_._QUOTE_TOKEN_(); _LP_FEE_RATE_MODEL_ = IFeeRateModel(lpFeeRateModel); _MT_FEE_RATE_MODEL_ = IFeeRateModel(mtFeeRateModel); _I_ = i; diff --git a/contracts/DODOVenderMachine/impl/DVMFunding.sol b/contracts/DODOVendorMachine/impl/DVMFunding.sol similarity index 54% rename from contracts/DODOVenderMachine/impl/DVMFunding.sol rename to contracts/DODOVendorMachine/impl/DVMFunding.sol index 34d8f9a..04fbc61 100644 --- a/contracts/DODOVenderMachine/impl/DVMFunding.sol +++ b/contracts/DODOVendorMachine/impl/DVMFunding.sol @@ -15,41 +15,35 @@ contract DVMFunding is DVMStorage { function buyShares(address account) external returns (uint256) { uint256 baseInput = _VAULT_.getBaseInput(); uint256 quoteInput = _VAULT_.getQuoteInput(); - require(baseInput > 0, "NO_BASE_INPUT"); - uint256 baseReserve = _VAULT_._BASE_RESERVE_(); uint256 quoteReserve = _VAULT_._QUOTE_RESERVE_(); uint256 mintAmount; - // case 1. initial supply if (baseReserve == 0 && quoteReserve == 0) { mintAmount = baseInput; } - - // case 2. supply when quote reserve is 0 - if (baseReserve > 0 && quoteReserve == 0) { - uint256 mintRatio = DecimalMath.divFloor(baseInput, baseReserve); - mintAmount = DecimalMath.mulFloor(_VAULT_.totalSupply(), mintRatio); - } - - // case 3. normal case - if (baseReserve > 0 && quoteReserve > 0) { - uint256 baseInputRatio = DecimalMath.divFloor(baseInput, baseReserve); - uint256 quoteInputRatio = DecimalMath.divFloor(quoteInput, quoteReserve); - uint256 mintRatio = baseInputRatio > quoteInputRatio ? quoteInputRatio : baseInputRatio; - // 在提币的时候向下取整。因此永远不会出现,balance为0但totalsupply不为0的情况 - // 但有可能出现,reserve>0但totalSupply=0的场景 - uint256 totalShare = _VAULT_.totalSupply(); - if (totalShare > 0) { - mintAmount = DecimalMath.mulFloor(totalShare, mintRatio); - } else { - mintAmount = baseInput; - } - } - - _VAULT_.mint(account, mintAmount); - _VAULT_.sync(); + // // case 2. supply when quote reserve is 0 + // if (baseReserve > 0 && quoteReserve == 0) { + // uint256 mintRatio = DecimalMath.divFloor(baseInput, baseReserve); + // mintAmount = DecimalMath.mulFloor(_VAULT_.totalSupply(), mintRatio); + // } + // // case 3. normal case + // if (baseReserve > 0 && quoteReserve > 0) { + // uint256 baseInputRatio = DecimalMath.divFloor(baseInput, baseReserve); + // uint256 quoteInputRatio = DecimalMath.divFloor(quoteInput, quoteReserve); + // uint256 mintRatio = baseInputRatio > quoteInputRatio ? quoteInputRatio : baseInputRatio; + // // 在提币的时候向下取整。因此永远不会出现,balance为0但totalsupply不为0的情况 + // // 但有可能出现,reserve>0但totalSupply=0的场景 + // uint256 totalShare = _VAULT_.totalSupply(); + // if (totalShare > 0) { + // mintAmount = DecimalMath.mulFloor(totalShare, mintRatio); + // } else { + // mintAmount = baseInput; + // } + // } + // _VAULT_.mint(account, mintAmount); + // _VAULT_.sync(); } function sellShares( diff --git a/contracts/DODOVenderMachine/impl/DVMStorage.sol b/contracts/DODOVendorMachine/impl/DVMStorage.sol similarity index 100% rename from contracts/DODOVenderMachine/impl/DVMStorage.sol rename to contracts/DODOVendorMachine/impl/DVMStorage.sol diff --git a/contracts/DODOVenderMachine/impl/DVMTrader.sol b/contracts/DODOVendorMachine/impl/DVMTrader.sol similarity index 100% rename from contracts/DODOVenderMachine/impl/DVMTrader.sol rename to contracts/DODOVendorMachine/impl/DVMTrader.sol diff --git a/contracts/DODOVenderMachine/impl/DVMVault.sol b/contracts/DODOVendorMachine/impl/DVMVault.sol similarity index 98% rename from contracts/DODOVenderMachine/impl/DVMVault.sol rename to contracts/DODOVendorMachine/impl/DVMVault.sol index 2f6c968..5e0e5d9 100644 --- a/contracts/DODOVenderMachine/impl/DVMVault.sol +++ b/contracts/DODOVendorMachine/impl/DVMVault.sol @@ -66,6 +66,8 @@ contract DVMVault is InitializableOwnable { ); symbol = "DLP"; decimals = IERC20(_baseToken).decimals(); + _BASE_TOKEN_ = _baseToken; + _QUOTE_TOKEN_ = _quoteToken; } // Vault related diff --git a/contracts/SmartRoute/SmartRoute.sol b/contracts/SmartRoute/SmartRoute.sol index 26f2eb1..57f9718 100644 --- a/contracts/SmartRoute/SmartRoute.sol +++ b/contracts/SmartRoute/SmartRoute.sol @@ -8,8 +8,8 @@ pragma solidity 0.6.9; import {Ownable} from "../lib/Ownable.sol"; -import {DVMController} from "../DODOVenderMachine/impl/DVMController.sol"; -import {DVMVault} from "../DODOVenderMachine/impl/DVMVault.sol"; +import {DVMController} from "../DODOVendorMachine/impl/DVMController.sol"; +import {DVMVault} from "../DODOVendorMachine/impl/DVMVault.sol"; import {IERC20} from "../intf/IERC20.sol"; import {SafeERC20} from "../lib/SafeERC20.sol"; import {SafeMath} from "../lib/SafeMath.sol"; diff --git a/contracts/external/ERC20/NormalERC20.sol b/contracts/external/ERC20/MintableERC20.sol similarity index 91% rename from contracts/external/ERC20/NormalERC20.sol rename to contracts/external/ERC20/MintableERC20.sol index 416b1e8..32f94df 100644 --- a/contracts/external/ERC20/NormalERC20.sol +++ b/contracts/external/ERC20/MintableERC20.sol @@ -9,10 +9,11 @@ pragma solidity 0.6.9; import {SafeMath} from "../../lib/SafeMath.sol"; -contract TestERC20 { +contract MintableERC20 { using SafeMath for uint256; string public name; + string public symbol; uint8 public decimals; mapping(address => uint256) balances; @@ -21,8 +22,13 @@ contract TestERC20 { event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); - constructor(string memory _name, uint8 _decimals) public { + constructor( + string memory _name, + string memory _symbol, + uint8 _decimals + ) public { name = _name; + symbol = _symbol; decimals = _decimals; } diff --git a/migrations/2_deploy.js b/migrations/2_deploy.js index 434e5b6..63ed46d 100644 --- a/migrations/2_deploy.js +++ b/migrations/2_deploy.js @@ -1,3 +1 @@ -const DODOZoo = artifacts.require("DODOZoo"); - module.exports = async (deployer, network) => {}; diff --git a/test/DVM/trader.ts b/test/DVM/trader.ts new file mode 100644 index 0000000..bc6b435 --- /dev/null +++ b/test/DVM/trader.ts @@ -0,0 +1,85 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +// import * as assert from 'assert'; + +import { decimalStr } from '../utils/Converter'; +import { logGas } from '../utils/Log'; +import { DVMContext, getDVMContext } from '../utils/DVMContext'; +import { DVM_VAULT_NAME, getContractWithAddress } from '../utils/Contracts'; +import { Contract } from 'web3-eth-contract'; + +let lp: string; +let trader: string; +let vault: Contract + +async function init(ctx: DVMContext): Promise { + lp = ctx.SpareAccounts[0]; + trader = ctx.SpareAccounts[1]; + await ctx.approveRoute(lp); + await ctx.approveRoute(trader); + + console.log("approve") + + await ctx.mintTestToken(lp, decimalStr("10"), decimalStr("1000")); + await ctx.mintTestToken(trader, decimalStr("10"), decimalStr("1000")); + + console.log("mint") + + var vaultAddress = await ctx.DVM.methods._VAULT_().call(); + vault = getContractWithAddress(DVM_VAULT_NAME, vaultAddress) + + await ctx.Route.methods + .depositToDVM(ctx.DVM.options.address, lp, decimalStr("10"), decimalStr("0")) + .send(ctx.sendParam(lp)); + + console.log(await vault.methods.getVaultBalance().call()) + + console.log("deposit") +} + +describe("Trader", () => { + let snapshotId: string; + let ctx: DVMContext; + + before(async () => { + ctx = await getDVMContext(); + await init(ctx); + }); + + beforeEach(async () => { + snapshotId = await ctx.EVM.snapshot(); + }); + + afterEach(async () => { + await ctx.EVM.reset(snapshotId); + }); + + describe("trade", () => { + it("buy when R equals ONE", async () => { + await logGas(ctx.Route.methods.sellBaseOnDVM(ctx.DVM.options.address, trader, decimalStr("1"), decimalStr("90")), ctx.sendParam(trader), "buy base token when balanced") + // trader balances + console.log( + await ctx.BASE.methods.balanceOf(trader).call(), + decimalStr("11") + ); + console.log( + await ctx.QUOTE.methods.balanceOf(trader).call(), + "898581839502056240973" + ); + // maintainer balances + console.log( + await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), + decimalStr("0.001") + ); + console.log( + await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), + decimalStr("0") + ); + }); + }); +}); diff --git a/test/Admin.test.ts b/test/V1/Admin.test.ts similarity index 100% rename from test/Admin.test.ts rename to test/V1/Admin.test.ts diff --git a/test/Attacks.test.ts b/test/V1/Attacks.test.ts similarity index 100% rename from test/Attacks.test.ts rename to test/V1/Attacks.test.ts diff --git a/test/DODOEthProxyAsBase.test.ts b/test/V1/DODOEthProxyAsBase.test.ts similarity index 100% rename from test/DODOEthProxyAsBase.test.ts rename to test/V1/DODOEthProxyAsBase.test.ts diff --git a/test/DODOEthProxyAsQuote.test.ts b/test/V1/DODOEthProxyAsQuote.test.ts similarity index 100% rename from test/DODOEthProxyAsQuote.test.ts rename to test/V1/DODOEthProxyAsQuote.test.ts diff --git a/test/DODOZoo.test.ts b/test/V1/DODOZoo.test.ts similarity index 100% rename from test/DODOZoo.test.ts rename to test/V1/DODOZoo.test.ts diff --git a/test/LiquidityProvider.test.ts b/test/V1/LiquidityProvider.test.ts similarity index 100% rename from test/LiquidityProvider.test.ts rename to test/V1/LiquidityProvider.test.ts diff --git a/test/LongTailTokenlMode.test.ts b/test/V1/LongTailTokenlMode.test.ts similarity index 100% rename from test/LongTailTokenlMode.test.ts rename to test/V1/LongTailTokenlMode.test.ts diff --git a/test/Mining.test.ts b/test/V1/Mining.test.ts similarity index 100% rename from test/Mining.test.ts rename to test/V1/Mining.test.ts diff --git a/test/Rebalance.test.ts b/test/V1/Rebalance.test.ts similarity index 100% rename from test/Rebalance.test.ts rename to test/V1/Rebalance.test.ts diff --git a/test/StableCoinMode.test.ts b/test/V1/StableCoinMode.test.ts similarity index 100% rename from test/StableCoinMode.test.ts rename to test/V1/StableCoinMode.test.ts diff --git a/test/TokenLock.test.ts b/test/V1/TokenLock.test.ts similarity index 100% rename from test/TokenLock.test.ts rename to test/V1/TokenLock.test.ts diff --git a/test/Trader.test.ts b/test/V1/Trader.test.ts similarity index 100% rename from test/Trader.test.ts rename to test/V1/Trader.test.ts diff --git a/test/UniswapArbitrageur.test.ts b/test/V1/UniswapArbitrageur.test.ts similarity index 100% rename from test/UniswapArbitrageur.test.ts rename to test/V1/UniswapArbitrageur.test.ts diff --git a/test/utils/Contracts.ts b/test/utils/Contracts.ts index fabcb07..fae2178 100644 --- a/test/utils/Contracts.ts +++ b/test/utils/Contracts.ts @@ -15,7 +15,7 @@ import { Contract } from 'web3-eth-contract'; export const CLONE_FACTORY_CONTRACT_NAME = "CloneFactory" export const DODO_CONTRACT_NAME = "DODO" -export const TEST_ERC20_CONTRACT_NAME = "TestERC20" +export const MINTABLE_ERC20_CONTRACT_NAME = "MintableERC20" export const NAIVE_ORACLE_CONTRACT_NAME = "NaiveOracle" export const DODO_LP_TOKEN_CONTRACT_NAME = "DODOLpToken" export const DODO_ZOO_CONTRACT_NAME = "DOOZoo" diff --git a/test/utils/DVMContext.ts b/test/utils/DVMContext.ts index 4c9c539..fa6adb8 100644 --- a/test/utils/DVMContext.ts +++ b/test/utils/DVMContext.ts @@ -77,12 +77,12 @@ export class DVMContext { this.DVMFactory = await contracts.newContract(contracts.DVM_FACTORY_NAME, [cloneFactory.options.address, vaultTemplate.options.address, controllerTemplate.options.address]) this.BASE = await contracts.newContract( - contracts.TEST_ERC20_CONTRACT_NAME, - ["TestBase", 18] + contracts.MINTABLE_ERC20_CONTRACT_NAME, + ["TestBase", "BASE", 18] ); this.QUOTE = await contracts.newContract( - contracts.TEST_ERC20_CONTRACT_NAME, - ["TestQuote", 18] + contracts.MINTABLE_ERC20_CONTRACT_NAME, + ["TestQuote", "QUOTE", 18] ); const allAccounts = await this.Web3.eth.getAccounts(); @@ -92,7 +92,7 @@ export class DVMContext { var lpFeeRateModel = await contracts.newContract(contracts.NAIVE_FEE_RATE_MODEL_NAME, [config.lpFeeRate]) var mtFeeRateModel = await contracts.newContract(contracts.NAIVE_FEE_RATE_MODEL_NAME, [config.mtFeeRate]) - var DVMAddress = this.DVMFactory.methods.createDODOVenderMachine( + await this.DVMFactory.methods.createDODOVendorMachine( this.Maintainer, this.BASE.options.address, this.QUOTE.options.address, @@ -102,7 +102,8 @@ export class DVMContext { config.k, config.gasPriceLimit).send(this.sendParam(this.Deployer)) - this.DVM = contracts.getContractWithAddress(contracts.DVM_CONTROLLER_NAME, DVMAddress) + var vendorMachines = await this.DVMFactory.methods.getVendorMachine(this.BASE.options.address, this.QUOTE.options.address).call() + this.DVM = contracts.getContractWithAddress(contracts.DVM_CONTROLLER_NAME, vendorMachines[0]) console.log(log.blueText("[Init DVM context]")); } @@ -133,7 +134,7 @@ export class DVMContext { } } -export async function getDODOContext( +export async function getDVMContext( config: DVMContextInitConfig = DefaultDVMContextInitConfig ): Promise { var context = new DVMContext(); From 2c27386c34539aa31d0d6f30e930ea3d1e3b2c9c Mon Sep 17 00:00:00 2001 From: mingda Date: Tue, 27 Oct 2020 02:53:23 +0800 Subject: [PATCH 099/118] init funding test --- .../DODOVendorMachine/impl/DVMFunding.sol | 42 ++--- .../DODOVendorMachine/impl/DVMStorage.sol | 9 +- .../DODOVendorMachine/impl/DVMTrader.sol | 18 ++- contracts/SmartRoute/SmartRoute.sol | 2 +- contracts/helper/NaiveFeeRateModel.sol | 2 +- test/DVM/funding.test.ts | 144 ++++++++++++++++++ test/DVM/trader.test.ts | 121 +++++++++++++++ test/DVM/trader.ts | 85 ----------- test/utils/DVMContext.ts | 2 + 9 files changed, 305 insertions(+), 120 deletions(-) create mode 100644 test/DVM/funding.test.ts create mode 100644 test/DVM/trader.test.ts delete mode 100644 test/DVM/trader.ts diff --git a/contracts/DODOVendorMachine/impl/DVMFunding.sol b/contracts/DODOVendorMachine/impl/DVMFunding.sol index 04fbc61..65be8bb 100644 --- a/contracts/DODOVendorMachine/impl/DVMFunding.sol +++ b/contracts/DODOVendorMachine/impl/DVMFunding.sol @@ -23,27 +23,27 @@ contract DVMFunding is DVMStorage { if (baseReserve == 0 && quoteReserve == 0) { mintAmount = baseInput; } - // // case 2. supply when quote reserve is 0 - // if (baseReserve > 0 && quoteReserve == 0) { - // uint256 mintRatio = DecimalMath.divFloor(baseInput, baseReserve); - // mintAmount = DecimalMath.mulFloor(_VAULT_.totalSupply(), mintRatio); - // } - // // case 3. normal case - // if (baseReserve > 0 && quoteReserve > 0) { - // uint256 baseInputRatio = DecimalMath.divFloor(baseInput, baseReserve); - // uint256 quoteInputRatio = DecimalMath.divFloor(quoteInput, quoteReserve); - // uint256 mintRatio = baseInputRatio > quoteInputRatio ? quoteInputRatio : baseInputRatio; - // // 在提币的时候向下取整。因此永远不会出现,balance为0但totalsupply不为0的情况 - // // 但有可能出现,reserve>0但totalSupply=0的场景 - // uint256 totalShare = _VAULT_.totalSupply(); - // if (totalShare > 0) { - // mintAmount = DecimalMath.mulFloor(totalShare, mintRatio); - // } else { - // mintAmount = baseInput; - // } - // } - // _VAULT_.mint(account, mintAmount); - // _VAULT_.sync(); + // case 2. supply when quote reserve is 0 + if (baseReserve > 0 && quoteReserve == 0) { + uint256 mintRatio = DecimalMath.divFloor(baseInput, baseReserve); + mintAmount = DecimalMath.mulFloor(_VAULT_.totalSupply(), mintRatio); + } + // case 3. normal case + if (baseReserve > 0 && quoteReserve > 0) { + uint256 baseInputRatio = DecimalMath.divFloor(baseInput, baseReserve); + uint256 quoteInputRatio = DecimalMath.divFloor(quoteInput, quoteReserve); + uint256 mintRatio = baseInputRatio > quoteInputRatio ? quoteInputRatio : baseInputRatio; + // 在提币的时候向下取整。因此永远不会出现,balance为0但totalsupply不为0的情况 + // 但有可能出现,reserve>0但totalSupply=0的场景 + uint256 totalShare = _VAULT_.totalSupply(); + if (totalShare > 0) { + mintAmount = DecimalMath.mulFloor(totalShare, mintRatio); + } else { + mintAmount = baseInput; + } + } + _VAULT_.mint(account, mintAmount); + _VAULT_.sync(); } function sellShares( diff --git a/contracts/DODOVendorMachine/impl/DVMStorage.sol b/contracts/DODOVendorMachine/impl/DVMStorage.sol index 7be080d..9061dce 100644 --- a/contracts/DODOVendorMachine/impl/DVMStorage.sol +++ b/contracts/DODOVendorMachine/impl/DVMStorage.sol @@ -46,7 +46,6 @@ contract DVMStorage is InitializableOwnable, ReentrancyGuard { IFeeRateModel public _MT_FEE_RATE_MODEL_; uint256 public _K_; uint256 public _I_; - uint256 public _BASE0_; DVMVault public _VAULT_; DVMVault public _PROTECTION_VAULT_; @@ -59,13 +58,9 @@ contract DVMStorage is InitializableOwnable, ReentrancyGuard { } // ============ Helper Functions ============ - function _updateBase0() internal { + function getBase0() public view returns (uint256) { uint256 fairAmount = DecimalMath.divFloor(_VAULT_._QUOTE_RESERVE_(), _I_); - _BASE0_ = DODOMath._SolveQuadraticFunctionForTarget( - _VAULT_._BASE_RESERVE_(), - _K_, - fairAmount - ); + return DODOMath._SolveQuadraticFunctionForTarget(_VAULT_._BASE_RESERVE_(), _K_, fairAmount); } // ============ Version Control ============ diff --git a/contracts/DODOVendorMachine/impl/DVMTrader.sol b/contracts/DODOVendorMachine/impl/DVMTrader.sol index 6fd4ab0..f374d5e 100644 --- a/contracts/DODOVendorMachine/impl/DVMTrader.sol +++ b/contracts/DODOVendorMachine/impl/DVMTrader.sol @@ -25,7 +25,6 @@ contract DVMTrader is DVMStorage { _VAULT_.transferQuoteOut(_MAINTAINER_, mtFee); } _VAULT_.sync(); - _updateBase0(); // 这里需要想想,原则上不需要update B0. 但精度问题,或者用户往合约里充值,可能导致需要updateBase0 return receiveQuoteAmount; } @@ -38,7 +37,6 @@ contract DVMTrader is DVMStorage { _VAULT_.transferBaseOut(_MAINTAINER_, mtFee); } _VAULT_.sync(); - _updateBase0(); return receiveBaseAmount; } @@ -47,10 +45,11 @@ contract DVMTrader is DVMStorage { view returns (uint256 receiveQuoteAmount, uint256 mtFee) { + uint256 B0 = getBase0(); uint256 B2 = _VAULT_._BASE_RESERVE_(); uint256 B1 = B2.add(payBaseAmount); - require(_BASE0_ >= B1, "DODO_BASE_BALANCE_NOT_ENOUGH"); - uint256 Q = DODOMath._GeneralIntegrate(_BASE0_, B1, B2, _I_, _K_); + require(B0 >= B1, "DODO_BASE_BALANCE_NOT_ENOUGH"); + uint256 Q = DODOMath._GeneralIntegrate(B0, B1, B2, _I_, _K_); uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(Q); uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(Q); mtFee = DecimalMath.mulCeil(Q, mtFeeRate); @@ -63,10 +62,11 @@ contract DVMTrader is DVMStorage { view returns (uint256 receiveBaseAmount, uint256 mtFee) { + uint256 B0 = getBase0(); uint256 B1 = _VAULT_._BASE_RESERVE_(); uint256 fairAmount = DecimalMath.divFloor(payQuoteAmount, _I_); uint256 newBaseReserve = DODOMath._SolveQuadraticFunctionForTrade( - _BASE0_, + B0, B1, fairAmount, false, @@ -79,4 +79,12 @@ contract DVMTrader is DVMStorage { receiveBaseAmount = deltaBase.sub(mtFee).sub(DecimalMath.mulCeil(deltaBase, lpFeeRate)); return (receiveBaseAmount, mtFee); } + + function getMidPrice() public view returns (uint256 midPrice) { + uint256 B0 = getBase0(); + uint256 B1 = _VAULT_._BASE_RESERVE_(); + uint256 offsetRatio = DecimalMath.ONE.mul(B0).div(B1).mul(B0).div(B1); + uint256 offset = DecimalMath.ONE.sub(_K_).add(DecimalMath.mulFloor(offsetRatio, _K_)); + return DecimalMath.mulFloor(_I_, offset); + } } diff --git a/contracts/SmartRoute/SmartRoute.sol b/contracts/SmartRoute/SmartRoute.sol index 57f9718..f1a7712 100644 --- a/contracts/SmartRoute/SmartRoute.sol +++ b/contracts/SmartRoute/SmartRoute.sol @@ -46,7 +46,7 @@ contract SmartRoute is Ownable { address(DVMController(DVM)._VAULT_()), quoteAmount ); - receiveAmount = DVMController(DVM).sellBase(to); + receiveAmount = DVMController(DVM).sellQuote(to); require(receiveAmount >= minReceive, "RECEIVE_NOT_ENOUGU"); return receiveAmount; } diff --git a/contracts/helper/NaiveFeeRateModel.sol b/contracts/helper/NaiveFeeRateModel.sol index eff1ea2..7b5727d 100644 --- a/contracts/helper/NaiveFeeRateModel.sol +++ b/contracts/helper/NaiveFeeRateModel.sol @@ -15,7 +15,7 @@ contract NaiveFeeRateModel is Ownable, IFeeRateModel { uint256 public _FEE_RATE_; constructor(uint256 feeRate) public { - feeRate = _FEE_RATE_; + _FEE_RATE_ = feeRate; } function setFeeRate(uint256 newFeeRate) external { diff --git a/test/DVM/funding.test.ts b/test/DVM/funding.test.ts new file mode 100644 index 0000000..0f90ac4 --- /dev/null +++ b/test/DVM/funding.test.ts @@ -0,0 +1,144 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +// import * as assert from 'assert'; + +import { decimalStr } from '../utils/Converter'; +import { logGas } from '../utils/Log'; +import { DVMContext, getDVMContext } from '../utils/DVMContext'; +import { assert } from 'chai'; +import BigNumber from 'bignumber.js'; + +let lp: string; +let trader: string; + +async function init(ctx: DVMContext): Promise { + lp = ctx.SpareAccounts[0]; + trader = ctx.SpareAccounts[1]; + await ctx.approveRoute(lp); + await ctx.approveRoute(trader); + + await ctx.mintTestToken(lp, decimalStr("10"), decimalStr("1000")); + await ctx.mintTestToken(trader, decimalStr("10"), decimalStr("1000")); +} + +describe("Funding", () => { + let snapshotId: string; + let ctx: DVMContext; + + before(async () => { + ctx = await getDVMContext(); + await init(ctx); + }); + + beforeEach(async () => { + snapshotId = await ctx.EVM.snapshot(); + }); + + afterEach(async () => { + await ctx.EVM.reset(snapshotId); + }); + + describe("buy shares", () => { + + it("buy shares from init states", async () => { + + await logGas(ctx.Route.methods + .depositToDVM(ctx.DVM.options.address, lp, decimalStr("10"), decimalStr("0")) + , ctx.sendParam(lp), "buy shares"); + + // vault balances + assert.equal( + await ctx.BASE.methods.balanceOf(ctx.Vault.options.address).call(), + decimalStr("10") + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(ctx.Vault.options.address).call(), + decimalStr("0") + ); + assert.equal( + await ctx.Vault.methods._BASE_RESERVE_().call(), + decimalStr("10") + ) + assert.equal( + await ctx.Vault.methods._QUOTE_RESERVE_().call(), + decimalStr("0") + ) + + // shares number + assert.equal(await ctx.Vault.methods.balanceOf(lp).call(), decimalStr("10")) + }); + + it("buy shares from init states with quote != 0", async () => { + await ctx.Route.methods + .depositToDVM(ctx.DVM.options.address, lp, decimalStr("10"), decimalStr("100")) + .send(ctx.sendParam(lp)); + assert.equal(await ctx.Vault.methods.balanceOf(lp).call(), decimalStr("10")) + assert.equal(await ctx.DVM.methods.getMidPrice().call(), "102078438912577213500") + }) + + it("buy shares with balanced input", async () => { + await ctx.Route.methods + .depositToDVM(ctx.DVM.options.address, lp, decimalStr("10"), decimalStr("0")) + .send(ctx.sendParam(lp)); + await ctx.Route.methods.sellQuoteOnDVM(ctx.DVM.options.address, trader, decimalStr("200"), decimalStr("1")).send(ctx.sendParam(trader)) + + var vaultBaseBalance = new BigNumber(await ctx.BASE.methods.balanceOf(ctx.Vault.options.address).call()) + var vaultQuoteBalance = new BigNumber(await ctx.QUOTE.methods.balanceOf(ctx.Vault.options.address).call()) + var increaseRatio = new BigNumber("0.1") + + await ctx.Route.methods.depositToDVM(ctx.DVM.options.address, trader, vaultBaseBalance.multipliedBy(increaseRatio).toFixed(0), vaultQuoteBalance.multipliedBy(increaseRatio).toFixed(0)).send(ctx.sendParam(trader)) + + assert.equal( + await ctx.BASE.methods.balanceOf(ctx.Vault.options.address).call(), + "8856412162577279149" + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(ctx.Vault.options.address).call(), + "219999999999999999800" + ); + + assert.equal(await ctx.Vault.methods.balanceOf(trader).call(), "999999999999999990") + }) + + it("buy shares with unbalanced input (less quote)", async () => { + await ctx.Route.methods + .depositToDVM(ctx.DVM.options.address, lp, decimalStr("10"), decimalStr("0")) + .send(ctx.sendParam(lp)); + await ctx.Route.methods.sellQuoteOnDVM(ctx.DVM.options.address, trader, decimalStr("200"), decimalStr("1")).send(ctx.sendParam(trader)) + + var vaultBaseBalance = new BigNumber(await ctx.BASE.methods.balanceOf(ctx.Vault.options.address).call()) + var vaultQuoteBalance = new BigNumber(await ctx.QUOTE.methods.balanceOf(ctx.Vault.options.address).call()) + var increaseRatio = new BigNumber("0.1") + await ctx.Route.methods.depositToDVM( + ctx.DVM.options.address, + trader, + vaultBaseBalance.multipliedBy(increaseRatio).toFixed(0), + vaultQuoteBalance.multipliedBy(increaseRatio).div(2).toFixed(0) + ).send(ctx.sendParam(trader)) + assert.equal(await ctx.Vault.methods.balanceOf(trader).call(), "499999999999999990") + }) + + it("buy shares with unbalanced input (less base)", async () => { + await ctx.Route.methods + .depositToDVM(ctx.DVM.options.address, lp, decimalStr("10"), decimalStr("0")) + .send(ctx.sendParam(lp)); + await ctx.Route.methods.sellQuoteOnDVM(ctx.DVM.options.address, trader, decimalStr("200"), decimalStr("1")).send(ctx.sendParam(trader)) + + var vaultBaseBalance = new BigNumber(await ctx.BASE.methods.balanceOf(ctx.Vault.options.address).call()) + var vaultQuoteBalance = new BigNumber(await ctx.QUOTE.methods.balanceOf(ctx.Vault.options.address).call()) + var increaseRatio = new BigNumber("0.1") + await ctx.Route.methods.depositToDVM( + ctx.DVM.options.address, + trader, + vaultBaseBalance.multipliedBy(increaseRatio).div(2).toFixed(0), + vaultQuoteBalance.multipliedBy(increaseRatio).toFixed(0) + ).send(ctx.sendParam(trader)) + assert.equal(await ctx.Vault.methods.balanceOf(trader).call(), "499999999999999990") + }) + }); +}); diff --git a/test/DVM/trader.test.ts b/test/DVM/trader.test.ts new file mode 100644 index 0000000..6580bc0 --- /dev/null +++ b/test/DVM/trader.test.ts @@ -0,0 +1,121 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +// import * as assert from 'assert'; + +import { decimalStr } from '../utils/Converter'; +import { logGas } from '../utils/Log'; +import { DVMContext, getDVMContext } from '../utils/DVMContext'; +import { assert } from 'chai'; + +let lp: string; +let trader: string; + +async function init(ctx: DVMContext): Promise { + lp = ctx.SpareAccounts[0]; + trader = ctx.SpareAccounts[1]; + await ctx.approveRoute(lp); + await ctx.approveRoute(trader); + + await ctx.mintTestToken(lp, decimalStr("10"), decimalStr("1000")); + await ctx.mintTestToken(trader, decimalStr("10"), decimalStr("1000")); + + await ctx.Route.methods + .depositToDVM(ctx.DVM.options.address, lp, decimalStr("10"), decimalStr("0")) + .send(ctx.sendParam(lp)); + + console.log(await ctx.Vault.methods.getVaultBalance().call()) + + console.log("deposit") +} + +describe("Trader", () => { + let snapshotId: string; + let ctx: DVMContext; + + before(async () => { + ctx = await getDVMContext(); + await init(ctx); + }); + + beforeEach(async () => { + snapshotId = await ctx.EVM.snapshot(); + }); + + afterEach(async () => { + await ctx.EVM.reset(snapshotId); + }); + + describe("trade", () => { + it("buy & sell", async () => { + + console.log("BASE0 before buy", await ctx.DVM.methods._BASE0_().call()) + + // buy + await logGas(ctx.Route.methods.sellQuoteOnDVM(ctx.DVM.options.address, trader, decimalStr("200"), decimalStr("1")), ctx.sendParam(trader), "buy base token") + console.log("BASE0 after buy", await ctx.DVM.methods._BASE0_().call()) + // trader balances + assert.equal( + await ctx.BASE.methods.balanceOf(trader).call(), + "11946763594380080787" + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(trader).call(), + decimalStr("800") + ); + // vault balances + assert.equal( + await ctx.BASE.methods.balanceOf(ctx.Vault.options.address).call(), + "8051283784161162863" + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(ctx.Vault.options.address).call(), + decimalStr("200") + ); + // maintainer balances + assert.equal( + await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), + "1952621458756350" + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), + decimalStr("0") + ); + + // sell + await logGas(ctx.Route.methods.sellBaseOnDVM(ctx.DVM.options.address, trader, decimalStr("1"), decimalStr("100")), ctx.sendParam(trader), "sell base token") + console.log("BASE0 after sell", await ctx.DVM.methods._BASE0_().call()) + // trader balances + assert.equal( + await ctx.BASE.methods.balanceOf(trader).call(), + "10946763594380080787" + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(trader).call(), + "903421810640399874603" + ); + // vault balances + assert.equal( + await ctx.BASE.methods.balanceOf(ctx.Vault.options.address).call(), + "9051283784161162863" + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(ctx.Vault.options.address).call(), + "96474456349930717298" + ); + // maintainer balances + assert.equal( + await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), + "1952621458756350" + ); + assert.equal( + await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), + "103733009669408099" + ); + }); + }); +}); diff --git a/test/DVM/trader.ts b/test/DVM/trader.ts deleted file mode 100644 index bc6b435..0000000 --- a/test/DVM/trader.ts +++ /dev/null @@ -1,85 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -// import * as assert from 'assert'; - -import { decimalStr } from '../utils/Converter'; -import { logGas } from '../utils/Log'; -import { DVMContext, getDVMContext } from '../utils/DVMContext'; -import { DVM_VAULT_NAME, getContractWithAddress } from '../utils/Contracts'; -import { Contract } from 'web3-eth-contract'; - -let lp: string; -let trader: string; -let vault: Contract - -async function init(ctx: DVMContext): Promise { - lp = ctx.SpareAccounts[0]; - trader = ctx.SpareAccounts[1]; - await ctx.approveRoute(lp); - await ctx.approveRoute(trader); - - console.log("approve") - - await ctx.mintTestToken(lp, decimalStr("10"), decimalStr("1000")); - await ctx.mintTestToken(trader, decimalStr("10"), decimalStr("1000")); - - console.log("mint") - - var vaultAddress = await ctx.DVM.methods._VAULT_().call(); - vault = getContractWithAddress(DVM_VAULT_NAME, vaultAddress) - - await ctx.Route.methods - .depositToDVM(ctx.DVM.options.address, lp, decimalStr("10"), decimalStr("0")) - .send(ctx.sendParam(lp)); - - console.log(await vault.methods.getVaultBalance().call()) - - console.log("deposit") -} - -describe("Trader", () => { - let snapshotId: string; - let ctx: DVMContext; - - before(async () => { - ctx = await getDVMContext(); - await init(ctx); - }); - - beforeEach(async () => { - snapshotId = await ctx.EVM.snapshot(); - }); - - afterEach(async () => { - await ctx.EVM.reset(snapshotId); - }); - - describe("trade", () => { - it("buy when R equals ONE", async () => { - await logGas(ctx.Route.methods.sellBaseOnDVM(ctx.DVM.options.address, trader, decimalStr("1"), decimalStr("90")), ctx.sendParam(trader), "buy base token when balanced") - // trader balances - console.log( - await ctx.BASE.methods.balanceOf(trader).call(), - decimalStr("11") - ); - console.log( - await ctx.QUOTE.methods.balanceOf(trader).call(), - "898581839502056240973" - ); - // maintainer balances - console.log( - await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), - decimalStr("0.001") - ); - console.log( - await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), - decimalStr("0") - ); - }); - }); -}); diff --git a/test/utils/DVMContext.ts b/test/utils/DVMContext.ts index fa6adb8..17d5d7d 100644 --- a/test/utils/DVMContext.ts +++ b/test/utils/DVMContext.ts @@ -105,6 +105,8 @@ export class DVMContext { var vendorMachines = await this.DVMFactory.methods.getVendorMachine(this.BASE.options.address, this.QUOTE.options.address).call() this.DVM = contracts.getContractWithAddress(contracts.DVM_CONTROLLER_NAME, vendorMachines[0]) + this.Vault = contracts.getContractWithAddress(contracts.DVM_VAULT_NAME, await this.DVM.methods._VAULT_().call()) + console.log(log.blueText("[Init DVM context]")); } From 4a7c5a546ddeadd1f044d41ac044ef2948261487 Mon Sep 17 00:00:00 2001 From: mingda Date: Thu, 5 Nov 2020 00:26:45 +0800 Subject: [PATCH 100/118] snapshot --- contracts/DODOVendorMachine/DVMFactory.sol | 70 -------------- .../impl/{DVMController.sol => DVM.sol} | 22 +++-- contracts/DODOVendorMachine/impl/DVMAdmin.sol | 19 ---- .../DODOVendorMachine/impl/DVMStorage.sol | 37 ++++++-- .../DODOVendorMachine/impl/DVMTrader.sol | 71 ++++++++++---- contracts/DODOVendorMachine/impl/DVMVault.sol | 10 +- contracts/DODOVendorMachine/intf/IDVM.sol | 23 +++++ .../DODOVendorMachine/intf/IDVMVault.sol | 17 ++++ .../DODOVendorMachine/intf/IExternalCall.sol | 13 +++ contracts/Factory/DVMFactory.sol | 93 +++++++++++++++++++ contracts/SmartRoute/SmartRoute.sol | 32 +++---- contracts/helper/ConstFeeRateModel.sol | 23 ----- contracts/helper/NaiveFeeRateModel.sol | 28 ------ contracts/intf/IFeeRateModel.sol | 3 +- contracts/lib/ConstFeeRateModel.sol | 38 ++++++++ contracts/lib/OperatorSystem.sol | 36 +++++++ contracts/lib/PermissionManager.sol | 65 ++++++------- 17 files changed, 366 insertions(+), 234 deletions(-) delete mode 100644 contracts/DODOVendorMachine/DVMFactory.sol rename contracts/DODOVendorMachine/impl/{DVMController.sol => DVM.sol} (61%) delete mode 100644 contracts/DODOVendorMachine/impl/DVMAdmin.sol create mode 100644 contracts/DODOVendorMachine/intf/IDVM.sol create mode 100644 contracts/DODOVendorMachine/intf/IDVMVault.sol create mode 100644 contracts/DODOVendorMachine/intf/IExternalCall.sol create mode 100644 contracts/Factory/DVMFactory.sol delete mode 100644 contracts/helper/ConstFeeRateModel.sol delete mode 100644 contracts/helper/NaiveFeeRateModel.sol create mode 100644 contracts/lib/ConstFeeRateModel.sol create mode 100644 contracts/lib/OperatorSystem.sol diff --git a/contracts/DODOVendorMachine/DVMFactory.sol b/contracts/DODOVendorMachine/DVMFactory.sol deleted file mode 100644 index 4d5623a..0000000 --- a/contracts/DODOVendorMachine/DVMFactory.sol +++ /dev/null @@ -1,70 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - -import {Ownable} from "../lib/Ownable.sol"; -import {ICloneFactory} from "../lib/CloneFactory.sol"; -import {DVMVault} from "./impl/DVMVault.sol"; -import {DVMController} from "./impl/DVMController.sol"; - -contract DVMFactory is Ownable { - address public _CLONE_FACTORY_; - address public _VAULT_TEMPLATE_; - address public _CONTROLLER_TEMPLATE_; - - // base -> quote -> DVM address list - mapping(address => mapping(address => address[])) _REGISTRY_; - - constructor( - address cloneFactory, - address vaultTemplate, - address controllerTemplate - ) public { - _CLONE_FACTORY_ = cloneFactory; - _VAULT_TEMPLATE_ = vaultTemplate; - _CONTROLLER_TEMPLATE_ = controllerTemplate; - } - - function createDODOVendorMachine( - address maintainer, - address baseToken, - address quoteToken, - address lpFeeRateModel, - address mtFeeRateModel, - uint256 i, - uint256 k, - uint256 gasPriceLimit - ) external returns (address newVendorMachine) { - newVendorMachine = ICloneFactory(_CLONE_FACTORY_).clone(_CONTROLLER_TEMPLATE_); - address vault = ICloneFactory(_CLONE_FACTORY_).clone(_VAULT_TEMPLATE_); - DVMVault(vault).init(newVendorMachine, baseToken, quoteToken); // vault owner is controller - - DVMController(newVendorMachine).init( - msg.sender, - maintainer, - vault, - lpFeeRateModel, - mtFeeRateModel, - i, - k, - gasPriceLimit - ); - - _REGISTRY_[baseToken][quoteToken].push(newVendorMachine); - return newVendorMachine; - } - - function getVendorMachine(address baseToken, address quoteToken) - external - view - returns (address[] memory machines) - { - return _REGISTRY_[baseToken][quoteToken]; - } -} diff --git a/contracts/DODOVendorMachine/impl/DVMController.sol b/contracts/DODOVendorMachine/impl/DVM.sol similarity index 61% rename from contracts/DODOVendorMachine/impl/DVMController.sol rename to contracts/DODOVendorMachine/impl/DVM.sol index 5abb225..8310d88 100644 --- a/contracts/DODOVendorMachine/impl/DVMController.sol +++ b/contracts/DODOVendorMachine/impl/DVM.sol @@ -8,32 +8,40 @@ pragma solidity 0.6.9; pragma experimental ABIEncoderV2; +import {IFeeRateModel} from "../../intf/IFeeRateModel.sol"; +import {IPermissionManager} from "../../lib/PermissionManager.sol"; import {DVMTrader} from "./DVMTrader.sol"; import {DVMFunding} from "./DVMFunding.sol"; -import {DVMAdmin} from "./DVMAdmin.sol"; import {DVMVault} from "./DVMVault.sol"; -import {IFeeRateModel} from "../../intf/IFeeRateModel.sol"; -contract DVMController is DVMTrader, DVMFunding, DVMAdmin { +contract DVM is DVMTrader, DVMFunding { function init( address owner, address maintainer, address vault, address lpFeeRateModel, address mtFeeRateModel, + address tradePermissionManager, + address fundingPermissionManager, uint256 i, - uint256 k, - uint256 gasPriceLimit + uint256 k ) external { initOwner(owner); - _MAINTAINER_ = maintainer; _VAULT_ = DVMVault(vault); _BASE_TOKEN_ = _VAULT_._BASE_TOKEN_(); _QUOTE_TOKEN_ = _VAULT_._QUOTE_TOKEN_(); _LP_FEE_RATE_MODEL_ = IFeeRateModel(lpFeeRateModel); _MT_FEE_RATE_MODEL_ = IFeeRateModel(mtFeeRateModel); + _TRADE_PERMISSION_ = IPermissionManager(tradePermissionManager); + _FUNDING_PERMISSION_ = IPermissionManager(fundingPermissionManager); + _MAINTAINER_ = maintainer; _I_ = i; _K_ = k; - _GAS_PRICE_LIMIT_ = gasPriceLimit; + _GAS_PRICE_LIMIT_ = uint256(-1); + } + + // ============ Version Control ============ + function version() external pure returns (uint256) { + return 100; // 1.0.0 } } diff --git a/contracts/DODOVendorMachine/impl/DVMAdmin.sol b/contracts/DODOVendorMachine/impl/DVMAdmin.sol deleted file mode 100644 index 3738c41..0000000 --- a/contracts/DODOVendorMachine/impl/DVMAdmin.sol +++ /dev/null @@ -1,19 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - -import {DVMStorage} from "./DVMStorage.sol"; - -contract DVMAdmin is DVMStorage{ - - function setI(uint256 newI) external onlyOwner{} - - function setK(uint256 newK) external onlyOwner{} - -} \ No newline at end of file diff --git a/contracts/DODOVendorMachine/impl/DVMStorage.sol b/contracts/DODOVendorMachine/impl/DVMStorage.sol index 9061dce..0d5f314 100644 --- a/contracts/DODOVendorMachine/impl/DVMStorage.sol +++ b/contracts/DODOVendorMachine/impl/DVMStorage.sol @@ -13,7 +13,7 @@ import {ReentrancyGuard} from "../../lib/ReentrancyGuard.sol"; import {SafeMath} from "../../lib/SafeMath.sol"; import {DODOMath} from "../../lib/DODOMath.sol"; import {DecimalMath} from "../../lib/DecimalMath.sol"; -import {PermissionManager} from "../../lib/PermissionManager.sol"; +import {IPermissionManager} from "../../lib/PermissionManager.sol"; import {IFeeRateModel} from "../../intf/IFeeRateModel.sol"; import {DVMVault} from "./DVMVault.sol"; @@ -30,8 +30,8 @@ contract DVMStorage is InitializableOwnable, ReentrancyGuard { bool public _BUYING_ALLOWED_; bool public _SELLING_ALLOWED_; - PermissionManager public _TRADE_PERMISSION_; - PermissionManager public _FUNDING_PERMISSION_; + IPermissionManager public _TRADE_PERMISSION_; + IPermissionManager public _FUNDING_PERMISSION_; // ============ Core Address ============ @@ -48,7 +48,6 @@ contract DVMStorage is InitializableOwnable, ReentrancyGuard { uint256 public _I_; DVMVault public _VAULT_; - DVMVault public _PROTECTION_VAULT_; // ============ Modifiers ============ @@ -58,13 +57,31 @@ contract DVMStorage is InitializableOwnable, ReentrancyGuard { } // ============ Helper Functions ============ - function getBase0() public view returns (uint256) { - uint256 fairAmount = DecimalMath.divFloor(_VAULT_._QUOTE_RESERVE_(), _I_); - return DODOMath._SolveQuadraticFunctionForTarget(_VAULT_._BASE_RESERVE_(), _K_, fairAmount); + + function getBase0(uint256 baseAmount, uint256 quoteAmount) public view returns (uint256) { + uint256 fairAmount = DecimalMath.divFloor(quoteAmount, _I_); + return DODOMath._SolveQuadraticFunctionForTarget(baseAmount, _K_, fairAmount); } - // ============ Version Control ============ - function version() external pure returns (uint256) { - return 101; // 1.0.1 + // ============ Setting Functions ============ + + function setLpFeeRateModel(address newLpFeeRateModel) external onlyOwner { + _LP_FEE_RATE_MODEL_ = IFeeRateModel(newLpFeeRateModel); + } + + function setMtFeeRateModel(address newMtFeeRateModel) external onlyOwner { + _MT_FEE_RATE_MODEL_ = IFeeRateModel(newMtFeeRateModel); + } + + function setTradePermissionManager(address newTradePermissionManager) external onlyOwner { + _TRADE_PERMISSION_ = IPermissionManager(newTradePermissionManager); + } + + function setFundingPermissionManager(address newFundingPermissionManager) external onlyOwner { + _FUNDING_PERMISSION_ = IPermissionManager(newFundingPermissionManager); + } + + function setMaintainer(address newMaintainer) external onlyOwner { + _MAINTAINER_ = newMaintainer; } } diff --git a/contracts/DODOVendorMachine/impl/DVMTrader.sol b/contracts/DODOVendorMachine/impl/DVMTrader.sol index f374d5e..c212df4 100644 --- a/contracts/DODOVendorMachine/impl/DVMTrader.sol +++ b/contracts/DODOVendorMachine/impl/DVMTrader.sol @@ -12,6 +12,7 @@ import {DVMStorage} from "./DVMStorage.sol"; import {SafeMath} from "../../lib/SafeMath.sol"; import {DecimalMath} from "../../lib/DecimalMath.sol"; import {DODOMath} from "../../lib/DODOMath.sol"; +import {IExternalCall} from "../intf/IExternalCall.sol"; contract DVMTrader is DVMStorage { using SafeMath for uint256; @@ -19,7 +20,7 @@ contract DVMTrader is DVMStorage { function sellBase(address to) external returns (uint256 receiveQuoteAmount) { uint256 baseInput = _VAULT_.getBaseInput(); uint256 mtFee; - (receiveQuoteAmount, mtFee) = querySellBase(baseInput); + (receiveQuoteAmount, mtFee) = querySellBase(to, baseInput); _VAULT_.transferQuoteOut(to, receiveQuoteAmount); if (mtFee > 0) { _VAULT_.transferQuoteOut(_MAINTAINER_, mtFee); @@ -31,7 +32,7 @@ contract DVMTrader is DVMStorage { function sellQuote(address to) external returns (uint256 receiveBaseAmount) { uint256 quoteInput = _VAULT_.getQuoteInput(); uint256 mtFee; - (receiveBaseAmount, mtFee) = querySellQuote(quoteInput); + (receiveBaseAmount, mtFee) = querySellQuote(to, quoteInput); _VAULT_.transferBaseOut(to, receiveBaseAmount); if (mtFee > 0) { _VAULT_.transferBaseOut(_MAINTAINER_, mtFee); @@ -40,50 +41,82 @@ contract DVMTrader is DVMStorage { return receiveBaseAmount; } - function querySellBase(uint256 payBaseAmount) + function flashLoan( + uint256 baseAmount, + uint256 quoteAmount, + address assetTo, + address call, + bytes calldata data + ) external { + (uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve(); + uint256 B0 = getBase0(baseReserve, quoteReserve); + + uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(assetTo, quoteAmount); + uint256 baseMtFee = DecimalMath.mulCeil(baseAmount, mtFeeRate); + uint256 quoteMtFee = DecimalMath.mulCeil(quoteAmount, mtFeeRate); + + _VAULT_.transferBaseOut(_MAINTAINER_, baseMtFee); + _VAULT_.transferQuoteOut(_MAINTAINER_, quoteMtFee); + _VAULT_.transferBaseOut(assetTo, baseAmount); + _VAULT_.transferQuoteOut(assetTo, quoteAmount); + + IExternalCall(call).DVMCall(data); + + (uint256 baseBalance, uint256 quoteBalance) = _VAULT_.getVaultBalance(); + uint256 newB0 = getBase0(baseBalance, quoteBalance); + require(newB0 >= B0, "FLASH_LOAN_FAILED"); + _VAULT_.sync(); + } + + function querySellBase(address trader, uint256 payBaseAmount) public view returns (uint256 receiveQuoteAmount, uint256 mtFee) { - uint256 B0 = getBase0(); - uint256 B2 = _VAULT_._BASE_RESERVE_(); - uint256 B1 = B2.add(payBaseAmount); + (uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve(); + uint256 B0 = getBase0(baseReserve, quoteReserve); + + uint256 B1 = baseReserve.add(payBaseAmount); require(B0 >= B1, "DODO_BASE_BALANCE_NOT_ENOUGH"); - uint256 Q = DODOMath._GeneralIntegrate(B0, B1, B2, _I_, _K_); - uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(Q); - uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(Q); + uint256 Q = DODOMath._GeneralIntegrate(B0, B1, baseReserve, _I_, _K_); + + uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(trader, Q); + uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(trader, Q); mtFee = DecimalMath.mulCeil(Q, mtFeeRate); receiveQuoteAmount = Q.sub(mtFee).sub(DecimalMath.mulCeil(Q, lpFeeRate)); + return (receiveQuoteAmount, mtFee); } - function querySellQuote(uint256 payQuoteAmount) + function querySellQuote(address trader, uint256 payQuoteAmount) public view returns (uint256 receiveBaseAmount, uint256 mtFee) { - uint256 B0 = getBase0(); - uint256 B1 = _VAULT_._BASE_RESERVE_(); + (uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve(); + uint256 B0 = getBase0(baseReserve, quoteReserve); + uint256 fairAmount = DecimalMath.divFloor(payQuoteAmount, _I_); uint256 newBaseReserve = DODOMath._SolveQuadraticFunctionForTrade( B0, - B1, + baseReserve, fairAmount, false, _K_ ); - uint256 deltaBase = B1.sub(newBaseReserve); - uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(payQuoteAmount); - uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(payQuoteAmount); + uint256 deltaBase = baseReserve.sub(newBaseReserve); + uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(trader, payQuoteAmount); + uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(trader, payQuoteAmount); mtFee = DecimalMath.mulCeil(deltaBase, mtFeeRate); receiveBaseAmount = deltaBase.sub(mtFee).sub(DecimalMath.mulCeil(deltaBase, lpFeeRate)); return (receiveBaseAmount, mtFee); } function getMidPrice() public view returns (uint256 midPrice) { - uint256 B0 = getBase0(); - uint256 B1 = _VAULT_._BASE_RESERVE_(); - uint256 offsetRatio = DecimalMath.ONE.mul(B0).div(B1).mul(B0).div(B1); + (uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve(); + uint256 B0 = getBase0(baseReserve, quoteReserve); + + uint256 offsetRatio = DecimalMath.ONE.mul(B0).div(baseReserve).mul(B0).div(baseReserve); uint256 offset = DecimalMath.ONE.sub(_K_).add(DecimalMath.mulFloor(offsetRatio, _K_)); return DecimalMath.mulFloor(_I_, offset); } diff --git a/contracts/DODOVendorMachine/impl/DVMVault.sol b/contracts/DODOVendorMachine/impl/DVMVault.sol index 5e0e5d9..f68315d 100644 --- a/contracts/DODOVendorMachine/impl/DVMVault.sol +++ b/contracts/DODOVendorMachine/impl/DVMVault.sol @@ -109,14 +109,6 @@ contract DVMVault is InitializableOwnable { } } - function transferOut( - address token, - address to, - uint256 amount - ) public onlyOwner { - IERC20(token).safeTransfer(to, amount); - } - function transferBaseOut(address to, uint256 amount) public onlyOwner { IERC20(_BASE_TOKEN_).safeTransfer(to, amount); } @@ -208,4 +200,6 @@ contract DVMVault is InitializableOwnable { emit Burn(user, value); emit Transfer(user, address(0), value); } + + // function approveAndCall() } diff --git a/contracts/DODOVendorMachine/intf/IDVM.sol b/contracts/DODOVendorMachine/intf/IDVM.sol new file mode 100644 index 0000000..8569973 --- /dev/null +++ b/contracts/DODOVendorMachine/intf/IDVM.sol @@ -0,0 +1,23 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +interface IDVM { + function init( + address owner, + address maintainer, + address vault, + address lpFeeRateModel, + address mtFeeRateModel, + address tradePermissionManager, + address fundingPermissionManager, + uint256 i, + uint256 k + ) external; +} diff --git a/contracts/DODOVendorMachine/intf/IDVMVault.sol b/contracts/DODOVendorMachine/intf/IDVMVault.sol new file mode 100644 index 0000000..eba49e2 --- /dev/null +++ b/contracts/DODOVendorMachine/intf/IDVMVault.sol @@ -0,0 +1,17 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +interface IDVMVault { + function init( + address owner, + address _baseToken, + address _quoteToken + ) external; +} diff --git a/contracts/DODOVendorMachine/intf/IExternalCall.sol b/contracts/DODOVendorMachine/intf/IExternalCall.sol new file mode 100644 index 0000000..fbd517e --- /dev/null +++ b/contracts/DODOVendorMachine/intf/IExternalCall.sol @@ -0,0 +1,13 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +interface IExternalCall { + function DVMCall(bytes calldata data) external; +} diff --git a/contracts/Factory/DVMFactory.sol b/contracts/Factory/DVMFactory.sol new file mode 100644 index 0000000..f67369f --- /dev/null +++ b/contracts/Factory/DVMFactory.sol @@ -0,0 +1,93 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {Ownable} from "../lib/Ownable.sol"; +import {ICloneFactory} from "../lib/CloneFactory.sol"; +import {IConstFeeRateModel} from "../lib/ConstFeeRateModel.sol"; +import {IDVM} from "../DODOVendorMachine/intf/IDVM.sol"; +import {IDVMVault} from "../DODOVendorMachine/intf/IDVMVault.sol"; +import {IPermissionManager} from "../lib/PermissionManager.sol"; + +contract DVMFactory is Ownable { + address public _CLONE_FACTORY_; + address public _VAULT_TEMPLATE_; + address public _DVM_TEMPLATE_; + address public _FEE_RATE_MODEL_TEMPLATE_; + address public _PERMISSION_MANAGER_TEMPLATE_; + + // base -> quote -> DVM address list + mapping(address => mapping(address => address[])) _REGISTRY_; + + constructor( + address cloneFactory, + address vaultTemplate, + address dvmTemplate, + address feeRateModelTemplate, + address permissionManagerTemplate + ) public { + _CLONE_FACTORY_ = cloneFactory; + _VAULT_TEMPLATE_ = vaultTemplate; + _DVM_TEMPLATE_ = dvmTemplate; + _FEE_RATE_MODEL_TEMPLATE_ = feeRateModelTemplate; + _PERMISSION_MANAGER_TEMPLATE_ = permissionManagerTemplate; + } + + function createStandardDODOVendorMachine( + address baseToken, + address quoteToken, + uint256 lpFeeRate, + uint256 mtFeeRate, + uint256 i, + uint256 k + ) external returns (address newVendorMachine) { + newVendorMachine = ICloneFactory(_CLONE_FACTORY_).clone(_DVM_TEMPLATE_); + + address vault = ICloneFactory(_CLONE_FACTORY_).clone(_VAULT_TEMPLATE_); + + IDVMVault(vault).init(newVendorMachine, baseToken, quoteToken); // vault owner is controller + IDVM(newVendorMachine).init( + msg.sender, + msg.sender, + vault, + createConstFeeRateModel(msg.sender, lpFeeRate), + createConstFeeRateModel(msg.sender, mtFeeRate), + createPermissionManager(msg.sender), + createPermissionManager(msg.sender), + i, + k + ); + + _REGISTRY_[baseToken][quoteToken].push(newVendorMachine); + return newVendorMachine; + } + + function createConstFeeRateModel(address owner, uint256 feeRate) + public + returns (address feeRateModel) + { + feeRateModel = ICloneFactory(_CLONE_FACTORY_).clone(_FEE_RATE_MODEL_TEMPLATE_); + IConstFeeRateModel(feeRateModel).init(owner, feeRate); + return feeRateModel; + } + + function createPermissionManager(address owner) public returns (address permissionManager) { + permissionManager = ICloneFactory(_CLONE_FACTORY_).clone(_PERMISSION_MANAGER_TEMPLATE_); + IPermissionManager(permissionManager).initOwner(owner); + return permissionManager; + } + + function getVendorMachine(address baseToken, address quoteToken) + external + view + returns (address[] memory machines) + { + return _REGISTRY_[baseToken][quoteToken]; + } +} diff --git a/contracts/SmartRoute/SmartRoute.sol b/contracts/SmartRoute/SmartRoute.sol index f1a7712..d7949bf 100644 --- a/contracts/SmartRoute/SmartRoute.sol +++ b/contracts/SmartRoute/SmartRoute.sol @@ -8,7 +8,7 @@ pragma solidity 0.6.9; import {Ownable} from "../lib/Ownable.sol"; -import {DVMController} from "../DODOVendorMachine/impl/DVMController.sol"; +import {DVM} from "../DODOVendorMachine/impl/DVM.sol"; import {DVMVault} from "../DODOVendorMachine/impl/DVMVault.sol"; import {IERC20} from "../intf/IERC20.sol"; import {SafeERC20} from "../lib/SafeERC20.sol"; @@ -20,49 +20,47 @@ contract SmartRoute is Ownable { using SafeERC20 for IERC20; function sellBaseOnDVM( - address DVM, + address DVMAddress, address to, uint256 baseAmount, uint256 minReceive ) public returns (uint256 receiveAmount) { - IERC20(DVMController(DVM)._BASE_TOKEN_()).safeTransferFrom( + IERC20(DVM(DVMAddress)._BASE_TOKEN_()).safeTransferFrom( msg.sender, - address(DVMController(DVM)._VAULT_()), + address(DVM(DVMAddress)._VAULT_()), baseAmount ); - receiveAmount = DVMController(DVM).sellBase(to); + receiveAmount = DVM(DVMAddress).sellBase(to); require(receiveAmount >= minReceive, "RECEIVE_NOT_ENOUGH"); return receiveAmount; } function sellQuoteOnDVM( - address DVM, + address DVMAddress, address to, uint256 quoteAmount, uint256 minReceive ) public returns (uint256 receiveAmount) { - IERC20(DVMController(DVM)._QUOTE_TOKEN_()).safeTransferFrom( + IERC20(DVM(DVMAddress)._QUOTE_TOKEN_()).safeTransferFrom( msg.sender, - address(DVMController(DVM)._VAULT_()), + address(DVM(DVMAddress)._VAULT_()), quoteAmount ); - receiveAmount = DVMController(DVM).sellQuote(to); + receiveAmount = DVM(DVMAddress).sellQuote(to); require(receiveAmount >= minReceive, "RECEIVE_NOT_ENOUGU"); return receiveAmount; } function depositToDVM( - address DVM, + address DVMAddress, address to, uint256 baseAmount, uint256 quoteAmount ) public returns (uint256 shares) { - address vault = address(DVMController(DVM)._VAULT_()); + address vault = address(DVM(DVMAddress)._VAULT_()); uint256 adjustedBaseAmount; uint256 adjustedQuoteAmount; - (uint256 baseReserve, uint256 quoteReserve) = DVMController(DVM) - ._VAULT_() - .getVaultReserve(); + (uint256 baseReserve, uint256 quoteReserve) = DVM(DVMAddress)._VAULT_().getVaultReserve(); if (quoteReserve == 0 && baseReserve == 0) { adjustedBaseAmount = baseAmount; @@ -86,17 +84,17 @@ contract SmartRoute is Ownable { } } - IERC20(DVMController(DVM)._BASE_TOKEN_()).safeTransferFrom( + IERC20(DVM(DVMAddress)._BASE_TOKEN_()).safeTransferFrom( msg.sender, vault, adjustedBaseAmount ); - IERC20(DVMController(DVM)._QUOTE_TOKEN_()).safeTransferFrom( + IERC20(DVM(DVMAddress)._QUOTE_TOKEN_()).safeTransferFrom( msg.sender, vault, adjustedQuoteAmount ); - return DVMController(DVM).buyShares(to); + return DVM(DVMAddress).buyShares(to); } } diff --git a/contracts/helper/ConstFeeRateModel.sol b/contracts/helper/ConstFeeRateModel.sol deleted file mode 100644 index a3afd17..0000000 --- a/contracts/helper/ConstFeeRateModel.sol +++ /dev/null @@ -1,23 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - -import {IFeeRateModel} from "../intf/IFeeRateModel.sol"; - -contract ConstFeeRateModel is IFeeRateModel { - uint256 public _FEE_RATE_; - - constructor(uint256 feeRate) public { - feeRate = _FEE_RATE_; - } - - function getFeeRate(uint256) external override view returns (uint256) { - return _FEE_RATE_; - } -} diff --git a/contracts/helper/NaiveFeeRateModel.sol b/contracts/helper/NaiveFeeRateModel.sol deleted file mode 100644 index 7b5727d..0000000 --- a/contracts/helper/NaiveFeeRateModel.sol +++ /dev/null @@ -1,28 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - -import {IFeeRateModel} from "../intf/IFeeRateModel.sol"; -import {Ownable} from "../lib/Ownable.sol"; - -contract NaiveFeeRateModel is Ownable, IFeeRateModel { - uint256 public _FEE_RATE_; - - constructor(uint256 feeRate) public { - _FEE_RATE_ = feeRate; - } - - function setFeeRate(uint256 newFeeRate) external { - _FEE_RATE_ = newFeeRate; - } - - function getFeeRate(uint256) external override view returns (uint256) { - return _FEE_RATE_; - } -} diff --git a/contracts/intf/IFeeRateModel.sol b/contracts/intf/IFeeRateModel.sol index 81c3fdd..10e7a30 100644 --- a/contracts/intf/IFeeRateModel.sol +++ b/contracts/intf/IFeeRateModel.sol @@ -8,7 +8,6 @@ pragma solidity 0.6.9; pragma experimental ABIEncoderV2; - interface IFeeRateModel { - function getFeeRate(uint256 amount) external view returns (uint256); + function getFeeRate(address trader, uint256 amount) external view returns (uint256); } diff --git a/contracts/lib/ConstFeeRateModel.sol b/contracts/lib/ConstFeeRateModel.sol new file mode 100644 index 0000000..4cf695c --- /dev/null +++ b/contracts/lib/ConstFeeRateModel.sol @@ -0,0 +1,38 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {IFeeRateModel} from "../intf/IFeeRateModel.sol"; +import {Ownable} from "../lib/Ownable.sol"; +import {InitializableOwnable} from "../lib/InitializableOwnable.sol"; + +interface IConstFeeRateModel { + function init(address owner, uint256 feeRate) external; + + function setFeeRate(uint256 newFeeRate) external; + + function getFeeRate(address, uint256) external view returns (uint256); +} + +contract ConstFeeRateModel is InitializableOwnable, IFeeRateModel { + uint256 public _FEE_RATE_; + + function init(address owner, uint256 feeRate) external { + initOwner(owner); + _FEE_RATE_ = feeRate; + } + + function setFeeRate(uint256 newFeeRate) external { + _FEE_RATE_ = newFeeRate; + } + + function getFeeRate(address, uint256) external override view returns (uint256) { + return _FEE_RATE_; + } +} diff --git a/contracts/lib/OperatorSystem.sol b/contracts/lib/OperatorSystem.sol new file mode 100644 index 0000000..c2be516 --- /dev/null +++ b/contracts/lib/OperatorSystem.sol @@ -0,0 +1,36 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {InitializableOwnable} from "./InitializableOwnable.sol"; + +contract OperatorSystem is InitializableOwnable { + mapping(address => bool) internal _global_operator_; + mapping(address => mapping(address => bool)) internal _operator_; // user=>operator=>isValid + + function isValidOperator(address user, address operator) external view returns (bool) { + return user == operator || _global_operator_[operator] || _operator_[user][operator]; + } + + function addGlobalOperator(address operator) external onlyOwner { + _global_operator_[operator] = true; + } + + function removeGlobalOperator(address operator) external onlyOwner { + _global_operator_[operator] = false; + } + + function addOperator(address operator) external { + _operator_[msg.sender][operator] = true; + } + + function removeOperator(address operator) external { + _operator_[msg.sender][operator] = false; + } +} diff --git a/contracts/lib/PermissionManager.sol b/contracts/lib/PermissionManager.sol index e813039..cc9d6d7 100644 --- a/contracts/lib/PermissionManager.sol +++ b/contracts/lib/PermissionManager.sol @@ -10,44 +10,47 @@ pragma experimental ABIEncoderV2; import {InitializableOwnable} from "./InitializableOwnable.sol"; +interface IPermissionManager { + function initOwner(address) external; + + function isAllowed(address) external returns (bool); +} + contract PermissionManager is InitializableOwnable { + bool public _BLACKLIST_MODE_ON_; - bool public _BLACKLIST_MODE_ON_; + mapping(address => bool) internal _whitelist_; + mapping(address => bool) internal _blacklist_; - mapping(address => bool) internal _whitelist_; - mapping(address => bool) internal _blacklist_; - - function isAllowed(address account) external view returns(bool){ - if (_BLACKLIST_MODE_ON_) { - return !_blacklist_[account]; - } else { - return _whitelist_[account]; + function isAllowed(address account) external view returns (bool) { + if (_BLACKLIST_MODE_ON_) { + return !_blacklist_[account]; + } else { + return _whitelist_[account]; + } } - } - function openBlacklist() external onlyOwner { - _BLACKLIST_MODE_ON_ = true; - } + function openBlacklist() external onlyOwner { + _BLACKLIST_MODE_ON_ = true; + } - function openWhitelist() external onlyOwner { - _BLACKLIST_MODE_ON_ = true; + function openWhitelist() external onlyOwner { + _BLACKLIST_MODE_ON_ = true; + } - } + function addToWhitelist(address account) external onlyOwner { + _whitelist_[account] = true; + } - function addToWhitelist(address account) external onlyOwner{ - _whitelist_[account] = true; - } + function removeFromWhitelist(address account) external onlyOwner { + _whitelist_[account] = false; + } - function removeFromWhitelist(address account) external onlyOwner{ - _whitelist_[account] = false; - } + function addToBlacklist(address account) external onlyOwner { + _blacklist_[account] = true; + } - function addToBlacklist(address account) external onlyOwner{ - _blacklist_[account] = true; - } - - function removeFromBlacklist(address account) external onlyOwner{ - _blacklist_[account] = false; - } - -} \ No newline at end of file + function removeFromBlacklist(address account) external onlyOwner { + _blacklist_[account] = false; + } +} From b31f1a30e26923c6b7baf6c1c686d4efc7d2a642 Mon Sep 17 00:00:00 2001 From: mingda Date: Thu, 5 Nov 2020 14:10:59 +0800 Subject: [PATCH 101/118] fix test --- .../DODOVendorMachine/impl/DVMFunding.sol | 26 +++++++++------ .../DODOVendorMachine/impl/DVMStorage.sol | 8 ++++- .../DODOVendorMachine/impl/DVMTrader.sol | 10 +++--- contracts/SmartRoute/SmartRoute.sol | 4 ++- test/DVM/funding.test.ts | 13 ++++++++ test/DVM/trader.test.ts | 6 ++-- test/utils/Contracts.ts | 5 +-- test/utils/DVMContext.ts | 33 ++++++++++--------- 8 files changed, 68 insertions(+), 37 deletions(-) diff --git a/contracts/DODOVendorMachine/impl/DVMFunding.sol b/contracts/DODOVendorMachine/impl/DVMFunding.sol index 65be8bb..346cc72 100644 --- a/contracts/DODOVendorMachine/impl/DVMFunding.sol +++ b/contracts/DODOVendorMachine/impl/DVMFunding.sol @@ -12,7 +12,7 @@ import {DVMStorage} from "./DVMStorage.sol"; import {DecimalMath} from "../../lib/DecimalMath.sol"; contract DVMFunding is DVMStorage { - function buyShares(address account) external returns (uint256) { + function buyShares(address to) external returns (uint256) { uint256 baseInput = _VAULT_.getBaseInput(); uint256 quoteInput = _VAULT_.getQuoteInput(); require(baseInput > 0, "NO_BASE_INPUT"); @@ -42,22 +42,28 @@ contract DVMFunding is DVMStorage { mintAmount = baseInput; } } - _VAULT_.mint(account, mintAmount); + _VAULT_.mint(to, mintAmount); _VAULT_.sync(); } - function sellShares( - address account, - address to, - uint256 amount - ) external returns (uint256) { - require(msg.sender == account, "PERMISSION_DENY"); - require(_VAULT_.balanceOf(account) >= amount, "SHARES_NOT_ENOUGH"); + function sellShares(address to, uint256 amount) external returns (uint256) { + require(_VAULT_.balanceOf(msg.sender) >= amount, "SHARES_NOT_ENOUGH"); (uint256 baseBalance, uint256 quoteBalance) = _VAULT_.getVaultBalance(); uint256 totalShares = _VAULT_.totalSupply(); - _VAULT_.burn(account, amount); + _VAULT_.burn(msg.sender, amount); _VAULT_.transferBaseOut(to, baseBalance.mul(amount).div(totalShares)); _VAULT_.transferQuoteOut(to, quoteBalance.mul(amount).div(totalShares)); _VAULT_.sync(); } + + function retrieve(address to) external { + (uint256 baseBalance, uint256 quoteBalance) = _VAULT_.getVaultBalance(); + (uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve(); + if (baseBalance.sub(baseReserve) > 0) { + _VAULT_.transferBaseOut(to, baseBalance.sub(baseReserve)); + } + if (quoteBalance.sub(quoteReserve) > 0) { + _VAULT_.transferQuoteOut(to, quoteBalance.sub(quoteReserve)); + } + } } diff --git a/contracts/DODOVendorMachine/impl/DVMStorage.sol b/contracts/DODOVendorMachine/impl/DVMStorage.sol index 0d5f314..848fc2f 100644 --- a/contracts/DODOVendorMachine/impl/DVMStorage.sol +++ b/contracts/DODOVendorMachine/impl/DVMStorage.sol @@ -58,7 +58,13 @@ contract DVMStorage is InitializableOwnable, ReentrancyGuard { // ============ Helper Functions ============ - function getBase0(uint256 baseAmount, uint256 quoteAmount) public view returns (uint256) { + function calculateBase0(uint256 baseAmount, uint256 quoteAmount) public view returns (uint256) { + uint256 fairAmount = DecimalMath.divFloor(quoteAmount, _I_); + return DODOMath._SolveQuadraticFunctionForTarget(baseAmount, _K_, fairAmount); + } + + function getBase0() public view returns (uint256) { + (uint256 baseAmount, uint256 quoteAmount) = _VAULT_.getVaultReserve(); uint256 fairAmount = DecimalMath.divFloor(quoteAmount, _I_); return DODOMath._SolveQuadraticFunctionForTarget(baseAmount, _K_, fairAmount); } diff --git a/contracts/DODOVendorMachine/impl/DVMTrader.sol b/contracts/DODOVendorMachine/impl/DVMTrader.sol index c212df4..52d0286 100644 --- a/contracts/DODOVendorMachine/impl/DVMTrader.sol +++ b/contracts/DODOVendorMachine/impl/DVMTrader.sol @@ -49,7 +49,7 @@ contract DVMTrader is DVMStorage { bytes calldata data ) external { (uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve(); - uint256 B0 = getBase0(baseReserve, quoteReserve); + uint256 B0 = calculateBase0(baseReserve, quoteReserve); uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(assetTo, quoteAmount); uint256 baseMtFee = DecimalMath.mulCeil(baseAmount, mtFeeRate); @@ -63,7 +63,7 @@ contract DVMTrader is DVMStorage { IExternalCall(call).DVMCall(data); (uint256 baseBalance, uint256 quoteBalance) = _VAULT_.getVaultBalance(); - uint256 newB0 = getBase0(baseBalance, quoteBalance); + uint256 newB0 = calculateBase0(baseBalance, quoteBalance); require(newB0 >= B0, "FLASH_LOAN_FAILED"); _VAULT_.sync(); } @@ -74,7 +74,7 @@ contract DVMTrader is DVMStorage { returns (uint256 receiveQuoteAmount, uint256 mtFee) { (uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve(); - uint256 B0 = getBase0(baseReserve, quoteReserve); + uint256 B0 = calculateBase0(baseReserve, quoteReserve); uint256 B1 = baseReserve.add(payBaseAmount); require(B0 >= B1, "DODO_BASE_BALANCE_NOT_ENOUGH"); @@ -94,7 +94,7 @@ contract DVMTrader is DVMStorage { returns (uint256 receiveBaseAmount, uint256 mtFee) { (uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve(); - uint256 B0 = getBase0(baseReserve, quoteReserve); + uint256 B0 = calculateBase0(baseReserve, quoteReserve); uint256 fairAmount = DecimalMath.divFloor(payQuoteAmount, _I_); uint256 newBaseReserve = DODOMath._SolveQuadraticFunctionForTrade( @@ -114,7 +114,7 @@ contract DVMTrader is DVMStorage { function getMidPrice() public view returns (uint256 midPrice) { (uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve(); - uint256 B0 = getBase0(baseReserve, quoteReserve); + uint256 B0 = calculateBase0(baseReserve, quoteReserve); uint256 offsetRatio = DecimalMath.ONE.mul(B0).div(baseReserve).mul(B0).div(baseReserve); uint256 offset = DecimalMath.ONE.sub(_K_).add(DecimalMath.mulFloor(offsetRatio, _K_)); diff --git a/contracts/SmartRoute/SmartRoute.sol b/contracts/SmartRoute/SmartRoute.sol index d7949bf..5e0d958 100644 --- a/contracts/SmartRoute/SmartRoute.sol +++ b/contracts/SmartRoute/SmartRoute.sol @@ -95,6 +95,8 @@ contract SmartRoute is Ownable { adjustedQuoteAmount ); - return DVM(DVMAddress).buyShares(to); + shares = DVM(DVMAddress).buyShares(to); + + return shares; } } diff --git a/test/DVM/funding.test.ts b/test/DVM/funding.test.ts index 0f90ac4..93b7625 100644 --- a/test/DVM/funding.test.ts +++ b/test/DVM/funding.test.ts @@ -141,4 +141,17 @@ describe("Funding", () => { assert.equal(await ctx.Vault.methods.balanceOf(trader).call(), "499999999999999990") }) }); + + describe("sell shares", () => { + it("sell shares", async () => { + await ctx.Route.methods + .depositToDVM(ctx.DVM.options.address, lp, decimalStr("10"), decimalStr("100")) + .send(ctx.sendParam(lp)); + var vaultShares = await ctx.Vault.methods.balanceOf(lp).call() + var bob = ctx.SpareAccounts[0] + await ctx.DVM.methods.sellShares(bob, vaultShares).send(ctx.sendParam(lp)) + assert.equal(await ctx.BASE.methods.balanceOf(bob).call(), decimalStr("10")) + assert.equal(await ctx.QUOTE.methods.balanceOf(bob).call(), decimalStr("100")) + }) + }) }); diff --git a/test/DVM/trader.test.ts b/test/DVM/trader.test.ts index 6580bc0..e63d7e9 100644 --- a/test/DVM/trader.test.ts +++ b/test/DVM/trader.test.ts @@ -53,11 +53,11 @@ describe("Trader", () => { describe("trade", () => { it("buy & sell", async () => { - console.log("BASE0 before buy", await ctx.DVM.methods._BASE0_().call()) + console.log("BASE0 before buy", await ctx.DVM.methods.getBase0().call()) // buy await logGas(ctx.Route.methods.sellQuoteOnDVM(ctx.DVM.options.address, trader, decimalStr("200"), decimalStr("1")), ctx.sendParam(trader), "buy base token") - console.log("BASE0 after buy", await ctx.DVM.methods._BASE0_().call()) + console.log("BASE0 after buy", await ctx.DVM.methods.getBase0().call()) // trader balances assert.equal( await ctx.BASE.methods.balanceOf(trader).call(), @@ -88,7 +88,7 @@ describe("Trader", () => { // sell await logGas(ctx.Route.methods.sellBaseOnDVM(ctx.DVM.options.address, trader, decimalStr("1"), decimalStr("100")), ctx.sendParam(trader), "sell base token") - console.log("BASE0 after sell", await ctx.DVM.methods._BASE0_().call()) + console.log("BASE0 after sell", await ctx.DVM.methods.getBase0().call()) // trader balances assert.equal( await ctx.BASE.methods.balanceOf(trader).call(), diff --git a/test/utils/Contracts.ts b/test/utils/Contracts.ts index fae2178..f781f46 100644 --- a/test/utils/Contracts.ts +++ b/test/utils/Contracts.ts @@ -29,10 +29,11 @@ export const LOCKED_TOKEN_VAULT_CONTRACT_NAME = "LockedTokenVault" export const DODO_MINE_NAME = "DODOMine" export const DODO_MINE_READER_NAME = "DODOMineReader" export const DVM_VAULT_NAME = "DVMVault" -export const DVM_CONTROLLER_NAME = "DVMController" +export const DVM_NAME = "DVM" export const DVM_FACTORY_NAME = "DVMFactory" export const SMART_ROUTE_NAME = "SmartRoute" -export const NAIVE_FEE_RATE_MODEL_NAME = "NaiveFeeRateModel" +export const CONST_FEE_RATE_MODEL_NAME = "ConstFeeRateModel" +export const PERMISSION_MANAGER_NAME = "PermissionManager" interface ContractJson { abi: any; diff --git a/test/utils/DVMContext.ts b/test/utils/DVMContext.ts index 17d5d7d..2f35a1e 100644 --- a/test/utils/DVMContext.ts +++ b/test/utils/DVMContext.ts @@ -10,7 +10,7 @@ import Web3 from 'web3'; import { Contract } from 'web3-eth-contract'; import * as contracts from './Contracts'; -import { decimalStr, gweiStr, MAX_UINT256 } from './Converter'; +import { decimalStr, MAX_UINT256 } from './Converter'; import { EVM, getDefaultWeb3 } from './EVM'; import * as log from './Log'; @@ -24,7 +24,6 @@ export interface DVMContextInitConfig { mtFeeRate: string; k: string; i: string; - gasPriceLimit: string; } /* @@ -45,7 +44,6 @@ export let DefaultDVMContextInitConfig = { mtFeeRate: decimalStr("0.001"), k: decimalStr("0.1"), i: decimalStr("100"), - gasPriceLimit: gweiStr("100"), }; export class DVMContext { @@ -72,9 +70,16 @@ export class DVMContext { contracts.CLONE_FACTORY_CONTRACT_NAME ); var vaultTemplate = await contracts.newContract(contracts.DVM_VAULT_NAME) - var controllerTemplate = await contracts.newContract(contracts.DVM_CONTROLLER_NAME) + var dvmTemplate = await contracts.newContract(contracts.DVM_NAME) + var feeRateModelTemplate = await contracts.newContract(contracts.CONST_FEE_RATE_MODEL_NAME) + var permissionManagerTemplate = await contracts.newContract(contracts.PERMISSION_MANAGER_NAME) - this.DVMFactory = await contracts.newContract(contracts.DVM_FACTORY_NAME, [cloneFactory.options.address, vaultTemplate.options.address, controllerTemplate.options.address]) + this.DVMFactory = await contracts.newContract(contracts.DVM_FACTORY_NAME, + [cloneFactory.options.address, + vaultTemplate.options.address, + dvmTemplate.options.address, + feeRateModelTemplate.options.address, + permissionManagerTemplate.options.address]) this.BASE = await contracts.newContract( contracts.MINTABLE_ERC20_CONTRACT_NAME, @@ -90,23 +95,21 @@ export class DVMContext { this.Maintainer = allAccounts[1]; this.SpareAccounts = allAccounts.slice(2, 10); - var lpFeeRateModel = await contracts.newContract(contracts.NAIVE_FEE_RATE_MODEL_NAME, [config.lpFeeRate]) - var mtFeeRateModel = await contracts.newContract(contracts.NAIVE_FEE_RATE_MODEL_NAME, [config.mtFeeRate]) - await this.DVMFactory.methods.createDODOVendorMachine( - this.Maintainer, + await this.DVMFactory.methods.createStandardDODOVendorMachine( this.BASE.options.address, this.QUOTE.options.address, - lpFeeRateModel.options.address, - mtFeeRateModel.options.address, + config.lpFeeRate, + config.mtFeeRate, config.i, - config.k, - config.gasPriceLimit).send(this.sendParam(this.Deployer)) + config.k + ).send(this.sendParam(this.Deployer)) var vendorMachines = await this.DVMFactory.methods.getVendorMachine(this.BASE.options.address, this.QUOTE.options.address).call() - this.DVM = contracts.getContractWithAddress(contracts.DVM_CONTROLLER_NAME, vendorMachines[0]) - + this.DVM = contracts.getContractWithAddress(contracts.DVM_NAME, vendorMachines[0]) this.Vault = contracts.getContractWithAddress(contracts.DVM_VAULT_NAME, await this.DVM.methods._VAULT_().call()) + await this.DVM.methods.setMaintainer(this.Maintainer).send(this.sendParam(this.Deployer)) + console.log(log.blueText("[Init DVM context]")); } From cdb5a3ba6200b63078f3c036111b2bce78576dd1 Mon Sep 17 00:00:00 2001 From: mingda Date: Fri, 6 Nov 2020 00:31:30 +0800 Subject: [PATCH 102/118] flash loan --- contracts/DODOVendorMachine/impl/DVM.sol | 2 - .../DODOVendorMachine/impl/DVMStorage.sol | 34 +++++++++---- .../DODOVendorMachine/impl/DVMTrader.sol | 50 ++++++++++++------- contracts/DODOVendorMachine/impl/DVMVault.sol | 8 ++- contracts/DODOVendorMachine/intf/IDVM.sol | 1 - contracts/Factory/DVMFactory.sol | 1 - contracts/intf/IFeeRateModel.sol | 2 +- contracts/lib/ConstFeeRateModel.sol | 6 +-- 8 files changed, 65 insertions(+), 39 deletions(-) diff --git a/contracts/DODOVendorMachine/impl/DVM.sol b/contracts/DODOVendorMachine/impl/DVM.sol index 8310d88..70ea6d2 100644 --- a/contracts/DODOVendorMachine/impl/DVM.sol +++ b/contracts/DODOVendorMachine/impl/DVM.sol @@ -22,7 +22,6 @@ contract DVM is DVMTrader, DVMFunding { address lpFeeRateModel, address mtFeeRateModel, address tradePermissionManager, - address fundingPermissionManager, uint256 i, uint256 k ) external { @@ -33,7 +32,6 @@ contract DVM is DVMTrader, DVMFunding { _LP_FEE_RATE_MODEL_ = IFeeRateModel(lpFeeRateModel); _MT_FEE_RATE_MODEL_ = IFeeRateModel(mtFeeRateModel); _TRADE_PERMISSION_ = IPermissionManager(tradePermissionManager); - _FUNDING_PERMISSION_ = IPermissionManager(fundingPermissionManager); _MAINTAINER_ = maintainer; _I_ = i; _K_ = k; diff --git a/contracts/DODOVendorMachine/impl/DVMStorage.sol b/contracts/DODOVendorMachine/impl/DVMStorage.sol index 848fc2f..e2712f3 100644 --- a/contracts/DODOVendorMachine/impl/DVMStorage.sol +++ b/contracts/DODOVendorMachine/impl/DVMStorage.sol @@ -22,16 +22,14 @@ contract DVMStorage is InitializableOwnable, ReentrancyGuard { // ============ Variables for Control ============ - bool public _CLOSED_; uint256 public _GAS_PRICE_LIMIT_; // ============ Advanced Controls ============ - bool public _BUYING_ALLOWED_; - bool public _SELLING_ALLOWED_; + bool public _BUYING_CLOSE_; + bool public _SELLING_CLOSE_; IPermissionManager public _TRADE_PERMISSION_; - IPermissionManager public _FUNDING_PERMISSION_; // ============ Core Address ============ @@ -51,8 +49,16 @@ contract DVMStorage is InitializableOwnable, ReentrancyGuard { // ============ Modifiers ============ - modifier notClosed() { - require(!_CLOSED_, "DODO_CLOSED"); + modifier isBuyAllow(address trader) { + require(!_BUYING_CLOSE_ && _TRADE_PERMISSION_.isAllowed(trader), "TRADER_BUY_NOT_ALLOWED"); + _; + } + + modifier isSellAllow(address trader) { + require( + !_SELLING_CLOSE_ && _TRADE_PERMISSION_.isAllowed(trader), + "TRADER_SELL_NOT_ALLOWED" + ); _; } @@ -83,11 +89,19 @@ contract DVMStorage is InitializableOwnable, ReentrancyGuard { _TRADE_PERMISSION_ = IPermissionManager(newTradePermissionManager); } - function setFundingPermissionManager(address newFundingPermissionManager) external onlyOwner { - _FUNDING_PERMISSION_ = IPermissionManager(newFundingPermissionManager); - } - function setMaintainer(address newMaintainer) external onlyOwner { _MAINTAINER_ = newMaintainer; } + + function setGasPriceLimit(uint256 newGasPriceLimit) external onlyOwner { + _GAS_PRICE_LIMIT_ = newGasPriceLimit; + } + + function setBuy(bool open) external onlyOwner { + _BUYING_CLOSE_ = !open; + } + + function setSell(bool open) external onlyOwner { + _SELLING_CLOSE_ = !open; + } } diff --git a/contracts/DODOVendorMachine/impl/DVMTrader.sol b/contracts/DODOVendorMachine/impl/DVMTrader.sol index 52d0286..086d5eb 100644 --- a/contracts/DODOVendorMachine/impl/DVMTrader.sol +++ b/contracts/DODOVendorMachine/impl/DVMTrader.sol @@ -17,7 +17,7 @@ import {IExternalCall} from "../intf/IExternalCall.sol"; contract DVMTrader is DVMStorage { using SafeMath for uint256; - function sellBase(address to) external returns (uint256 receiveQuoteAmount) { + function sellBase(address to) external isSellAllow(to) returns (uint256 receiveQuoteAmount) { uint256 baseInput = _VAULT_.getBaseInput(); uint256 mtFee; (receiveQuoteAmount, mtFee) = querySellBase(to, baseInput); @@ -29,7 +29,7 @@ contract DVMTrader is DVMStorage { return receiveQuoteAmount; } - function sellQuote(address to) external returns (uint256 receiveBaseAmount) { + function sellQuote(address to) external isBuyAllow(to) returns (uint256 receiveBaseAmount) { uint256 quoteInput = _VAULT_.getQuoteInput(); uint256 mtFee; (receiveBaseAmount, mtFee) = querySellQuote(to, quoteInput); @@ -48,23 +48,37 @@ contract DVMTrader is DVMStorage { address call, bytes calldata data ) external { - (uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve(); - uint256 B0 = calculateBase0(baseReserve, quoteReserve); - - uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(assetTo, quoteAmount); - uint256 baseMtFee = DecimalMath.mulCeil(baseAmount, mtFeeRate); - uint256 quoteMtFee = DecimalMath.mulCeil(quoteAmount, mtFeeRate); - - _VAULT_.transferBaseOut(_MAINTAINER_, baseMtFee); - _VAULT_.transferQuoteOut(_MAINTAINER_, quoteMtFee); _VAULT_.transferBaseOut(assetTo, baseAmount); _VAULT_.transferQuoteOut(assetTo, quoteAmount); - IExternalCall(call).DVMCall(data); + (uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve(); (uint256 baseBalance, uint256 quoteBalance) = _VAULT_.getVaultBalance(); - uint256 newB0 = calculateBase0(baseBalance, quoteBalance); - require(newB0 >= B0, "FLASH_LOAN_FAILED"); + + uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(assetTo); + uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(assetTo); + if (baseBalance < baseReserve) { + uint256 validBaseOut = DecimalMath.divCeil( + baseReserve - baseBalance, + DecimalMath.ONE.sub(mtFeeRate).sub(lpFeeRate) + ); + baseBalance = baseReserve.sub(validBaseOut); + _VAULT_.transferBaseOut(_MAINTAINER_, DecimalMath.mulCeil(validBaseOut, mtFeeRate)); + } + if (quoteBalance < quoteReserve) { + uint256 validQuoteOut = DecimalMath.divCeil( + quoteReserve - quoteBalance, + DecimalMath.ONE.sub(mtFeeRate).sub(lpFeeRate) + ); + quoteBalance = quoteReserve.sub(validQuoteOut); + _VAULT_.transferQuoteOut(_MAINTAINER_, DecimalMath.mulCeil(validQuoteOut, mtFeeRate)); + } + + require( + calculateBase0(baseBalance, quoteBalance) >= calculateBase0(baseReserve, quoteReserve), + "FLASH_LOAN_FAILED" + ); + _VAULT_.sync(); } @@ -80,8 +94,8 @@ contract DVMTrader is DVMStorage { require(B0 >= B1, "DODO_BASE_BALANCE_NOT_ENOUGH"); uint256 Q = DODOMath._GeneralIntegrate(B0, B1, baseReserve, _I_, _K_); - uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(trader, Q); - uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(trader, Q); + uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(trader); + uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(trader); mtFee = DecimalMath.mulCeil(Q, mtFeeRate); receiveQuoteAmount = Q.sub(mtFee).sub(DecimalMath.mulCeil(Q, lpFeeRate)); @@ -105,8 +119,8 @@ contract DVMTrader is DVMStorage { _K_ ); uint256 deltaBase = baseReserve.sub(newBaseReserve); - uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(trader, payQuoteAmount); - uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(trader, payQuoteAmount); + uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(trader); + uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(trader); mtFee = DecimalMath.mulCeil(deltaBase, mtFeeRate); receiveBaseAmount = deltaBase.sub(mtFee).sub(DecimalMath.mulCeil(deltaBase, lpFeeRate)); return (receiveBaseAmount, mtFee); diff --git a/contracts/DODOVendorMachine/impl/DVMVault.sol b/contracts/DODOVendorMachine/impl/DVMVault.sol index f68315d..cc256c8 100644 --- a/contracts/DODOVendorMachine/impl/DVMVault.sol +++ b/contracts/DODOVendorMachine/impl/DVMVault.sol @@ -110,11 +110,15 @@ contract DVMVault is InitializableOwnable { } function transferBaseOut(address to, uint256 amount) public onlyOwner { - IERC20(_BASE_TOKEN_).safeTransfer(to, amount); + if (amount > 0) { + IERC20(_BASE_TOKEN_).safeTransfer(to, amount); + } } function transferQuoteOut(address to, uint256 amount) public onlyOwner { - IERC20(_QUOTE_TOKEN_).safeTransfer(to, amount); + if (amount > 0) { + IERC20(_QUOTE_TOKEN_).safeTransfer(to, amount); + } } // Shares related diff --git a/contracts/DODOVendorMachine/intf/IDVM.sol b/contracts/DODOVendorMachine/intf/IDVM.sol index 8569973..854a6dd 100644 --- a/contracts/DODOVendorMachine/intf/IDVM.sol +++ b/contracts/DODOVendorMachine/intf/IDVM.sol @@ -16,7 +16,6 @@ interface IDVM { address lpFeeRateModel, address mtFeeRateModel, address tradePermissionManager, - address fundingPermissionManager, uint256 i, uint256 k ) external; diff --git a/contracts/Factory/DVMFactory.sol b/contracts/Factory/DVMFactory.sol index f67369f..1dd6414 100644 --- a/contracts/Factory/DVMFactory.sol +++ b/contracts/Factory/DVMFactory.sol @@ -59,7 +59,6 @@ contract DVMFactory is Ownable { createConstFeeRateModel(msg.sender, lpFeeRate), createConstFeeRateModel(msg.sender, mtFeeRate), createPermissionManager(msg.sender), - createPermissionManager(msg.sender), i, k ); diff --git a/contracts/intf/IFeeRateModel.sol b/contracts/intf/IFeeRateModel.sol index 10e7a30..076c316 100644 --- a/contracts/intf/IFeeRateModel.sol +++ b/contracts/intf/IFeeRateModel.sol @@ -9,5 +9,5 @@ pragma solidity 0.6.9; pragma experimental ABIEncoderV2; interface IFeeRateModel { - function getFeeRate(address trader, uint256 amount) external view returns (uint256); + function getFeeRate(address trader) external view returns (uint256); } diff --git a/contracts/lib/ConstFeeRateModel.sol b/contracts/lib/ConstFeeRateModel.sol index 4cf695c..36d36ca 100644 --- a/contracts/lib/ConstFeeRateModel.sol +++ b/contracts/lib/ConstFeeRateModel.sol @@ -12,12 +12,10 @@ import {IFeeRateModel} from "../intf/IFeeRateModel.sol"; import {Ownable} from "../lib/Ownable.sol"; import {InitializableOwnable} from "../lib/InitializableOwnable.sol"; -interface IConstFeeRateModel { +interface IConstFeeRateModel is IFeeRateModel { function init(address owner, uint256 feeRate) external; function setFeeRate(uint256 newFeeRate) external; - - function getFeeRate(address, uint256) external view returns (uint256); } contract ConstFeeRateModel is InitializableOwnable, IFeeRateModel { @@ -32,7 +30,7 @@ contract ConstFeeRateModel is InitializableOwnable, IFeeRateModel { _FEE_RATE_ = newFeeRate; } - function getFeeRate(address, uint256) external override view returns (uint256) { + function getFeeRate(address) external override view returns (uint256) { return _FEE_RATE_; } } From 14b024c3708556afcaf827e6178979c2e902581a Mon Sep 17 00:00:00 2001 From: mingda Date: Fri, 6 Nov 2020 01:20:07 +0800 Subject: [PATCH 103/118] query buy --- .../DODOVendorMachine/impl/DVMTrader.sol | 47 ++++++++++++++++++- contracts/lib/DODOMath.sol | 4 +- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/contracts/DODOVendorMachine/impl/DVMTrader.sol b/contracts/DODOVendorMachine/impl/DVMTrader.sol index 086d5eb..7cc064e 100644 --- a/contracts/DODOVendorMachine/impl/DVMTrader.sol +++ b/contracts/DODOVendorMachine/impl/DVMTrader.sol @@ -102,6 +102,26 @@ contract DVMTrader is DVMStorage { return (receiveQuoteAmount, mtFee); } + // 这是一个仅供查询的合约,所有交易都是基于先给input,再输出output的 + // 所以想要买10ETH,这个函数可以给你一个大概的成本,你用这个成本输入,最后能否得到10ETH是要看情况的 + function queryBuyBase(address trader, uint256 receiveBaseAmount) + public + view + returns (uint256 payQuoteAmount) + { + uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(trader); + uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(trader); + uint256 validReceiveBaseAmount = DecimalMath.divCeil( + receiveBaseAmount, + DecimalMath.ONE.sub(mtFeeRate).sub(lpFeeRate) + ); + (uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve(); + uint256 B0 = calculateBase0(baseReserve, quoteReserve); + uint256 B2 = baseReserve.sub(validReceiveBaseAmount); + payQuoteAmount = DODOMath._GeneralIntegrate(B0, baseReserve, B2, _I_, _K_); + return payQuoteAmount; + } + function querySellQuote(address trader, uint256 payQuoteAmount) public view @@ -111,14 +131,13 @@ contract DVMTrader is DVMStorage { uint256 B0 = calculateBase0(baseReserve, quoteReserve); uint256 fairAmount = DecimalMath.divFloor(payQuoteAmount, _I_); - uint256 newBaseReserve = DODOMath._SolveQuadraticFunctionForTrade( + uint256 deltaBase = DODOMath._SolveQuadraticFunctionForTrade( B0, baseReserve, fairAmount, false, _K_ ); - uint256 deltaBase = baseReserve.sub(newBaseReserve); uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(trader); uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(trader); mtFee = DecimalMath.mulCeil(deltaBase, mtFeeRate); @@ -126,6 +145,30 @@ contract DVMTrader is DVMStorage { return (receiveBaseAmount, mtFee); } + function queryBuyQuote(address trader, uint256 receiveQuoteAmount) + public + view + returns (uint256 payBaseAmount) + { + uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(trader); + uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(trader); + uint256 validReceiveQuoteAmount = DecimalMath.divCeil( + receiveQuoteAmount, + DecimalMath.ONE.sub(mtFeeRate).sub(lpFeeRate) + ); + (uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve(); + uint256 B0 = calculateBase0(baseReserve, quoteReserve); + uint256 fairAmount = DecimalMath.divFloor(validReceiveQuoteAmount, _I_); + payBaseAmount = DODOMath._SolveQuadraticFunctionForTrade( + B0, + baseReserve, + fairAmount, + true, + _K_ + ); + return payBaseAmount; + } + function getMidPrice() public view returns (uint256 midPrice) { (uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve(); uint256 B0 = calculateBase0(baseReserve, quoteReserve); diff --git a/contracts/lib/DODOMath.sol b/contracts/lib/DODOMath.sol index 606f344..783b806 100644 --- a/contracts/lib/DODOMath.sol +++ b/contracts/lib/DODOMath.sol @@ -96,9 +96,9 @@ library DODOMath { } if (deltaBSig) { - return DecimalMath.divFloor(numerator, denominator); + return DecimalMath.divFloor(numerator, denominator).sub(Q1); } else { - return DecimalMath.divCeil(numerator, denominator); + return Q1.sub(DecimalMath.divCeil(numerator, denominator)); } } From ad7ed919d0e187eef89cf1c2cad8fe1a3a50bda1 Mon Sep 17 00:00:00 2001 From: mingda Date: Fri, 6 Nov 2020 16:03:18 +0800 Subject: [PATCH 104/118] set external call interface --- .../DODOVendorMachine/impl/DVMFunding.sol | 22 ++++--- .../DODOVendorMachine/impl/DVMTrader.sol | 63 +++++++++++-------- .../DODOVendorMachine/intf/IExternalCall.sol | 13 ---- contracts/intf/IDODOCallee.sol | 26 ++++++++ contracts/lib/DODOMath.sol | 1 + contracts/lib/PermissionManager.sol | 16 ++--- test/DVM/trader.test.ts | 3 + 7 files changed, 90 insertions(+), 54 deletions(-) delete mode 100644 contracts/DODOVendorMachine/intf/IExternalCall.sol create mode 100644 contracts/intf/IDODOCallee.sol diff --git a/contracts/DODOVendorMachine/impl/DVMFunding.sol b/contracts/DODOVendorMachine/impl/DVMFunding.sol index 346cc72..9e715c2 100644 --- a/contracts/DODOVendorMachine/impl/DVMFunding.sol +++ b/contracts/DODOVendorMachine/impl/DVMFunding.sol @@ -10,9 +10,10 @@ pragma experimental ABIEncoderV2; import {DVMStorage} from "./DVMStorage.sol"; import {DecimalMath} from "../../lib/DecimalMath.sol"; +import {IDODOCallee} from "../../intf/IDODOCallee.sol"; contract DVMFunding is DVMStorage { - function buyShares(address to) external returns (uint256) { + function buyShares(address to) external preventReentrant returns (uint256) { uint256 baseInput = _VAULT_.getBaseInput(); uint256 quoteInput = _VAULT_.getQuoteInput(); require(baseInput > 0, "NO_BASE_INPUT"); @@ -46,17 +47,24 @@ contract DVMFunding is DVMStorage { _VAULT_.sync(); } - function sellShares(address to, uint256 amount) external returns (uint256) { - require(_VAULT_.balanceOf(msg.sender) >= amount, "SHARES_NOT_ENOUGH"); + function sellShares( + address to, + uint256 shareAmount, + bytes calldata data + ) external preventReentrant returns (uint256) { + require(_VAULT_.balanceOf(msg.sender) >= shareAmount, "SHARES_NOT_ENOUGH"); (uint256 baseBalance, uint256 quoteBalance) = _VAULT_.getVaultBalance(); uint256 totalShares = _VAULT_.totalSupply(); - _VAULT_.burn(msg.sender, amount); - _VAULT_.transferBaseOut(to, baseBalance.mul(amount).div(totalShares)); - _VAULT_.transferQuoteOut(to, quoteBalance.mul(amount).div(totalShares)); + _VAULT_.burn(msg.sender, shareAmount); + uint256 baseAmount = baseBalance.mul(shareAmount).div(totalShares); + uint256 quoteAmount = quoteBalance.mul(shareAmount).div(totalShares); + _VAULT_.transferBaseOut(to, baseAmount); + _VAULT_.transferQuoteOut(to, quoteAmount); _VAULT_.sync(); + if (data.length > 0) IDODOCallee(to, shareAmount, baseAmount, quoteAmount, data); } - function retrieve(address to) external { + function retrieve(address to) external preventReentrant { (uint256 baseBalance, uint256 quoteBalance) = _VAULT_.getVaultBalance(); (uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve(); if (baseBalance.sub(baseReserve) > 0) { diff --git a/contracts/DODOVendorMachine/impl/DVMTrader.sol b/contracts/DODOVendorMachine/impl/DVMTrader.sol index 7cc064e..657581f 100644 --- a/contracts/DODOVendorMachine/impl/DVMTrader.sol +++ b/contracts/DODOVendorMachine/impl/DVMTrader.sol @@ -12,12 +12,17 @@ import {DVMStorage} from "./DVMStorage.sol"; import {SafeMath} from "../../lib/SafeMath.sol"; import {DecimalMath} from "../../lib/DecimalMath.sol"; import {DODOMath} from "../../lib/DODOMath.sol"; -import {IExternalCall} from "../intf/IExternalCall.sol"; +import {IDODOCallee} from "../../intf/IDODOCallee.sol"; contract DVMTrader is DVMStorage { using SafeMath for uint256; - function sellBase(address to) external isSellAllow(to) returns (uint256 receiveQuoteAmount) { + function sellBase(address to) + external + preventReentrant + isSellAllow(to) + returns (uint256 receiveQuoteAmount) + { uint256 baseInput = _VAULT_.getBaseInput(); uint256 mtFee; (receiveQuoteAmount, mtFee) = querySellBase(to, baseInput); @@ -29,7 +34,12 @@ contract DVMTrader is DVMStorage { return receiveQuoteAmount; } - function sellQuote(address to) external isBuyAllow(to) returns (uint256 receiveBaseAmount) { + function sellQuote(address to) + external + preventReentrant + isBuyAllow(to) + returns (uint256 receiveBaseAmount) + { uint256 quoteInput = _VAULT_.getQuoteInput(); uint256 mtFee; (receiveBaseAmount, mtFee) = querySellQuote(to, quoteInput); @@ -45,12 +55,13 @@ contract DVMTrader is DVMStorage { uint256 baseAmount, uint256 quoteAmount, address assetTo, - address call, bytes calldata data - ) external { + ) external preventReentrant { _VAULT_.transferBaseOut(assetTo, baseAmount); _VAULT_.transferQuoteOut(assetTo, quoteAmount); - IExternalCall(call).DVMCall(data); + + if (data.length > 0) + IDODOCallee(assetTo).DVMFlashLoanCall(msg.sender, baseAmount, quoteAmount, data); (uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve(); (uint256 baseBalance, uint256 quoteBalance) = _VAULT_.getVaultBalance(); @@ -102,26 +113,6 @@ contract DVMTrader is DVMStorage { return (receiveQuoteAmount, mtFee); } - // 这是一个仅供查询的合约,所有交易都是基于先给input,再输出output的 - // 所以想要买10ETH,这个函数可以给你一个大概的成本,你用这个成本输入,最后能否得到10ETH是要看情况的 - function queryBuyBase(address trader, uint256 receiveBaseAmount) - public - view - returns (uint256 payQuoteAmount) - { - uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(trader); - uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(trader); - uint256 validReceiveBaseAmount = DecimalMath.divCeil( - receiveBaseAmount, - DecimalMath.ONE.sub(mtFeeRate).sub(lpFeeRate) - ); - (uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve(); - uint256 B0 = calculateBase0(baseReserve, quoteReserve); - uint256 B2 = baseReserve.sub(validReceiveBaseAmount); - payQuoteAmount = DODOMath._GeneralIntegrate(B0, baseReserve, B2, _I_, _K_); - return payQuoteAmount; - } - function querySellQuote(address trader, uint256 payQuoteAmount) public view @@ -145,6 +136,26 @@ contract DVMTrader is DVMStorage { return (receiveBaseAmount, mtFee); } + // 这是一个仅供查询的合约,所有交易都是基于先给input,再输出output的 + // 所以想要买10ETH,这个函数可以给你一个大概的成本,你用这个成本输入,最后能否得到10ETH是要看情况的 + function queryBuyBase(address trader, uint256 receiveBaseAmount) + public + view + returns (uint256 payQuoteAmount) + { + uint256 mtFeeRate = _MT_FEE_RATE_MODEL_.getFeeRate(trader); + uint256 lpFeeRate = _LP_FEE_RATE_MODEL_.getFeeRate(trader); + uint256 validReceiveBaseAmount = DecimalMath.divCeil( + receiveBaseAmount, + DecimalMath.ONE.sub(mtFeeRate).sub(lpFeeRate) + ); + (uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve(); + uint256 B0 = calculateBase0(baseReserve, quoteReserve); + uint256 B2 = baseReserve.sub(validReceiveBaseAmount); + payQuoteAmount = DODOMath._GeneralIntegrate(B0, baseReserve, B2, _I_, _K_); + return payQuoteAmount; + } + function queryBuyQuote(address trader, uint256 receiveQuoteAmount) public view diff --git a/contracts/DODOVendorMachine/intf/IExternalCall.sol b/contracts/DODOVendorMachine/intf/IExternalCall.sol deleted file mode 100644 index fbd517e..0000000 --- a/contracts/DODOVendorMachine/intf/IExternalCall.sol +++ /dev/null @@ -1,13 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ - -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - -interface IExternalCall { - function DVMCall(bytes calldata data) external; -} diff --git a/contracts/intf/IDODOCallee.sol b/contracts/intf/IDODOCallee.sol new file mode 100644 index 0000000..5bde65f --- /dev/null +++ b/contracts/intf/IDODOCallee.sol @@ -0,0 +1,26 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +interface IDODOCallee { + function DVMSellShareCall( + address sender, + uint256 burnShareAmount, + uint256 baseAmount, + uint256 quoteAmount, + bytes calldata data + ) external; + + function DVMFlashLoanCall( + address sender, + uint256 baseAmount, + uint256 quoteAmount, + bytes calldata data + ) external; +} diff --git a/contracts/lib/DODOMath.sol b/contracts/lib/DODOMath.sol index 783b806..6a726ae 100644 --- a/contracts/lib/DODOMath.sol +++ b/contracts/lib/DODOMath.sol @@ -53,6 +53,7 @@ library DODOMath { note: another root is negative, abondan if deltaBSig=true, then Q2>Q1 if deltaBSig=false, then Q2 bool) internal _whitelist_; mapping(address => bool) internal _blacklist_; function isAllowed(address account) external view returns (bool) { - if (_BLACKLIST_MODE_ON_) { - return !_blacklist_[account]; - } else { + if (_WHITELIST_MODE_ON_) { return _whitelist_[account]; + } else { + return !_blacklist_[account]; } } - function openBlacklist() external onlyOwner { - _BLACKLIST_MODE_ON_ = true; + function openBlacklistMode() external onlyOwner { + _WHITELIST_MODE_ON_ = false; } - function openWhitelist() external onlyOwner { - _BLACKLIST_MODE_ON_ = true; + function openWhitelistMode() external onlyOwner { + _WHITELIST_MODE_ON_ = true; } function addToWhitelist(address account) external onlyOwner { diff --git a/test/DVM/trader.test.ts b/test/DVM/trader.test.ts index e63d7e9..1b1b5f3 100644 --- a/test/DVM/trader.test.ts +++ b/test/DVM/trader.test.ts @@ -51,6 +51,9 @@ describe("Trader", () => { }); describe("trade", () => { + // it.only("gas cost", async () => { + // await logGas(ctx.DVM.methods.calculateBase0(decimalStr("200"), decimalStr("1")), ctx.sendParam(trader), "calculate base0") + // }) it("buy & sell", async () => { console.log("BASE0 before buy", await ctx.DVM.methods.getBase0().call()) From 1a0d3990fc1c4ca60d0451fb978285b19b64d3e7 Mon Sep 17 00:00:00 2001 From: mingda Date: Fri, 6 Nov 2020 19:33:12 +0800 Subject: [PATCH 105/118] check query buy --- contracts/DODOVendorMachine/impl/DVMTrader.sol | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contracts/DODOVendorMachine/impl/DVMTrader.sol b/contracts/DODOVendorMachine/impl/DVMTrader.sol index 657581f..6981e1e 100644 --- a/contracts/DODOVendorMachine/impl/DVMTrader.sol +++ b/contracts/DODOVendorMachine/impl/DVMTrader.sol @@ -150,6 +150,8 @@ contract DVMTrader is DVMStorage { DecimalMath.ONE.sub(mtFeeRate).sub(lpFeeRate) ); (uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve(); + require(baseReserve > validReceiveBaseAmount, "DODO_BASE_BALANCE_NOT_ENOUGH"); + uint256 B0 = calculateBase0(baseReserve, quoteReserve); uint256 B2 = baseReserve.sub(validReceiveBaseAmount); payQuoteAmount = DODOMath._GeneralIntegrate(B0, baseReserve, B2, _I_, _K_); @@ -168,6 +170,8 @@ contract DVMTrader is DVMStorage { DecimalMath.ONE.sub(mtFeeRate).sub(lpFeeRate) ); (uint256 baseReserve, uint256 quoteReserve) = _VAULT_.getVaultReserve(); + require(quoteReserve > validReceiveQuoteAmount, "DODO_QUOTE_BALANCE_NOT_ENOUGH"); + uint256 B0 = calculateBase0(baseReserve, quoteReserve); uint256 fairAmount = DecimalMath.divFloor(validReceiveQuoteAmount, _I_); payBaseAmount = DODOMath._SolveQuadraticFunctionForTrade( From d965ce140972abda611a519edfe7e3fe7ff6915e Mon Sep 17 00:00:00 2001 From: owen05 Date: Mon, 9 Nov 2020 14:26:38 +0800 Subject: [PATCH 106/118] add route test framework --- .gitignore | 6 + contracts/SmartRoute/SmartApprove.sol | 36 + contracts/SmartRoute/SmartSwap.sol | 118 + contracts/intf/ISmartApprove.sol | 15 + contracts/lib/ExternalCall.sol | 34 + contracts/lib/UniversalERC20.sol | 75 + package-lock.json | 6520 +++++++++-------------- test/Route/Route.test.ts | 171 + test/utils-v1/Context.ts | 195 + test/utils-v1/Contracts.ts | 118 + test/utils-v1/Converter.ts | 15 + test/utils-v1/EVM.ts | 92 + test/utils-v1/Log.ts | 30 + tsconfig.json | 2 +- yarn.lock | 6820 ------------------------- 15 files changed, 3342 insertions(+), 10905 deletions(-) create mode 100644 contracts/SmartRoute/SmartApprove.sol create mode 100644 contracts/SmartRoute/SmartSwap.sol create mode 100644 contracts/intf/ISmartApprove.sol create mode 100644 contracts/lib/ExternalCall.sol create mode 100644 contracts/lib/UniversalERC20.sol create mode 100644 test/Route/Route.test.ts create mode 100644 test/utils-v1/Context.ts create mode 100644 test/utils-v1/Contracts.ts create mode 100644 test/utils-v1/Converter.ts create mode 100644 test/utils-v1/EVM.ts create mode 100644 test/utils-v1/Log.ts delete mode 100644 yarn.lock diff --git a/.gitignore b/.gitignore index 06def01..7f476ea 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,9 @@ flattered/ *.swo *.swp + +node_modules + +#Hardhat files +cache +artifacts diff --git a/contracts/SmartRoute/SmartApprove.sol b/contracts/SmartRoute/SmartApprove.sol new file mode 100644 index 0000000..3b6ccd3 --- /dev/null +++ b/contracts/SmartRoute/SmartApprove.sol @@ -0,0 +1,36 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; + +import {IERC20} from "../intf/IERC20.sol"; +import {SafeERC20} from "../lib/SafeERC20.sol"; +import {Ownable} from "../lib/Ownable.sol"; + + +contract SmartApprove is Ownable { + using SafeERC20 for IERC20; + address public smartSwap; + + function setSmartSwap(address _smartSwap) external onlyOwner { + smartSwap = _smartSwap; + } + + + event Test1(uint256 amount); + + function claimTokens( + IERC20 token, + address who, + address dest, + uint256 amount + ) external { + require(msg.sender == smartSwap, "Not SmartSwap Address, Access restricted"); + emit Test1(amount); + // token.safeTransferFrom(who, dest, amount); + } +} diff --git a/contracts/SmartRoute/SmartSwap.sol b/contracts/SmartRoute/SmartSwap.sol new file mode 100644 index 0000000..0856450 --- /dev/null +++ b/contracts/SmartRoute/SmartSwap.sol @@ -0,0 +1,118 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; + +import {Ownable} from "../lib/Ownable.sol"; +import {ExternalCall} from "../lib/ExternalCall.sol"; +import {IERC20} from "../intf/IERC20.sol"; +import {UniversalERC20} from "../lib/UniversalERC20.sol"; +import {SafeMath} from "../lib/SafeMath.sol"; +import {DecimalMath} from "../lib/DecimalMath.sol"; +import {ISmartApprove} from "../intf/ISmartApprove.sol"; + + +contract SmartSwap is Ownable { + using SafeMath for uint256; + using UniversalERC20 for IERC20; + using ExternalCall for address; + + ISmartApprove public smartApprove; + + IERC20 constant ETH_ADDRESS = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); + + event Swapped( + IERC20 indexed fromToken, + IERC20 indexed toToken, + address indexed sender, + uint256 fromAmount, + uint256 toAmount + ); + + event ExternalRecord(address indexed to, address indexed sender); + + constructor(address _smartApprove) public { + smartApprove = ISmartApprove(_smartApprove); + } + + + function dodoSwap( + IERC20 fromToken, + IERC20 toToken, + uint256 fromTokenAmount, + uint256 minReturnAmount, + address[] memory callPairs, + bytes memory callDataConcat, + uint256[] memory starts, + uint256[] memory gasLimitsAndValues + ) public payable returns (uint256 returnAmount) { + require(minReturnAmount > 0, "haha hihi Min return should be bigger then 0."); + require(callPairs.length > 0, "pairs should exists."); + + // if (fromToken != ETH_ADDRESS) { + // // smartApprove.claimTokens(fromToken, msg.sender, address(this), fromTokenAmount); + // } + + // for (uint256 i = 0; i < callPairs.length; i++) { + // require(callPairs[i] != address(smartApprove), "Access denied"); + // require( + // callPairs[i].externalCall( + // gasLimitsAndValues[i] & ((1 << 128) - 1), + // callDataConcat, + // starts[i], + // starts[i + 1] - starts[i], + // gasLimitsAndValues[i] >> 128 + // ) + // ); + // } + + // // Return back all unswapped + // fromToken.universalTransfer(msg.sender, fromToken.universalBalanceOf(address(this))); + + // returnAmount = toToken.universalBalanceOf(address(this)); + + // require(returnAmount >= minReturnAmount, "Return amount is not enough"); + // toToken.universalTransfer(msg.sender, returnAmount); + emit Swapped(fromToken, toToken, msg.sender, fromTokenAmount, fromTokenAmount); + // emit Swapped(fromToken, toToken, msg.sender, fromTokenAmount, returnAmount); + } + + function externalSwap( + IERC20 fromToken, + IERC20 toToken, + address approveTarget, + address to, + uint256 gasSwap, + uint256 fromTokenAmount, + uint256 minReturnAmount, + bytes memory callDataConcat + ) public payable returns (uint256 returnAmount) { + + require(minReturnAmount > 0, "Min return should be bigger then 0."); + + if (fromToken != ETH_ADDRESS) { + smartApprove.claimTokens(fromToken, msg.sender, address(this), fromTokenAmount); + fromToken.approve(approveTarget, fromTokenAmount); + } + + (bool success, ) = to.call{value: msg.value, gas: gasSwap}(callDataConcat); + + require(success, "Contract Swap execution Failed"); + + // Return back all unswapped + fromToken.universalTransfer(msg.sender, fromToken.universalBalanceOf(address(this))); + + returnAmount = toToken.universalBalanceOf(address(this)); + + require(returnAmount >= minReturnAmount, "Return amount is not enough"); + toToken.universalTransfer(msg.sender, returnAmount); + + emit Swapped(fromToken, toToken, msg.sender, fromTokenAmount, returnAmount); + + emit ExternalRecord(to, msg.sender); + } +} diff --git a/contracts/intf/ISmartApprove.sol b/contracts/intf/ISmartApprove.sol new file mode 100644 index 0000000..6ee509f --- /dev/null +++ b/contracts/intf/ISmartApprove.sol @@ -0,0 +1,15 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {IERC20} from "./IERC20.sol"; + +interface ISmartApprove { + function claimTokens(IERC20 token,address who,address dest,uint256 amount) external; +} \ No newline at end of file diff --git a/contracts/lib/ExternalCall.sol b/contracts/lib/ExternalCall.sol new file mode 100644 index 0000000..ce8d0b9 --- /dev/null +++ b/contracts/lib/ExternalCall.sol @@ -0,0 +1,34 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +library ExternalCall { + // Source: https://github.com/gnosis/MultiSigWallet/blob/master/contracts/MultiSigWallet.sol + // call has been separated into its own function in order to take advantage + // of the Solidity's code generator to produce a loop that copies tx.data into memory. + function externalCall(address destination, uint value, bytes memory data, uint dataOffset, uint dataLength, uint gasLimit) internal returns(bool result) { + // solium-disable-next-line security/no-inline-assembly + if (gasLimit == 0) { + gasLimit = gasleft() - 40000; + } + assembly { + let x := mload(0x40) // "Allocate" memory for output (0x40 is where "free memory" pointer is stored by convention) + let d := add(data, 32) // First 32 bytes are the padded length of data, so exclude that + result := call( + gasLimit, + destination, + value, + add(d, dataOffset), + dataLength, // Size of the input (in bytes) - this is what fixes the padding problem + x, + 0 // Output is ignored, therefore the output size is zero + ) + } + } +} diff --git a/contracts/lib/UniversalERC20.sol b/contracts/lib/UniversalERC20.sol new file mode 100644 index 0000000..7005a5b --- /dev/null +++ b/contracts/lib/UniversalERC20.sol @@ -0,0 +1,75 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; + +import {SafeMath} from "./SafeMath.sol"; +import {IERC20} from "../intf/IERC20.sol"; +import {SafeERC20} from "./SafeERC20.sol"; + +library UniversalERC20 { + + using SafeMath for uint256; + using SafeERC20 for IERC20; + + IERC20 private constant ZERO_ADDRESS = IERC20(0x0000000000000000000000000000000000000000); + IERC20 private constant ETH_ADDRESS = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); + + function universalTransfer(IERC20 token, address to, uint256 amount) internal { + universalTransfer(token, to, amount, false); + } + + function universalTransfer(IERC20 token, address to, uint256 amount, bool mayFail) internal returns(bool) { + if (amount == 0) { + return true; + } + + if (token == ZERO_ADDRESS || token == ETH_ADDRESS) { + if (mayFail) { + return address(uint160(to)).send(amount); + } else { + address(uint160(to)).transfer(amount); + return true; + } + } else { + token.safeTransfer(to, amount); + return true; + } + } + + function universalApprove(IERC20 token, address to, uint256 amount) internal { + if (token != ZERO_ADDRESS && token != ETH_ADDRESS) { + token.safeApprove(to, amount); + } + } + + function universalTransferFrom(IERC20 token, address from, address to, uint256 amount) internal { + if (amount == 0) { + return; + } + + if (token == ZERO_ADDRESS || token == ETH_ADDRESS) { + require(from == msg.sender && msg.value >= amount, "msg.value is zero"); + if (to != address(this)) { + address(uint160(to)).transfer(amount); + } + if (msg.value > amount) { + msg.sender.transfer(msg.value.sub(amount)); + } + } else { + token.safeTransferFrom(from, to, amount); + } + } + + function universalBalanceOf(IERC20 token, address who) internal view returns (uint256) { + if (token == ZERO_ADDRESS || token == ETH_ADDRESS) { + return who.balance; + } else { + return token.balanceOf(who); + } + } +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index bc64a18..e1bfe80 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,21 +5,20 @@ "requires": true, "dependencies": { "@babel/code-frame": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.1.tgz", - "integrity": "sha512-IGhtTmpjGbYzcEDOw7DcQtbQSXcG9ftmAXtWTu9V936vDye4xjjekktFAtgZsWpzTj/X01jocB46mTywm/4SZw==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", "requires": { - "@babel/highlight": "^7.10.1" + "@babel/highlight": "^7.10.4" } }, "@babel/generator": { - "version": "7.10.2", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.10.2.tgz", - "integrity": "sha512-AxfBNHNu99DTMvlUPlt1h2+Hn7knPpH5ayJ8OqDWSeLld+Fi2AYBTC/IejWDM9Edcii4UzZRCsbUt0WlSDsDsA==", + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.5.tgz", + "integrity": "sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A==", "requires": { - "@babel/types": "^7.10.2", + "@babel/types": "^7.12.5", "jsesc": "^2.5.1", - "lodash": "^4.17.13", "source-map": "^0.5.0" }, "dependencies": { @@ -27,70 +26,34 @@ "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" } } }, "@babel/helper-function-name": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.1.tgz", - "integrity": "sha512-fcpumwhs3YyZ/ttd5Rz0xn0TpIwVkN7X0V38B9TWNfVF42KEkhkAAuPCQ3oXmtTRtiPJrmZ0TrfS0GKF0eMaRQ==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", + "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", "requires": { - "@babel/helper-get-function-arity": "^7.10.1", - "@babel/template": "^7.10.1", - "@babel/types": "^7.10.1" + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" } }, "@babel/helper-get-function-arity": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.1.tgz", - "integrity": "sha512-F5qdXkYGOQUb0hpRaPoetF9AnsXknKjWMZ+wmsIRsp5ge5sFh4c3h1eH2pRTTuy9KKAA2+TTYomGXAtEL2fQEw==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", + "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", "requires": { - "@babel/types": "^7.10.1" + "@babel/types": "^7.10.4" } }, "@babel/helper-module-imports": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz", - "integrity": "sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw==", + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz", + "integrity": "sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA==", "dev": true, "requires": { - "@babel/types": "^7.10.4" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", - "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", - "dev": true - }, - "@babel/types": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.0.tgz", - "integrity": "sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - } + "@babel/types": "^7.12.5" } }, "@babel/helper-plugin-utils": { @@ -100,73 +63,82 @@ "dev": true }, "@babel/helper-split-export-declaration": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.1.tgz", - "integrity": "sha512-UQ1LVBPrYdbchNhLwj6fetj46BcFwfS4NllJo/1aJsT+1dLTEnXJL0qHqtY7gPzF8S2fXBJamf1biAXV3X077g==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz", + "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==", "requires": { - "@babel/types": "^7.10.1" + "@babel/types": "^7.11.0" } }, "@babel/helper-validator-identifier": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.1.tgz", - "integrity": "sha512-5vW/JXLALhczRCWP0PnFDMCJAchlBvM7f4uk/jXritBnIa6E1KmqmtrS3yn1LAnxFBypQ3eneLuXjsnfQsgILw==" + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==" }, "@babel/highlight": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.1.tgz", - "integrity": "sha512-8rMof+gVP8mxYZApLF/JgNDAkdKa+aJt3ZYxF8z6+j/hpeXL7iMsKCPHa2jNMHu/qqBwzQF4OHNoYi8dMA/rYg==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", "requires": { - "@babel/helper-validator-identifier": "^7.10.1", + "@babel/helper-validator-identifier": "^7.10.4", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } } } }, "@babel/parser": { - "version": "7.10.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.2.tgz", - "integrity": "sha512-PApSXlNMJyB4JiGVhCOlzKIif+TKFTvu0aQAhnTvfP/z3vVSN6ZypH5bfUNwFXXjRQtUEBNFd2PtmCmG2Py3qQ==" + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.5.tgz", + "integrity": "sha512-FVM6RZQ0mn2KCf1VUED7KepYeUWoVShczewOCfm3nzoBybaih51h+sYVVGthW9M6lPByEPTQf+xm27PBdlpwmQ==" }, "@babel/plugin-transform-runtime": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.11.0.tgz", - "integrity": "sha512-LFEsP+t3wkYBlis8w6/kmnd6Kb1dxTd+wGJ8MlxTGzQo//ehtqlVL4S9DNUa53+dtPSQobN2CXx4d81FqC58cw==", + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.12.1.tgz", + "integrity": "sha512-Ac/H6G9FEIkS2tXsZjL4RAdS3L3WHxci0usAnz7laPWUmFiGtj7tIASChqKZMHTSQTQY6xDbOq+V1/vIq3QrWg==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.10.4", + "@babel/helper-module-imports": "^7.12.1", "@babel/helper-plugin-utils": "^7.10.4", "resolve": "^1.8.1", "semver": "^5.5.1" - }, - "dependencies": { - "resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", - "dev": true, - "requires": { - "path-parse": "^1.0.6" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } } }, "@babel/runtime": { - "version": "7.11.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.11.2.tgz", - "integrity": "sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==", + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz", + "integrity": "sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==", "dev": true, "requires": { "regenerator-runtime": "^0.13.4" @@ -181,29 +153,29 @@ } }, "@babel/template": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.1.tgz", - "integrity": "sha512-OQDg6SqvFSsc9A0ej6SKINWrpJiNonRIniYondK2ViKhB06i3c0s+76XUft71iqBEe9S1OKsHwPAjfHnuvnCig==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", + "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", "requires": { - "@babel/code-frame": "^7.10.1", - "@babel/parser": "^7.10.1", - "@babel/types": "^7.10.1" + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4" } }, "@babel/traverse": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.10.1.tgz", - "integrity": "sha512-C/cTuXeKt85K+p08jN6vMDz8vSV0vZcI0wmQ36o6mjbuo++kPMdpOYw23W2XH04dbRt9/nMEfA4W3eR21CD+TQ==", + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.5.tgz", + "integrity": "sha512-xa15FbQnias7z9a62LwYAA5SZZPkHIXpd42C6uW68o8uTuua96FHZy1y61Va5P/i83FAAcMpW8+A/QayntzuqA==", "requires": { - "@babel/code-frame": "^7.10.1", - "@babel/generator": "^7.10.1", - "@babel/helper-function-name": "^7.10.1", - "@babel/helper-split-export-declaration": "^7.10.1", - "@babel/parser": "^7.10.1", - "@babel/types": "^7.10.1", + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.12.5", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/parser": "^7.12.5", + "@babel/types": "^7.12.5", "debug": "^4.1.0", "globals": "^11.1.0", - "lodash": "^4.17.13" + "lodash": "^4.17.19" }, "dependencies": { "globals": { @@ -214,12 +186,12 @@ } }, "@babel/types": { - "version": "7.10.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.2.tgz", - "integrity": "sha512-AD3AwWBSz0AWF0AkCN9VPiWrvldXq+/e3cHa4J89vo4ymjz1XwrBFFVZmkJTsQIPNk+ZVomPSXUJqq8yyjZsng==", + "version": "7.12.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.6.tgz", + "integrity": "sha512-hwyjw6GvjBLiyy3W0YQf0Z5Zf4NpYejUnKFcfcUhZCSffoBBp30w6wP2Wn6pk31jMYZvcOrB/1b7cGXvEoKogA==", "requires": { - "@babel/helper-validator-identifier": "^7.10.1", - "lodash": "^4.17.13", + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", "to-fast-properties": "^2.0.0" }, "dependencies": { @@ -246,16 +218,42 @@ "@ethersproject/strings": ">=5.0.0-beta.130" } }, - "@ethersproject/address": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.0.1.tgz", - "integrity": "sha512-kfQtXpBP2pI2TfoRRAYv8grHGiYw8U0c1KbMsC58/W33TIBy7gFSf/oAzOd94lNzdIUenKU0OuSzrHQfVcDDDA==", + "@ethersproject/abstract-provider": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.0.5.tgz", + "integrity": "sha512-i/CjElAkzV7vQBAeoz+IpjGfcFYEP9eD7j3fzZ0fzTq03DO7PPnR+xkEZ1IoDXGwDS+55aLM1xvLDwB/Lx6IOQ==", "requires": { - "@ethersproject/bignumber": "^5.0.0", - "@ethersproject/bytes": "^5.0.0", - "@ethersproject/keccak256": "^5.0.0", - "@ethersproject/logger": "^5.0.0", - "@ethersproject/rlp": "^5.0.0", + "@ethersproject/bignumber": "^5.0.7", + "@ethersproject/bytes": "^5.0.4", + "@ethersproject/logger": "^5.0.5", + "@ethersproject/networks": "^5.0.3", + "@ethersproject/properties": "^5.0.3", + "@ethersproject/transactions": "^5.0.5", + "@ethersproject/web": "^5.0.6" + } + }, + "@ethersproject/abstract-signer": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.0.7.tgz", + "integrity": "sha512-8W8gy/QutEL60EoMEpvxZ8MFAEWs/JvH5nmZ6xeLXoZvmBCasGmxqHdYjo2cxg0nevkPkq9SeenSsBBZSCx+SQ==", + "requires": { + "@ethersproject/abstract-provider": "^5.0.4", + "@ethersproject/bignumber": "^5.0.7", + "@ethersproject/bytes": "^5.0.4", + "@ethersproject/logger": "^5.0.5", + "@ethersproject/properties": "^5.0.3" + } + }, + "@ethersproject/address": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.0.5.tgz", + "integrity": "sha512-DpkQ6rwk9jTefrRsJzEm6nhRiJd9pvhn1xN0rw5N/jswXG5r7BLk/GVA0mMAVWAsYfvi2xSc5L41FMox43RYEA==", + "requires": { + "@ethersproject/bignumber": "^5.0.7", + "@ethersproject/bytes": "^5.0.4", + "@ethersproject/keccak256": "^5.0.3", + "@ethersproject/logger": "^5.0.5", + "@ethersproject/rlp": "^5.0.3", "bn.js": "^4.4.0" }, "dependencies": { @@ -266,14 +264,21 @@ } } }, - "@ethersproject/bignumber": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.0.1.tgz", - "integrity": "sha512-srGDO7ksT0avdDw5pBtj6F81psv5xiJMInwSSatfIKplitubFb6yVwoHGObGRd0Pp3TvrkIDfJkuskoSMj4OHQ==", + "@ethersproject/base64": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.0.4.tgz", + "integrity": "sha512-4KRykQ7BQMeOXfvio1YITwHjxwBzh92UoXIdzxDE1p53CK28bbHPdsPNYo0wl0El7lJAMpT2SOdL0hhbWRnyIA==", "requires": { - "@ethersproject/bytes": "^5.0.0", - "@ethersproject/logger": "^5.0.0", - "@ethersproject/properties": "^5.0.0", + "@ethersproject/bytes": "^5.0.4" + } + }, + "@ethersproject/bignumber": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.0.8.tgz", + "integrity": "sha512-KXFVAFKS1jdTXYN8BE5Oj+ZfPMh28iRdFeNGBVT6cUFdtiPVqeXqc0ggvBqA3A1VoFFGgM7oAeaagA393aORHA==", + "requires": { + "@ethersproject/bytes": "^5.0.4", + "@ethersproject/logger": "^5.0.5", "bn.js": "^4.4.0" }, "dependencies": { @@ -285,98 +290,129 @@ } }, "@ethersproject/bytes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.0.1.tgz", - "integrity": "sha512-Y198536UW9Jb9RBXuqmCsCa9mYJUsxJn+5aGr2XjNMpLBc6vEn/44GHnbQXYgRCzh4rnWtJ9bTgSwDjme9Hgnw==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.0.5.tgz", + "integrity": "sha512-IEj9HpZB+ACS6cZ+QQMTqmu/cnUK2fYNE6ms/PVxjoBjoxc6HCraLpam1KuRvreMy0i523PLmjN8OYeikRdcUQ==", "requires": { - "@ethersproject/logger": "^5.0.0" + "@ethersproject/logger": "^5.0.5" } }, "@ethersproject/constants": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.0.1.tgz", - "integrity": "sha512-Xec07hFCPN4wfC3WDiRay7KipkApl2msiKTrBHCuAwNMOM8M92+mlQp8tgfEL51DPwCZkmdk1f02kArc6caVSw==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.0.5.tgz", + "integrity": "sha512-foaQVmxp2+ik9FrLUCtVrLZCj4M3Ibgkqvh+Xw/vFRSerkjVSYePApaVE5essxhoSlF1U9oXfWY09QI2AXtgKA==", "requires": { - "@ethersproject/bignumber": "^5.0.0" + "@ethersproject/bignumber": "^5.0.7" } }, "@ethersproject/hash": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.0.1.tgz", - "integrity": "sha512-1ByUXYvkszrSSks07xctBtZfpFnIVmftxWlAAnguxh6Q65vKECd/EPi5uI5xVOvnrYMH9Vb8MK1SofPX/6fArQ==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.0.6.tgz", + "integrity": "sha512-Gvh57v6BWhwnud6l7tMfQm32PRQ2DYx2WaAAQmAxAfYvmzUkpQCBstnGeNMXIL8/2wdkvcB2u+WZRWaZtsFuUQ==", "requires": { - "@ethersproject/bytes": "^5.0.0", - "@ethersproject/keccak256": "^5.0.0", - "@ethersproject/logger": "^5.0.0", - "@ethersproject/strings": "^5.0.0" + "@ethersproject/abstract-signer": "^5.0.6", + "@ethersproject/address": "^5.0.5", + "@ethersproject/bignumber": "^5.0.8", + "@ethersproject/bytes": "^5.0.4", + "@ethersproject/keccak256": "^5.0.3", + "@ethersproject/logger": "^5.0.5", + "@ethersproject/properties": "^5.0.4", + "@ethersproject/strings": "^5.0.4" } }, "@ethersproject/keccak256": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.0.1.tgz", - "integrity": "sha512-AtFm/4qHRQUvZcG3WYmaT7zV79dz72+N01w0XphcIBaD/7UZXyW85Uf08sirVlckHmh9fvc4UDWyHiroKsBT6Q==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.0.4.tgz", + "integrity": "sha512-GNpiOUm9PGUxFNqOxYKDQBM0u68bG9XC9iOulEQ8I0tOx/4qUpgVzvgXL6ugxr0RY554Gz/NQsVqknqPzUcxpQ==", "requires": { - "@ethersproject/bytes": "^5.0.0", + "@ethersproject/bytes": "^5.0.4", "js-sha3": "0.5.7" + }, + "dependencies": { + "js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc=" + } } }, "@ethersproject/logger": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.0.2.tgz", - "integrity": "sha512-NQe3O1/Nwkcp6bto6hsTvrcCeR/cOGK+RhOMn0Zi2FND6gdWsf1g+5ie8gQ1REqDX4MTGP/Y131dZas985ls/g==" + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.0.6.tgz", + "integrity": "sha512-FrX0Vnb3JZ1md/7GIZfmJ06XOAA8r3q9Uqt9O5orr4ZiksnbpXKlyDzQtlZ5Yv18RS8CAUbiKH9vwidJg1BPmQ==" + }, + "@ethersproject/networks": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.0.4.tgz", + "integrity": "sha512-/wHDTRms5mpJ09BoDrbNdFWINzONe05wZRgohCXvEv39rrH/Gd/yAnct8wC0RsW3tmFOgjgQxuBvypIxuUynTw==", + "requires": { + "@ethersproject/logger": "^5.0.5" + } }, "@ethersproject/properties": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.0.1.tgz", - "integrity": "sha512-b3VZ/NpYIf64/hFXeWNxVCbY1xoMPIYM3n6Qnu6Ayr3bLt1olFPQfAaaRB0aOsLz7tMtmkT3DrA1KG/IrOgBRw==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.0.4.tgz", + "integrity": "sha512-UdyX3GqBxFt15B0uSESdDNmhvEbK3ACdDXl2soshoPcneXuTswHDeA0LoPlnaZzhbgk4p6jqb4GMms5C26Qu6A==", "requires": { - "@ethersproject/logger": "^5.0.0" + "@ethersproject/logger": "^5.0.5" } }, "@ethersproject/rlp": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.0.1.tgz", - "integrity": "sha512-3F8XE1zS4w8w4xiK1hMtFuVs6UnhQlmrEHLT85GanqK8vG5wGi81IQmkukL9tQIu2a5jykoO46ibja+6N1fpFg==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.0.4.tgz", + "integrity": "sha512-5qrrZad7VTjofxSsm7Zg/7Dr4ZOln4S2CqiDdOuTv6MBKnXj0CiBojXyuDy52M8O3wxH0CyE924hXWTDV1PQWQ==", "requires": { - "@ethersproject/bytes": "^5.0.0", - "@ethersproject/logger": "^5.0.0" + "@ethersproject/bytes": "^5.0.4", + "@ethersproject/logger": "^5.0.5" } }, "@ethersproject/signing-key": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.0.3.tgz", - "integrity": "sha512-5QPZaBRGCLzfVMbFb3LcVjNR0UbTXnwDHASnQYfbzwUOnFYHKxHsrcbl/5ONGoppgi8yXgOocKqlPCFycJJVWQ==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.0.5.tgz", + "integrity": "sha512-Z1wY7JC1HVO4CvQWY2TyTTuAr8xK3bJijZw1a9G92JEmKdv1j255R/0YLBBcFTl2J65LUjtXynNJ2GbArPGi5g==", "requires": { - "@ethersproject/bytes": "^5.0.0", - "@ethersproject/logger": "^5.0.0", - "@ethersproject/properties": "^5.0.0", + "@ethersproject/bytes": "^5.0.4", + "@ethersproject/logger": "^5.0.5", + "@ethersproject/properties": "^5.0.3", "elliptic": "6.5.3" } }, "@ethersproject/strings": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.0.1.tgz", - "integrity": "sha512-N8LxdHGBT7GZdogkEOV5xKXYTz5PNHuNzcxLNPYfH3kpvWSyXshZBgAz8YE1a8sMZagGj+Ic6d3mHijdCTSkGA==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.0.5.tgz", + "integrity": "sha512-JED6WaIV00xM/gvj8vSnd+0VWtDYdidTmavFRCTQakqfz+4tDo6Jz5LHgG+dd45h7ah7ykCHW0C7ZXWEDROCXQ==", "requires": { - "@ethersproject/bytes": "^5.0.0", - "@ethersproject/constants": "^5.0.0", - "@ethersproject/logger": "^5.0.0" + "@ethersproject/bytes": "^5.0.4", + "@ethersproject/constants": "^5.0.4", + "@ethersproject/logger": "^5.0.5" } }, "@ethersproject/transactions": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.0.1.tgz", - "integrity": "sha512-IGc6/5hri3PrqR/ZCj89osDiq3Lt0CSrycn6vlRl8SjpBKYDdcT+Ru5xkeC7YcsnqcdBmTL+jyR3SLudU+x2Kw==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.0.6.tgz", + "integrity": "sha512-htsFhOD+NMBxx676A8ehSuwVV49iqpSB+CkjPZ02tpNew0K6p8g0CZ46Z1ZP946gIHAU80xQ0NACHYrjIUaCFA==", "requires": { - "@ethersproject/address": "^5.0.0", - "@ethersproject/bignumber": "^5.0.0", - "@ethersproject/bytes": "^5.0.0", - "@ethersproject/constants": "^5.0.0", - "@ethersproject/keccak256": "^5.0.0", - "@ethersproject/logger": "^5.0.0", - "@ethersproject/properties": "^5.0.0", - "@ethersproject/rlp": "^5.0.0", - "@ethersproject/signing-key": "^5.0.0" + "@ethersproject/address": "^5.0.4", + "@ethersproject/bignumber": "^5.0.7", + "@ethersproject/bytes": "^5.0.4", + "@ethersproject/constants": "^5.0.4", + "@ethersproject/keccak256": "^5.0.3", + "@ethersproject/logger": "^5.0.5", + "@ethersproject/properties": "^5.0.3", + "@ethersproject/rlp": "^5.0.3", + "@ethersproject/signing-key": "^5.0.4" + } + }, + "@ethersproject/web": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.0.9.tgz", + "integrity": "sha512-//QNlv1MSkOII1hv3+HQwWoiVFS+BMVGI0KYeUww4cyrEktnx1QIez5bTSab9s9fWTFaWKNmQNBwMbxAqPuYDw==", + "requires": { + "@ethersproject/base64": "^5.0.3", + "@ethersproject/bytes": "^5.0.4", + "@ethersproject/logger": "^5.0.5", + "@ethersproject/properties": "^5.0.3", + "@ethersproject/strings": "^5.0.4" } }, "@nodelib/fs.scandir": { @@ -411,9 +447,9 @@ "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==" }, "@solidity-parser/parser": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.6.1.tgz", - "integrity": "sha512-MUA5kP9LdeTILeOsaz/k/qA4MdTNUxrn6q6HMYsMzQN5crU9bWKND2DaoWZhzofQM0VaTOaD8GFkCw1BYbNj5w==", + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.8.2.tgz", + "integrity": "sha512-8LySx3qrNXPgB5JiULfG10O3V7QTxI/TLzSw5hFQhXWSkVxZBAv4rZQ0sYgLEbc8g3L2lmnujj1hKul38Eu5NQ==", "dev": true }, "@szmarczak/http-timer": { @@ -431,9 +467,9 @@ "dev": true }, "@truffle/hdwallet-provider": { - "version": "1.0.42", - "resolved": "https://registry.npmjs.org/@truffle/hdwallet-provider/-/hdwallet-provider-1.0.42.tgz", - "integrity": "sha512-Q6+Pn6x9oLE0lTk72xC4V7il/UoI2i6dy8kSfh4xjYkE585SO9sc7ndXqX5K+epPolr7UAndEe7Lv6mHjiPmsQ==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@truffle/hdwallet-provider/-/hdwallet-provider-1.2.0.tgz", + "integrity": "sha512-EPatDbyRuGbB/MLt9ZBokmtjyLjaNpuHfUIWuv4mQMrH1Nu82H5AAZYLh4Z1BZliDZpqB03a0yUMmK/4R0BN9g==", "dev": true, "requires": { "@trufflesuite/web3-provider-engine": "15.0.13-1", @@ -533,9 +569,9 @@ }, "dependencies": { "@types/node": { - "version": "12.12.47", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.47.tgz", - "integrity": "sha512-yzBInQFhdY8kaZmqoL2+3U5dSTMrKaYcb561VU+lDzAYvqt+2lojvBEy+hmpSNuXnPTx7m9+04CzWYOUqWME2A==", + "version": "12.19.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.3.tgz", + "integrity": "sha512-8Jduo8wvvwDzEVJCOvS/G6sgilOLvvhn1eMmK3TW8/T217O7u1jdrK6ImKLv80tVryaPSVeKu6sjDEiFjd4/eg==", "dev": true }, "bn.js": { @@ -544,6 +580,77 @@ "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", "dev": true }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "eth-lib": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.7.tgz", + "integrity": "sha1-L5Pxex4jrsN1nNSj/iDBKGo/wco=", + "dev": true, + "requires": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + } + }, + "ethers": { + "version": "4.0.48", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.48.tgz", + "integrity": "sha512-sZD5K8H28dOrcidzx9f8KYh8083n5BexIO3+SbE4jK83L85FxtpXZBCQdXb8gkg+7sBqomcLhhkU7UHL+F7I2g==", + "dev": true, + "requires": { + "aes-js": "3.0.0", + "bn.js": "^4.4.0", + "elliptic": "6.5.3", + "hash.js": "1.1.3", + "js-sha3": "0.5.7", + "scrypt-js": "2.0.4", + "setimmediate": "1.0.4", + "uuid": "2.0.1", + "xmlhttprequest": "1.8.0" + } + }, + "hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.0" + } + }, + "js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc=", + "dev": true + }, + "scrypt-js": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.4.tgz", + "integrity": "sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw==", + "dev": true + }, + "setimmediate": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz", + "integrity": "sha1-IOgd5iLUoCWIzgyNqJc8vPHTE48=", + "dev": true + }, + "uuid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", + "integrity": "sha1-wqMN7bPlNdcsz4LjQ5QaULqFM6w=", + "dev": true + }, "web3": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/web3/-/web3-1.2.2.tgz", @@ -559,6 +666,358 @@ "web3-shh": "1.2.2", "web3-utils": "1.2.2" } + }, + "web3-bzz": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.2.2.tgz", + "integrity": "sha512-b1O2ObsqUN1lJxmFSjvnEC4TsaCbmh7Owj3IAIWTKqL9qhVgx7Qsu5O9cD13pBiSPNZJ68uJPaKq380QB4NWeA==", + "dev": true, + "requires": { + "@types/node": "^10.12.18", + "got": "9.6.0", + "swarm-js": "0.1.39", + "underscore": "1.9.1" + }, + "dependencies": { + "@types/node": { + "version": "10.17.44", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.44.tgz", + "integrity": "sha512-vHPAyBX1ffLcy4fQHmDyIUMUb42gHZjPHU66nhvbMzAWJqHnySGZ6STwN3rwrnSd1FHB0DI/RWgGELgKSYRDmw==", + "dev": true + } + } + }, + "web3-core": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.2.2.tgz", + "integrity": "sha512-miHAX3qUgxV+KYfaOY93Hlc3kLW2j5fH8FJy6kSxAv+d4d5aH0wwrU2IIoJylQdT+FeenQ38sgsCnFu9iZ1hCQ==", + "dev": true, + "requires": { + "@types/bn.js": "^4.11.4", + "@types/node": "^12.6.1", + "web3-core-helpers": "1.2.2", + "web3-core-method": "1.2.2", + "web3-core-requestmanager": "1.2.2", + "web3-utils": "1.2.2" + } + }, + "web3-core-helpers": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.2.tgz", + "integrity": "sha512-HJrRsIGgZa1jGUIhvGz4S5Yh6wtOIo/TMIsSLe+Xay+KVnbseJpPprDI5W3s7H2ODhMQTbogmmUFquZweW2ImQ==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-eth-iban": "1.2.2", + "web3-utils": "1.2.2" + } + }, + "web3-core-method": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.2.2.tgz", + "integrity": "sha512-szR4fDSBxNHaF1DFqE+j6sFR/afv9Aa36OW93saHZnrh+iXSrYeUUDfugeNcRlugEKeUCkd4CZylfgbK2SKYJA==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-core-helpers": "1.2.2", + "web3-core-promievent": "1.2.2", + "web3-core-subscriptions": "1.2.2", + "web3-utils": "1.2.2" + } + }, + "web3-core-promievent": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.2.2.tgz", + "integrity": "sha512-tKvYeT8bkUfKABcQswK6/X79blKTKYGk949urZKcLvLDEaWrM3uuzDwdQT3BNKzQ3vIvTggFPX9BwYh0F1WwqQ==", + "dev": true, + "requires": { + "any-promise": "1.3.0", + "eventemitter3": "3.1.2" + } + }, + "web3-core-requestmanager": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.2.2.tgz", + "integrity": "sha512-a+gSbiBRHtHvkp78U2bsntMGYGF2eCb6219aMufuZWeAZGXJ63Wc2321PCbA8hF9cQrZI4EoZ4kVLRI4OF15Hw==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-core-helpers": "1.2.2", + "web3-providers-http": "1.2.2", + "web3-providers-ipc": "1.2.2", + "web3-providers-ws": "1.2.2" + } + }, + "web3-core-subscriptions": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.2.2.tgz", + "integrity": "sha512-QbTgigNuT4eicAWWr7ahVpJyM8GbICsR1Ys9mJqzBEwpqS+RXTRVSkwZ2IsxO+iqv6liMNwGregbJLq4urMFcQ==", + "dev": true, + "requires": { + "eventemitter3": "3.1.2", + "underscore": "1.9.1", + "web3-core-helpers": "1.2.2" + } + }, + "web3-eth": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.2.2.tgz", + "integrity": "sha512-UXpC74mBQvZzd4b+baD4Ocp7g+BlwxhBHumy9seyE/LMIcMlePXwCKzxve9yReNpjaU16Mmyya6ZYlyiKKV8UA==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-core": "1.2.2", + "web3-core-helpers": "1.2.2", + "web3-core-method": "1.2.2", + "web3-core-subscriptions": "1.2.2", + "web3-eth-abi": "1.2.2", + "web3-eth-accounts": "1.2.2", + "web3-eth-contract": "1.2.2", + "web3-eth-ens": "1.2.2", + "web3-eth-iban": "1.2.2", + "web3-eth-personal": "1.2.2", + "web3-net": "1.2.2", + "web3-utils": "1.2.2" + } + }, + "web3-eth-abi": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.2.2.tgz", + "integrity": "sha512-Yn/ZMgoOLxhTVxIYtPJ0eS6pnAnkTAaJgUJh1JhZS4ekzgswMfEYXOwpMaD5eiqPJLpuxmZFnXnBZlnQ1JMXsw==", + "dev": true, + "requires": { + "ethers": "4.0.0-beta.3", + "underscore": "1.9.1", + "web3-utils": "1.2.2" + }, + "dependencies": { + "@types/node": { + "version": "10.17.44", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.44.tgz", + "integrity": "sha512-vHPAyBX1ffLcy4fQHmDyIUMUb42gHZjPHU66nhvbMzAWJqHnySGZ6STwN3rwrnSd1FHB0DI/RWgGELgKSYRDmw==", + "dev": true + }, + "elliptic": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.3.3.tgz", + "integrity": "sha1-VILZZG1UvLif19mU/J4ulWiHbj8=", + "dev": true, + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "inherits": "^2.0.1" + } + }, + "ethers": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.0-beta.3.tgz", + "integrity": "sha512-YYPogooSknTwvHg3+Mv71gM/3Wcrx+ZpCzarBj3mqs9njjRkrOo2/eufzhHloOCo3JSoNI4TQJJ6yU5ABm3Uog==", + "dev": true, + "requires": { + "@types/node": "^10.3.2", + "aes-js": "3.0.0", + "bn.js": "^4.4.0", + "elliptic": "6.3.3", + "hash.js": "1.1.3", + "js-sha3": "0.5.7", + "scrypt-js": "2.0.3", + "setimmediate": "1.0.4", + "uuid": "2.0.1", + "xmlhttprequest": "1.8.0" + } + }, + "scrypt-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.3.tgz", + "integrity": "sha1-uwBAvgMEPamgEqLOqfyfhSz8h9Q=", + "dev": true + } + } + }, + "web3-eth-accounts": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.2.2.tgz", + "integrity": "sha512-KzHOEyXOEZ13ZOkWN3skZKqSo5f4Z1ogPFNn9uZbKCz+kSp+gCAEKxyfbOsB/JMAp5h7o7pb6eYsPCUBJmFFiA==", + "dev": true, + "requires": { + "any-promise": "1.3.0", + "crypto-browserify": "3.12.0", + "eth-lib": "0.2.7", + "ethereumjs-common": "^1.3.2", + "ethereumjs-tx": "^2.1.1", + "scrypt-shim": "github:web3-js/scrypt-shim", + "underscore": "1.9.1", + "uuid": "3.3.2", + "web3-core": "1.2.2", + "web3-core-helpers": "1.2.2", + "web3-core-method": "1.2.2", + "web3-utils": "1.2.2" + }, + "dependencies": { + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true + } + } + }, + "web3-eth-contract": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.2.2.tgz", + "integrity": "sha512-EKT2yVFws3FEdotDQoNsXTYL798+ogJqR2//CaGwx3p0/RvQIgfzEwp8nbgA6dMxCsn9KOQi7OtklzpnJMkjtA==", + "dev": true, + "requires": { + "@types/bn.js": "^4.11.4", + "underscore": "1.9.1", + "web3-core": "1.2.2", + "web3-core-helpers": "1.2.2", + "web3-core-method": "1.2.2", + "web3-core-promievent": "1.2.2", + "web3-core-subscriptions": "1.2.2", + "web3-eth-abi": "1.2.2", + "web3-utils": "1.2.2" + } + }, + "web3-eth-ens": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.2.2.tgz", + "integrity": "sha512-CFjkr2HnuyMoMFBoNUWojyguD4Ef+NkyovcnUc/iAb9GP4LHohKrODG4pl76R5u61TkJGobC2ij6TyibtsyVYg==", + "dev": true, + "requires": { + "eth-ens-namehash": "2.0.8", + "underscore": "1.9.1", + "web3-core": "1.2.2", + "web3-core-helpers": "1.2.2", + "web3-core-promievent": "1.2.2", + "web3-eth-abi": "1.2.2", + "web3-eth-contract": "1.2.2", + "web3-utils": "1.2.2" + } + }, + "web3-eth-iban": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.2.2.tgz", + "integrity": "sha512-gxKXBoUhaTFHr0vJB/5sd4i8ejF/7gIsbM/VvemHT3tF5smnmY6hcwSMmn7sl5Gs+83XVb/BngnnGkf+I/rsrQ==", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "web3-utils": "1.2.2" + }, + "dependencies": { + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "dev": true + } + } + }, + "web3-eth-personal": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.2.2.tgz", + "integrity": "sha512-4w+GLvTlFqW3+q4xDUXvCEMU7kRZ+xm/iJC8gm1Li1nXxwwFbs+Y+KBK6ZYtoN1qqAnHR+plYpIoVo27ixI5Rg==", + "dev": true, + "requires": { + "@types/node": "^12.6.1", + "web3-core": "1.2.2", + "web3-core-helpers": "1.2.2", + "web3-core-method": "1.2.2", + "web3-net": "1.2.2", + "web3-utils": "1.2.2" + } + }, + "web3-net": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.2.2.tgz", + "integrity": "sha512-K07j2DXq0x4UOJgae65rWZKraOznhk8v5EGSTdFqASTx7vWE/m+NqBijBYGEsQY1lSMlVaAY9UEQlcXK5HzXTw==", + "dev": true, + "requires": { + "web3-core": "1.2.2", + "web3-core-method": "1.2.2", + "web3-utils": "1.2.2" + } + }, + "web3-providers-http": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.2.2.tgz", + "integrity": "sha512-BNZ7Hguy3eBszsarH5gqr9SIZNvqk9eKwqwmGH1LQS1FL3NdoOn7tgPPdddrXec4fL94CwgNk4rCU+OjjZRNDg==", + "dev": true, + "requires": { + "web3-core-helpers": "1.2.2", + "xhr2-cookies": "1.1.0" + } + }, + "web3-providers-ipc": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.2.2.tgz", + "integrity": "sha512-t97w3zi5Kn/LEWGA6D9qxoO0LBOG+lK2FjlEdCwDQatffB/+vYrzZ/CLYVQSoyFZAlsDoBasVoYSWZK1n39aHA==", + "dev": true, + "requires": { + "oboe": "2.1.4", + "underscore": "1.9.1", + "web3-core-helpers": "1.2.2" + } + }, + "web3-providers-ws": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.2.2.tgz", + "integrity": "sha512-Wb1mrWTGMTXOpJkL0yGvL/WYLt8fUIXx8k/l52QB2IiKzvyd42dTWn4+j8IKXGSYYzOm7NMqv6nhA5VDk12VfA==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-core-helpers": "1.2.2", + "websocket": "github:web3-js/WebSocket-Node#polyfill/globalThis" + } + }, + "web3-shh": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.2.2.tgz", + "integrity": "sha512-og258NPhlBn8yYrDWjoWBBb6zo1OlBgoWGT+LL5/LPqRbjPe09hlOYHgscAAr9zZGtohTOty7RrxYw6Z6oDWCg==", + "dev": true, + "requires": { + "web3-core": "1.2.2", + "web3-core-method": "1.2.2", + "web3-core-subscriptions": "1.2.2", + "web3-net": "1.2.2" + } + }, + "web3-utils": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.2.2.tgz", + "integrity": "sha512-joF+s3243TY5cL7Z7y4h1JsJpUCf/kmFmj+eJar7Y2yNIGVcW961VyrAms75tjUysSuHaUQ3eQXjBEUJueT52A==", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "eth-lib": "0.2.7", + "ethereum-bloom-filters": "^1.0.6", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "underscore": "1.9.1", + "utf8": "3.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "dev": true + } + } + }, + "websocket": { + "version": "github:web3-js/WebSocket-Node#ef5ea2f41daf4a2113b80c9223df884b4d56c400", + "from": "github:web3-js/WebSocket-Node#polyfill/globalThis", + "dev": true, + "requires": { + "debug": "^2.2.0", + "es5-ext": "^0.10.50", + "nan": "^2.14.0", + "typedarray-to-buffer": "^3.1.5", + "yaeti": "^0.0.6" + } } } }, @@ -573,83 +1032,6 @@ "web3": "1.2.1" }, "dependencies": { - "@types/node": { - "version": "10.17.26", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.26.tgz", - "integrity": "sha512-myMwkO2Cr82kirHY8uknNRHEVtn0wV3DTQfkrjx17jmkstDRZ24gNUdl8AHXVyVclTYI/bNjgTPTAWvWLqXqkw==", - "dev": true - }, - "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", - "dev": true - }, - "eth-lib": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.7.tgz", - "integrity": "sha1-L5Pxex4jrsN1nNSj/iDBKGo/wco=", - "dev": true, - "requires": { - "bn.js": "^4.11.6", - "elliptic": "^6.4.0", - "xhr-request-promise": "^0.1.2" - } - }, - "ethers": { - "version": "4.0.0-beta.3", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.0-beta.3.tgz", - "integrity": "sha512-YYPogooSknTwvHg3+Mv71gM/3Wcrx+ZpCzarBj3mqs9njjRkrOo2/eufzhHloOCo3JSoNI4TQJJ6yU5ABm3Uog==", - "dev": true, - "requires": { - "@types/node": "^10.3.2", - "aes-js": "3.0.0", - "bn.js": "^4.4.0", - "elliptic": "6.3.3", - "hash.js": "1.1.3", - "js-sha3": "0.5.7", - "scrypt-js": "2.0.3", - "setimmediate": "1.0.4", - "uuid": "2.0.1", - "xmlhttprequest": "1.8.0" - }, - "dependencies": { - "elliptic": { - "version": "6.3.3", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.3.3.tgz", - "integrity": "sha1-VILZZG1UvLif19mU/J4ulWiHbj8=", - "dev": true, - "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "inherits": "^2.0.1" - } - } - } - }, - "hash.js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", - "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.0" - } - }, - "scrypt-js": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.3.tgz", - "integrity": "sha1-uwBAvgMEPamgEqLOqfyfhSz8h9Q=", - "dev": true - }, - "semver": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.2.0.tgz", - "integrity": "sha512-jdFC1VdUGT/2Scgbimf7FSx9iJLXoqfglSF+gJeuNWVpiE37OIbc1jywR/GJyFdz3mnkz2/id0L0J/cr0izR5A==", - "dev": true - }, "web3": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/web3/-/web3-1.2.1.tgz", @@ -664,271 +1046,6 @@ "web3-shh": "1.2.1", "web3-utils": "1.2.1" } - }, - "web3-bzz": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.2.1.tgz", - "integrity": "sha512-LdOO44TuYbGIPfL4ilkuS89GQovxUpmLz6C1UC7VYVVRILeZS740FVB3j9V4P4FHUk1RenaDfKhcntqgVCHtjw==", - "dev": true, - "requires": { - "got": "9.6.0", - "swarm-js": "0.1.39", - "underscore": "1.9.1" - } - }, - "web3-core": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.2.1.tgz", - "integrity": "sha512-5ODwIqgl8oIg/0+Ai4jsLxkKFWJYE0uLuE1yUKHNVCL4zL6n3rFjRMpKPokd6id6nJCNgeA64KdWQ4XfpnjdMg==", - "dev": true, - "requires": { - "web3-core-helpers": "1.2.1", - "web3-core-method": "1.2.1", - "web3-core-requestmanager": "1.2.1", - "web3-utils": "1.2.1" - } - }, - "web3-core-helpers": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.1.tgz", - "integrity": "sha512-Gx3sTEajD5r96bJgfuW377PZVFmXIH4TdqDhgGwd2lZQCcMi+DA4TgxJNJGxn0R3aUVzyyE76j4LBrh412mXrw==", - "dev": true, - "requires": { - "underscore": "1.9.1", - "web3-eth-iban": "1.2.1", - "web3-utils": "1.2.1" - } - }, - "web3-core-method": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.2.1.tgz", - "integrity": "sha512-Ghg2WS23qi6Xj8Od3VCzaImLHseEA7/usvnOItluiIc5cKs00WYWsNy2YRStzU9a2+z8lwQywPYp0nTzR/QXdQ==", - "dev": true, - "requires": { - "underscore": "1.9.1", - "web3-core-helpers": "1.2.1", - "web3-core-promievent": "1.2.1", - "web3-core-subscriptions": "1.2.1", - "web3-utils": "1.2.1" - } - }, - "web3-core-promievent": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.2.1.tgz", - "integrity": "sha512-IVUqgpIKoeOYblwpex4Hye6npM0aMR+kU49VP06secPeN0rHMyhGF0ZGveWBrGvf8WDPI7jhqPBFIC6Jf3Q3zw==", - "dev": true, - "requires": { - "any-promise": "1.3.0", - "eventemitter3": "3.1.2" - } - }, - "web3-core-requestmanager": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.2.1.tgz", - "integrity": "sha512-xfknTC69RfYmLKC+83Jz73IC3/sS2ZLhGtX33D4Q5nQ8yc39ElyAolxr9sJQS8kihOcM6u4J+8gyGMqsLcpIBg==", - "dev": true, - "requires": { - "underscore": "1.9.1", - "web3-core-helpers": "1.2.1", - "web3-providers-http": "1.2.1", - "web3-providers-ipc": "1.2.1", - "web3-providers-ws": "1.2.1" - } - }, - "web3-core-subscriptions": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.2.1.tgz", - "integrity": "sha512-nmOwe3NsB8V8UFsY1r+sW6KjdOS68h8nuh7NzlWxBQT/19QSUGiERRTaZXWu5BYvo1EoZRMxCKyCQpSSXLc08g==", - "dev": true, - "requires": { - "eventemitter3": "3.1.2", - "underscore": "1.9.1", - "web3-core-helpers": "1.2.1" - } - }, - "web3-eth": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.2.1.tgz", - "integrity": "sha512-/2xly4Yry5FW1i+uygPjhfvgUP/MS/Dk+PDqmzp5M88tS86A+j8BzKc23GrlA8sgGs0645cpZK/999LpEF5UdA==", - "dev": true, - "requires": { - "underscore": "1.9.1", - "web3-core": "1.2.1", - "web3-core-helpers": "1.2.1", - "web3-core-method": "1.2.1", - "web3-core-subscriptions": "1.2.1", - "web3-eth-abi": "1.2.1", - "web3-eth-accounts": "1.2.1", - "web3-eth-contract": "1.2.1", - "web3-eth-ens": "1.2.1", - "web3-eth-iban": "1.2.1", - "web3-eth-personal": "1.2.1", - "web3-net": "1.2.1", - "web3-utils": "1.2.1" - } - }, - "web3-eth-abi": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.2.1.tgz", - "integrity": "sha512-jI/KhU2a/DQPZXHjo2GW0myEljzfiKOn+h1qxK1+Y9OQfTcBMxrQJyH5AP89O6l6NZ1QvNdq99ThAxBFoy5L+g==", - "dev": true, - "requires": { - "ethers": "4.0.0-beta.3", - "underscore": "1.9.1", - "web3-utils": "1.2.1" - } - }, - "web3-eth-accounts": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.2.1.tgz", - "integrity": "sha512-26I4qq42STQ8IeKUyur3MdQ1NzrzCqPsmzqpux0j6X/XBD7EjZ+Cs0lhGNkSKH5dI3V8CJasnQ5T1mNKeWB7nQ==", - "dev": true, - "requires": { - "any-promise": "1.3.0", - "crypto-browserify": "3.12.0", - "eth-lib": "0.2.7", - "scryptsy": "2.1.0", - "semver": "6.2.0", - "underscore": "1.9.1", - "uuid": "3.3.2", - "web3-core": "1.2.1", - "web3-core-helpers": "1.2.1", - "web3-core-method": "1.2.1", - "web3-utils": "1.2.1" - }, - "dependencies": { - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", - "dev": true - } - } - }, - "web3-eth-contract": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.2.1.tgz", - "integrity": "sha512-kYFESbQ3boC9bl2rYVghj7O8UKMiuKaiMkxvRH5cEDHil8V7MGEGZNH0slSdoyeftZVlaWSMqkRP/chfnKND0g==", - "dev": true, - "requires": { - "underscore": "1.9.1", - "web3-core": "1.2.1", - "web3-core-helpers": "1.2.1", - "web3-core-method": "1.2.1", - "web3-core-promievent": "1.2.1", - "web3-core-subscriptions": "1.2.1", - "web3-eth-abi": "1.2.1", - "web3-utils": "1.2.1" - } - }, - "web3-eth-ens": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.2.1.tgz", - "integrity": "sha512-lhP1kFhqZr2nnbu3CGIFFrAnNxk2veXpOXBY48Tub37RtobDyHijHgrj+xTh+mFiPokyrapVjpFsbGa+Xzye4Q==", - "dev": true, - "requires": { - "eth-ens-namehash": "2.0.8", - "underscore": "1.9.1", - "web3-core": "1.2.1", - "web3-core-helpers": "1.2.1", - "web3-core-promievent": "1.2.1", - "web3-eth-abi": "1.2.1", - "web3-eth-contract": "1.2.1", - "web3-utils": "1.2.1" - } - }, - "web3-eth-iban": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.2.1.tgz", - "integrity": "sha512-9gkr4QPl1jCU+wkgmZ8EwODVO3ovVj6d6JKMos52ggdT2YCmlfvFVF6wlGLwi0VvNa/p+0BjJzaqxnnG/JewjQ==", - "dev": true, - "requires": { - "bn.js": "4.11.8", - "web3-utils": "1.2.1" - } - }, - "web3-eth-personal": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.2.1.tgz", - "integrity": "sha512-RNDVSiaSoY4aIp8+Hc7z+X72H7lMb3fmAChuSBADoEc7DsJrY/d0R5qQDK9g9t2BO8oxgLrLNyBP/9ub2Hc6Bg==", - "dev": true, - "requires": { - "web3-core": "1.2.1", - "web3-core-helpers": "1.2.1", - "web3-core-method": "1.2.1", - "web3-net": "1.2.1", - "web3-utils": "1.2.1" - } - }, - "web3-net": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.2.1.tgz", - "integrity": "sha512-Yt1Bs7WgnLESPe0rri/ZoPWzSy55ovioaP35w1KZydrNtQ5Yq4WcrAdhBzcOW7vAkIwrsLQsvA+hrOCy7mNauw==", - "dev": true, - "requires": { - "web3-core": "1.2.1", - "web3-core-method": "1.2.1", - "web3-utils": "1.2.1" - } - }, - "web3-providers-http": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.2.1.tgz", - "integrity": "sha512-BDtVUVolT9b3CAzeGVA/np1hhn7RPUZ6YYGB/sYky+GjeO311Yoq8SRDUSezU92x8yImSC2B+SMReGhd1zL+bQ==", - "dev": true, - "requires": { - "web3-core-helpers": "1.2.1", - "xhr2-cookies": "1.1.0" - } - }, - "web3-providers-ipc": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.2.1.tgz", - "integrity": "sha512-oPEuOCwxVx8L4CPD0TUdnlOUZwGBSRKScCz/Ws2YHdr9Ium+whm+0NLmOZjkjQp5wovQbyBzNa6zJz1noFRvFA==", - "dev": true, - "requires": { - "oboe": "2.1.4", - "underscore": "1.9.1", - "web3-core-helpers": "1.2.1" - } - }, - "web3-providers-ws": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.2.1.tgz", - "integrity": "sha512-oqsQXzu+ejJACVHy864WwIyw+oB21nw/pI65/sD95Zi98+/HQzFfNcIFneF1NC4bVF3VNX4YHTNq2I2o97LAiA==", - "dev": true, - "requires": { - "underscore": "1.9.1", - "web3-core-helpers": "1.2.1", - "websocket": "github:web3-js/WebSocket-Node#polyfill/globalThis" - } - }, - "web3-shh": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.2.1.tgz", - "integrity": "sha512-/3Cl04nza5kuFn25bV3FJWa0s3Vafr5BlT933h26xovQ6HIIz61LmvNQlvX1AhFL+SNJOTcQmK1SM59vcyC8bA==", - "dev": true, - "requires": { - "web3-core": "1.2.1", - "web3-core-method": "1.2.1", - "web3-core-subscriptions": "1.2.1", - "web3-net": "1.2.1" - } - }, - "web3-utils": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.2.1.tgz", - "integrity": "sha512-Mrcn3l58L+yCKz3zBryM6JZpNruWuT0OCbag8w+reeNROSGVlXzUQkU+gtAwc9JCZ7tKUyg67+2YUGqUjVcyBA==", - "dev": true, - "requires": { - "bn.js": "4.11.8", - "eth-lib": "0.2.7", - "ethjs-unit": "0.1.6", - "number-to-bn": "1.7.0", - "randomhex": "0.1.5", - "underscore": "1.9.1", - "utf8": "3.0.0" - } } } }, @@ -1108,15 +1225,6 @@ "xtend": "^4.0.1" }, "dependencies": { - "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "dev": true, - "requires": { - "lodash": "^4.17.14" - } - }, "bn.js": { "version": "4.11.9", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", @@ -1154,46 +1262,6 @@ "safe-buffer": "^5.1.1" } }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - } - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - } - } - }, "ws": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", @@ -1214,9 +1282,9 @@ } }, "@types/chai": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.11.tgz", - "integrity": "sha512-t7uW6eFafjO+qJ3BIV2gGUyZs27egcNRkUdalkud+Qa3+kg//f129iuOFivHDXQ+vnU3fDXuwgv0cqMCbcE8sw==" + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.14.tgz", + "integrity": "sha512-G+ITQPXkwTrslfG5L/BksmbLUA0M1iybEsmCWPqzSxsRRhJZimBKJkoMi8fr/CPygPTj4zO5pJH7I2/cm9M7SQ==" }, "@types/es6-promisify": { "version": "6.0.0", @@ -1224,9 +1292,9 @@ "integrity": "sha512-w3eB2FfE60gHeUTWT65G/FsTlqOAl8qZeyDGxAniF4oS7T6acQ7uvtGKQlCIQNOGh6r21A/3mBASNzy8Tbx+hg==" }, "@types/glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-VgNIkxK+j7Nz5P7jvUZlRvhuPSmsEfS03b0alKcq5V/STUKAa3Plemsn5mrQUO7am6OErJ4rhGEGJbACclrtRA==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", "dev": true, "requires": { "@types/minimatch": "*", @@ -1245,15 +1313,14 @@ "integrity": "sha512-ZvO2tAcjmMi8V/5Z3JsyofMe3hasRcaw88cto5etSVMwVQfeivGAlEYmaQgceUSVYFofVjT+ioHsATjdWcFt1w==" }, "@types/node": { - "version": "14.0.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.10.tgz", - "integrity": "sha512-Bz23oN/5bi0rniKT24ExLf4cK0JdvN3dH/3k0whYkdN4eI4vS2ZW/2ENNn2uxHCzWcbdHIa/GRuWQytfzCjRYw==" + "version": "14.14.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.6.tgz", + "integrity": "sha512-6QlRuqsQ/Ox/aJEQWBEJG7A9+u7oSYl3mem/K8IzxXG/kAGbV1YPD9Bg9Zw3vyxC/YP+zONKwy8hGkSt1jxFMw==" }, "@types/pbkdf2": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.0.tgz", "integrity": "sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==", - "dev": true, "requires": { "@types/node": "*" } @@ -1262,7 +1329,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.1.tgz", "integrity": "sha512-+ZjSA8ELlOp8SlKi0YLB2tz9d5iPNEmOBd+8Rz21wTMdaXQIa9b6TEnD6l5qKOCypE7FSyPyck12qZJxSDNoog==", - "dev": true, "requires": { "@types/node": "*" } @@ -1276,54 +1342,6 @@ "web3": "*" } }, - "@web3-js/scrypt-shim": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@web3-js/scrypt-shim/-/scrypt-shim-0.1.0.tgz", - "integrity": "sha512-ZtZeWCc/s0nMcdx/+rZwY1EcuRdemOK9ag21ty9UsHkFxsNb/AaoucUz0iPuyGe0Ku+PFuRmWZG7Z7462p9xPw==", - "dev": true, - "requires": { - "scryptsy": "^2.1.0", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@web3-js/websocket": { - "version": "1.0.30", - "resolved": "https://registry.npmjs.org/@web3-js/websocket/-/websocket-1.0.30.tgz", - "integrity": "sha512-fDwrD47MiDrzcJdSeTLF75aCcxVVt8B1N74rA+vh2XCAvFy4tEWJjtnUtj2QG7/zlQ6g9cQ88bZFBxwd9/FmtA==", - "dev": true, - "requires": { - "debug": "^2.2.0", - "es5-ext": "^0.10.50", - "nan": "^2.14.0", - "typedarray-to-buffer": "^3.1.5", - "yaeti": "^0.0.6" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, "abbrev": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", @@ -1360,9 +1378,9 @@ "integrity": "sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0=" }, "ajv": { - "version": "6.12.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", - "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "requires": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -1383,18 +1401,14 @@ "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==" }, "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" }, "any-promise": { "version": "1.3.0", @@ -1409,64 +1423,6 @@ "requires": { "micromatch": "^2.1.5", "normalize-path": "^2.0.0" - }, - "dependencies": { - "braces": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", - "optional": true, - "requires": { - "expand-range": "^1.8.1", - "preserve": "^0.2.0", - "repeat-element": "^1.1.2" - } - }, - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "optional": true - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "optional": true, - "requires": { - "is-extglob": "^1.0.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "optional": true, - "requires": { - "is-buffer": "^1.1.5" - } - }, - "micromatch": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", - "optional": true, - "requires": { - "arr-diff": "^2.0.0", - "array-unique": "^0.2.1", - "braces": "^1.8.2", - "expand-brackets": "^0.1.4", - "extglob": "^0.3.1", - "filename-regex": "^2.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.1", - "kind-of": "^3.0.2", - "normalize-path": "^2.0.1", - "object.omit": "^2.0.0", - "parse-glob": "^3.0.4", - "regex-cache": "^0.4.2" - } - } } }, "arg": { @@ -1534,13 +1490,14 @@ } }, "asn1.js": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", - "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", "requires": { "bn.js": "^4.0.0", "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" }, "dependencies": { "bn.js": { @@ -1578,10 +1535,13 @@ "optional": true }, "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", - "dev": true + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } }, "async-each": { "version": "1.0.3", @@ -1596,17 +1556,6 @@ "dev": true, "requires": { "async": "^2.4.0" - }, - "dependencies": { - "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "dev": true, - "requires": { - "lodash": "^4.17.14" - } - } } }, "async-limiter": { @@ -1645,9 +1594,9 @@ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" }, "aws4": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.0.tgz", - "integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA==" + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" }, "axios": { "version": "0.20.0", @@ -1677,23 +1626,6 @@ "slash": "^1.0.0", "source-map": "^0.5.6", "v8flags": "^2.1.1" - }, - "dependencies": { - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" - } } }, "babel-code-frame": { @@ -1704,48 +1636,6 @@ "chalk": "^1.1.3", "esutils": "^2.0.2", "js-tokens": "^3.0.2" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - } } }, "babel-core": { @@ -1781,21 +1671,6 @@ "requires": { "ms": "2.0.0" } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" } } }, @@ -1810,16 +1685,6 @@ "@babel/types": "^7.7.0", "eslint-visitor-keys": "^1.0.0", "resolve": "^1.12.0" - }, - "dependencies": { - "resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", - "requires": { - "path-parse": "^1.0.6" - } - } } }, "babel-generator": { @@ -1835,13 +1700,6 @@ "lodash": "^4.17.4", "source-map": "^0.5.7", "trim-right": "^1.0.1" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" - } } }, "babel-helpers": { @@ -1890,16 +1748,6 @@ "lodash": "^4.17.4", "mkdirp": "^0.5.1", "source-map-support": "^0.4.15" - }, - "dependencies": { - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "requires": { - "minimist": "^1.2.5" - } - } } }, "babel-runtime": { @@ -1946,11 +1794,6 @@ "requires": { "ms": "2.0.0" } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" } } }, @@ -2042,6 +1885,12 @@ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "optional": true + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "optional": true } } }, @@ -2067,9 +1916,9 @@ } }, "bignumber.js": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", - "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", + "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==" }, "binary-extensions": { "version": "1.13.1", @@ -2085,66 +1934,19 @@ "file-uri-to-path": "1.0.0" } }, - "bip66": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/bip66/-/bip66-1.1.5.tgz", - "integrity": "sha1-AfqHSHhcpwlV1QESF9GzE5lpyiI=", - "requires": { - "safe-buffer": "^5.0.1" - } - }, "bl": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", - "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", + "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", "requires": { "readable-stream": "^2.3.5", "safe-buffer": "^5.1.1" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - } - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - } - } - } } }, "blakejs": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.1.0.tgz", - "integrity": "sha1-ad+S75U6qIylGjLfarHFShVfx6U=", - "dev": true + "integrity": "sha1-ad+S75U6qIylGjLfarHFShVfx6U=" }, "bluebird": { "version": "3.7.2", @@ -2152,9 +1954,9 @@ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, "bn.js": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.2.tgz", - "integrity": "sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA==" + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz", + "integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==" }, "body-parser": { "version": "1.19.0", @@ -2180,11 +1982,6 @@ "requires": { "ms": "2.0.0" } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" } } }, @@ -2198,11 +1995,14 @@ } }, "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "optional": true, "requires": { - "fill-range": "^7.0.1" + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" } }, "brorand": { @@ -2266,26 +2066,37 @@ } }, "browserify-sign": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.0.tgz", - "integrity": "sha512-hEZC1KEeYuoHRqhGhTy6gWrpJA3ZDjFWv0DE61643ZnOXAKJb3u7yWcrU0mMc9SwAqK1n7myPGndkp0dFG7NFA==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", + "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", "requires": { "bn.js": "^5.1.1", "browserify-rsa": "^4.0.1", "create-hash": "^1.2.0", "create-hmac": "^1.1.7", - "elliptic": "^6.5.2", + "elliptic": "^6.5.3", "inherits": "^2.0.4", "parse-asn1": "^5.1.5", "readable-stream": "^3.6.0", "safe-buffer": "^5.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } } }, "bs58": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", - "dev": true, "requires": { "base-x": "^3.0.2" } @@ -2294,7 +2105,6 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", - "dev": true, "requires": { "bs58": "^4.0.0", "create-hash": "^1.1.0", @@ -2308,12 +2118,12 @@ "dev": true }, "buffer": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", - "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" } }, "buffer-alloc": { @@ -2355,6 +2165,14 @@ "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" }, + "bufferutil": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.2.tgz", + "integrity": "sha512-AtnG3W6M8B2n4xDQ5R+70EXvOpnXsFYg/AK2yTZd+HQ/oxAdz+GI+DvjmhBw3L0ole+LJ0ngqY4JMbDzkfNzhA==", + "requires": { + "node-gyp-build": "^4.2.0" + } + }, "bytes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", @@ -2400,9 +2218,9 @@ }, "dependencies": { "get-stream": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", - "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", "requires": { "pump": "^3.0.0" } @@ -2414,6 +2232,15 @@ } } }, + "call-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.0.tgz", + "integrity": "sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.0" + } + }, "camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", @@ -2443,20 +2270,15 @@ "integrity": "sha512-SubOtaSI2AILWTWe2j0c6i2yFT/f9J6UBjeVGDuwDiPLkF/U5+/eTWUE3sbCZ1KgcPF6UJsDVYbIxaYA097MQA==" }, "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - } + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } }, "check-error": { @@ -2488,32 +2310,6 @@ "is-glob": "^2.0.0", "path-is-absolute": "^1.0.0", "readdirp": "^2.0.0" - }, - "dependencies": { - "glob-parent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", - "optional": true, - "requires": { - "is-glob": "^2.0.0" - } - }, - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "optional": true - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "optional": true, - "requires": { - "is-extglob": "^1.0.0" - } - } } }, "chownr": { @@ -2534,11 +2330,11 @@ }, "dependencies": { "multicodec": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-1.0.1.tgz", - "integrity": "sha512-yrrU/K8zHyAH2B0slNVeq3AiwluflHpgQ3TAzwNJcuO2AoPyXgBT2EDkdbP1D8B/yFOY+S2hDYmFlI1vhVFkQw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-1.0.4.tgz", + "integrity": "sha512-NDd7FeS3QamVtbgfvu5h7fd1IlbaC4EQ0/pgU4zqE2vdHCmBGsUa0TiM8/TdSeG6BMPC92OOCf8F1ocE/Wkrrg==", "requires": { - "buffer": "^5.5.0", + "buffer": "^5.6.0", "varint": "^5.0.0" } } @@ -2602,16 +2398,6 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -2683,12 +2469,9 @@ "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==" }, "commander": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", - "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", - "requires": { - "graceful-readlink": ">= 1.0.0" - } + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, "component-emitter": { "version": "1.3.0", @@ -2787,12 +2570,12 @@ } }, "create-ecdh": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", - "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", "requires": { "bn.js": "^4.1.0", - "elliptic": "^6.0.0" + "elliptic": "^6.5.3" }, "dependencies": { "bn.js": { @@ -2887,11 +2670,18 @@ "dev": true }, "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } } }, "decamelize": { @@ -2917,13 +2707,6 @@ "make-dir": "^1.0.0", "pify": "^2.3.0", "strip-dirs": "^2.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" - } } }, "decompress-response": { @@ -2997,11 +2780,6 @@ "object-assign": "^4.0.1", "pinkie-promise": "^2.0.0" } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" } } }, @@ -3085,6 +2863,12 @@ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "optional": true + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "optional": true } } }, @@ -3138,12 +2922,6 @@ "requires": { "ms": "2.0.0" } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true } } }, @@ -3195,23 +2973,13 @@ "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" }, "dotenv-flow": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/dotenv-flow/-/dotenv-flow-3.1.0.tgz", - "integrity": "sha512-BMA8vfu2DbAx5x5G3C+tgb1hCbONggZTSpBE7B4yCPG5vziKX/lA3CzsjdGKlPvLxZgTbP1qb+KlWux8pYqsmA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/dotenv-flow/-/dotenv-flow-3.2.0.tgz", + "integrity": "sha512-GEB6RrR4AbqDJvNSFrYHqZ33IKKbzkvLYiD5eo4+9aFXr4Y4G+QaFrB/fNp0y6McWBmvaPn3ZNjIufnj8irCtg==", "requires": { "dotenv": "^8.0.0" } }, - "drbg.js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/drbg.js/-/drbg.js-1.0.1.tgz", - "integrity": "sha1-Pja2xCs3BDgjzbwzLVjzHiRFSAs=", - "requires": { - "browserify-aes": "^1.0.6", - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4" - } - }, "duplexer3": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", @@ -3253,10 +3021,9 @@ } }, "emoji-regex": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.0.0.tgz", - "integrity": "sha512-6p1NII1Vm62wni/VR/cUMauVQoxmLVb9csqQlvLz+hO2gk8U2UYDfXHQSUYIBKmZwAKz867IDqG7B+u0mj+M6w==", - "dev": true + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" }, "encodeurl": { "version": "1.0.2", @@ -3301,19 +3068,20 @@ } }, "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "version": "1.18.0-next.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", + "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", "requires": { "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "has": "^1.0.3", "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", + "is-callable": "^1.2.2", + "is-negative-zero": "^2.0.0", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", "object-keys": "^1.1.1", - "object.assign": "^4.1.0", + "object.assign": "^4.1.1", "string.prototype.trimend": "^1.0.1", "string.prototype.trimstart": "^1.0.1" } @@ -3373,10 +3141,9 @@ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" }, "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "escodegen": { "version": "1.8.1", @@ -3396,13 +3163,23 @@ "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", "dev": true + }, + "source-map": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", + "dev": true, + "optional": true, + "requires": { + "amdefine": ">=0.0.4" + } } } }, "eslint-visitor-keys": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.2.0.tgz", - "integrity": "sha512-WFb4ihckKil6hu3Dp798xdzSfddwKKU3+nGniKF6HfeW6OLd2OUDEPP7TcHtB5+QXOKg2s6B2DaMPE1Nn/kxKQ==" + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==" }, "esprima": { "version": "4.0.1", @@ -3463,6 +3240,13 @@ "requires": { "idna-uts46-hx": "^2.3.1", "js-sha3": "^0.5.7" + }, + "dependencies": { + "js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc=" + } } }, "eth-json-rpc-errors": { @@ -3519,13 +3303,6 @@ "integrity": "sha512-cDcJJSJ9GMAcURiAWO3DxIEhTL/uWqlQnvgKpuYQzYPrt/izuGU+1ntQmHt0IRq6ADoSYHFnB+aCEFIldjhkMQ==", "requires": { "js-sha3": "^0.8.0" - }, - "dependencies": { - "js-sha3": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", - "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" - } } }, "ethereum-common": { @@ -3538,7 +3315,6 @@ "version": "0.1.3", "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "dev": true, "requires": { "@types/pbkdf2": "^3.0.0", "@types/secp256k1": "^4.0.1", @@ -3555,20 +3331,6 @@ "scrypt-js": "^3.0.0", "secp256k1": "^4.0.1", "setimmediate": "^1.0.5" - }, - "dependencies": { - "scrypt-js": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", - "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", - "dev": true - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", - "dev": true - } } }, "ethereum-protocol": { @@ -3657,15 +3419,6 @@ "merkle-patricia-tree": "^2.1.2" }, "dependencies": { - "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "dev": true, - "requires": { - "lodash": "^4.17.14" - } - }, "bn.js": { "version": "4.11.9", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", @@ -3708,9 +3461,9 @@ } }, "ethereumjs-common": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/ethereumjs-common/-/ethereumjs-common-1.5.1.tgz", - "integrity": "sha512-aVUPRLgmXORGXXEVkFYgPhr9TGtpBY2tGhZ9Uh0A3lIUzUDr1x6kQx33SbjPUkLkX3eniPQnIL/2psjkjrOfcQ==" + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/ethereumjs-common/-/ethereumjs-common-1.5.2.tgz", + "integrity": "sha512-hTfZjwGX52GS2jcVO6E2sx4YuFnf0Fhp5ylo4pEPhEffNln7vS59Hr5sLnp3/QCazFLluuBZ+FZ6J5HTp0EqCA==" }, "ethereumjs-tx": { "version": "2.1.2", @@ -3727,59 +3480,32 @@ "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" }, "ethereumjs-util": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.0.tgz", - "integrity": "sha512-vb0XN9J2QGdZGIEKG2vXM+kUdEivUfU6Wmi5y0cg+LRhDYKnXIZ/Lz7XjFbHRR9VIKq2lVGLzGBkA++y2nOdOQ==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", "requires": { "@types/bn.js": "^4.11.3", "bn.js": "^4.11.0", "create-hash": "^1.1.2", - "ethjs-util": "0.1.6", - "keccak": "^2.0.0", - "rlp": "^2.2.3", - "secp256k1": "^3.0.1" - } - }, - "keccak": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/keccak/-/keccak-2.1.0.tgz", - "integrity": "sha512-m1wbJRTo+gWbctZWay9i26v5fFnYkOn7D5PCxJ3fZUGUEb49dE1Pm4BREUYCt/aoO6di7jeoGmhvqN9Nzylm3Q==", - "requires": { - "bindings": "^1.5.0", - "inherits": "^2.0.4", - "nan": "^2.14.0", - "safe-buffer": "^5.2.0" - } - }, - "secp256k1": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-3.8.0.tgz", - "integrity": "sha512-k5ke5avRZbtl9Tqx/SA7CbY3NF6Ro+Sj9cZxezFzuBlLDmyqPiL8hJJ+EmzD8Ig4LUDByHJ3/iPOVoRixs/hmw==", - "requires": { - "bindings": "^1.5.0", - "bip66": "^1.1.5", - "bn.js": "^4.11.8", - "create-hash": "^1.2.0", - "drbg.js": "^1.0.1", "elliptic": "^6.5.2", - "nan": "^2.14.0", - "safe-buffer": "^5.1.2" + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" } } } }, "ethereumjs-util": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.0.2.tgz", - "integrity": "sha512-ATAP02eJLpAlWGfiKQddNrRfZpwXiTFhRN2EM/yLXMCdBW/xjKYblNKcx8GLzzrjXg0ymotck+lam1nuV90arQ==", + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.0.7.tgz", + "integrity": "sha512-vU5rtZBlZsgkTw3o6PDKyB8li2EgLavnAbsKcfsH2YhHH1Le+PP8vEiMnAnvgc1B6uMoaM5GDCrVztBw0Q5K9g==", "requires": { "@types/bn.js": "^4.11.3", "bn.js": "^5.1.2", "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", "ethjs-util": "0.1.6", - "keccak": "^3.0.0", - "rlp": "^2.2.4", - "secp256k1": "^4.0.1" + "rlp": "^2.2.4" } }, "ethereumjs-vm": { @@ -3801,15 +3527,6 @@ "safe-buffer": "^5.1.1" }, "dependencies": { - "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "dev": true, - "requires": { - "lodash": "^4.17.14" - } - }, "bn.js": { "version": "4.11.9", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", @@ -3915,62 +3632,75 @@ "requires": { "pbkdf2": "^3.0.3" } - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true } } }, "ethers": { - "version": "4.0.47", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.47.tgz", - "integrity": "sha512-hssRYhngV4hiDNeZmVU/k5/E8xmLG8UpcNUzg6mb7lqhgpFPH/t7nuv20RjRrEf0gblzvi2XwR5Te+V3ZFc9pQ==", - "dev": true, + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.0-beta.3.tgz", + "integrity": "sha512-YYPogooSknTwvHg3+Mv71gM/3Wcrx+ZpCzarBj3mqs9njjRkrOo2/eufzhHloOCo3JSoNI4TQJJ6yU5ABm3Uog==", "requires": { + "@types/node": "^10.3.2", "aes-js": "3.0.0", "bn.js": "^4.4.0", - "elliptic": "6.5.2", + "elliptic": "6.3.3", "hash.js": "1.1.3", "js-sha3": "0.5.7", - "scrypt-js": "2.0.4", + "scrypt-js": "2.0.3", "setimmediate": "1.0.4", "uuid": "2.0.1", "xmlhttprequest": "1.8.0" }, "dependencies": { + "@types/node": { + "version": "10.17.44", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.44.tgz", + "integrity": "sha512-vHPAyBX1ffLcy4fQHmDyIUMUb42gHZjPHU66nhvbMzAWJqHnySGZ6STwN3rwrnSd1FHB0DI/RWgGELgKSYRDmw==" + }, "bn.js": { "version": "4.11.9", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", - "dev": true + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" }, "elliptic": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz", - "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==", - "dev": true, + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.3.3.tgz", + "integrity": "sha1-VILZZG1UvLif19mU/J4ulWiHbj8=", "requires": { "bn.js": "^4.4.0", "brorand": "^1.0.1", "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" + "inherits": "^2.0.1" } }, "hash.js": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", - "dev": true, "requires": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.0" } + }, + "js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc=" + }, + "scrypt-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.3.tgz", + "integrity": "sha1-uwBAvgMEPamgEqLOqfyfhSz8h9Q=" + }, + "setimmediate": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz", + "integrity": "sha1-IOgd5iLUoCWIzgyNqJc8vPHTE48=" + }, + "uuid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", + "integrity": "sha1-wqMN7bPlNdcsz4LjQ5QaULqFM6w=" } } }, @@ -4035,39 +3765,6 @@ "optional": true, "requires": { "fill-range": "^2.1.0" - }, - "dependencies": { - "fill-range": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", - "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", - "optional": true, - "requires": { - "is-number": "^2.1.0", - "isobject": "^2.0.0", - "randomatic": "^3.0.0", - "repeat-element": "^1.1.2", - "repeat-string": "^1.5.2" - } - }, - "is-number": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", - "optional": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "optional": true, - "requires": { - "is-buffer": "^1.1.5" - } - } } }, "express": { @@ -4115,11 +3812,6 @@ "ms": "2.0.0" } }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -4136,9 +3828,9 @@ }, "dependencies": { "type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz", - "integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.1.0.tgz", + "integrity": "sha512-G9absDWvhAWCV2gmF1zKud3OyC61nZDwWvBL2DApaVFogI07CprggiQAOOjvp2NRjYWFzPyu7vwtDrQFq8jeSA==" } } }, @@ -4175,14 +3867,6 @@ "optional": true, "requires": { "is-extglob": "^1.0.0" - }, - "dependencies": { - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "optional": true - } } }, "extract-comments": { @@ -4210,14 +3894,14 @@ } }, "fast-deep-equal": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", - "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "fast-glob": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.3.tgz", - "integrity": "sha512-fWSEEcoqcYqlFJrpSH5dJTwv6o0r+2bLAmnlne8OQMbFhpSTQXA8Ngp6q1DGA4B+eewHeuH5ndZeiV2qyXXNsA==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", + "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", @@ -4226,6 +3910,75 @@ "merge2": "^1.3.0", "micromatch": "^4.0.2", "picomatch": "^2.2.1" + }, + "dependencies": { + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + } } }, "fast-json-stable-stringify": { @@ -4246,9 +3999,9 @@ "dev": true }, "fastq": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", - "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.9.0.tgz", + "integrity": "sha512-i7FVWL8HhVY+CTkwFxkN2mk3h+787ixS5S63eb78diVRc1MCssarHq3W5cj0av7YDSwmaV928RNag+U1etRQ7w==", "dev": true, "requires": { "reusify": "^1.0.4" @@ -4288,11 +4041,16 @@ "optional": true }, "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", + "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "optional": true, "requires": { - "to-regex-range": "^5.0.1" + "is-number": "^2.1.0", + "isobject": "^2.0.0", + "randomatic": "^3.0.0", + "repeat-element": "^1.1.2", + "repeat-string": "^1.5.2" } }, "finalhandler": { @@ -4316,11 +4074,6 @@ "requires": { "ms": "2.0.0" } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" } } }, @@ -4333,17 +4086,17 @@ } }, "flat": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", - "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.1.tgz", + "integrity": "sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA==", "requires": { "is-buffer": "~2.0.3" }, "dependencies": { "is-buffer": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", - "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==" + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" } } }, @@ -4412,14 +4165,15 @@ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" }, "fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=", "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" } }, "fs-minipass": { @@ -4462,16 +4216,45 @@ "dev": true }, "ganache-cli": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/ganache-cli/-/ganache-cli-6.9.1.tgz", - "integrity": "sha512-VPBumkNUZzXDRQwVOby5YyQpd5t1clkr06xMgB28lZdEIn5ht1GMwUskOTFOAxdkQ4J12IWP0gdeacVRGowqbA==", + "version": "6.12.1", + "resolved": "https://registry.npmjs.org/ganache-cli/-/ganache-cli-6.12.1.tgz", + "integrity": "sha512-zoefZLQpQyEJH9jgtVYgM+ENFLAC9iwys07IDCsju2Ieq9KSTLH89RxSP4bhizXKV/h/+qaWpfyCBGWnBfqgIQ==", "dev": true, "requires": { - "ethereumjs-util": "6.1.0", + "ethereumjs-util": "6.2.1", "source-map-support": "0.5.12", "yargs": "13.2.4" }, "dependencies": { + "@types/bn.js": { + "version": "4.11.6", + "bundled": true, + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/node": { + "version": "14.11.2", + "bundled": true, + "dev": true + }, + "@types/pbkdf2": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/secp256k1": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "requires": { + "@types/node": "*" + } + }, "ansi-regex": { "version": "4.1.0", "bundled": true, @@ -4485,24 +4268,21 @@ "color-convert": "^1.9.0" } }, - "bindings": { - "version": "1.5.0", - "bundled": true, - "dev": true, - "requires": { - "file-uri-to-path": "1.0.0" - } - }, - "bip66": { - "version": "1.1.5", + "base-x": { + "version": "3.0.8", "bundled": true, "dev": true, "requires": { "safe-buffer": "^5.0.1" } }, + "blakejs": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, "bn.js": { - "version": "4.11.8", + "version": "4.11.9", "bundled": true, "dev": true }, @@ -4524,6 +4304,24 @@ "safe-buffer": "^5.0.1" } }, + "bs58": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "requires": { + "base-x": "^3.0.2" + } + }, + "bs58check": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "requires": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, "buffer-from": { "version": "1.1.1", "bundled": true, @@ -4613,18 +4411,8 @@ "bundled": true, "dev": true }, - "drbg.js": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "browserify-aes": "^1.0.6", - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4" - } - }, "elliptic": { - "version": "6.5.0", + "version": "6.5.3", "bundled": true, "dev": true, "requires": { @@ -4643,25 +4431,47 @@ "dev": true }, "end-of-stream": { - "version": "1.4.1", + "version": "1.4.4", "bundled": true, "dev": true, "requires": { "once": "^1.4.0" } }, - "ethereumjs-util": { - "version": "6.1.0", + "ethereum-cryptography": { + "version": "0.1.3", "bundled": true, "dev": true, "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "ethereumjs-util": { + "version": "6.2.1", + "bundled": true, + "dev": true, + "requires": { + "@types/bn.js": "^4.11.3", "bn.js": "^4.11.0", "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", "ethjs-util": "0.1.6", - "keccak": "^1.0.2", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" + "rlp": "^2.2.3" } }, "ethjs-util": { @@ -4696,11 +4506,6 @@ "strip-eof": "^1.0.0" } }, - "file-uri-to-path": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, "find-up": { "version": "3.0.0", "bundled": true, @@ -4723,12 +4528,13 @@ } }, "hash-base": { - "version": "3.0.4", + "version": "3.1.0", "bundled": true, "dev": true, "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" } }, "hash.js": { @@ -4781,14 +4587,12 @@ "dev": true }, "keccak": { - "version": "1.4.0", + "version": "3.0.1", "bundled": true, "dev": true, "requires": { - "bindings": "^1.2.1", - "inherits": "^2.0.3", - "nan": "^2.2.1", - "safe-buffer": "^5.1.0" + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" } }, "lcid": { @@ -4851,13 +4655,18 @@ "bundled": true, "dev": true }, - "nan": { - "version": "2.14.0", + "nice-try": { + "version": "1.0.5", "bundled": true, "dev": true }, - "nice-try": { - "version": "1.0.5", + "node-addon-api": { + "version": "2.0.2", + "bundled": true, + "dev": true + }, + "node-gyp-build": { + "version": "4.2.3", "bundled": true, "dev": true }, @@ -4903,7 +4712,7 @@ "dev": true }, "p-limit": { - "version": "2.2.0", + "version": "2.3.0", "bundled": true, "dev": true, "requires": { @@ -4933,6 +4742,18 @@ "bundled": true, "dev": true }, + "pbkdf2": { + "version": "3.1.1", + "bundled": true, + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, "pump": { "version": "3.0.0", "bundled": true, @@ -4942,6 +4763,24 @@ "once": "^1.3.1" } }, + "randombytes": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "readable-stream": { + "version": "3.6.0", + "bundled": true, + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, "require-directory": { "version": "2.1.1", "bundled": true, @@ -4962,36 +4801,35 @@ } }, "rlp": { - "version": "2.2.3", + "version": "2.2.6", "bundled": true, "dev": true, "requires": { - "bn.js": "^4.11.1", - "safe-buffer": "^5.1.1" + "bn.js": "^4.11.1" } }, "safe-buffer": { - "version": "5.2.0", + "version": "5.2.1", + "bundled": true, + "dev": true + }, + "scrypt-js": { + "version": "3.0.1", "bundled": true, "dev": true }, "secp256k1": { - "version": "3.7.1", + "version": "4.0.2", "bundled": true, "dev": true, "requires": { - "bindings": "^1.5.0", - "bip66": "^1.1.5", - "bn.js": "^4.11.8", - "create-hash": "^1.2.0", - "drbg.js": "^1.0.1", - "elliptic": "^6.4.1", - "nan": "^2.14.0", - "safe-buffer": "^5.1.2" + "elliptic": "^6.5.2", + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" } }, "semver": { - "version": "5.7.0", + "version": "5.7.1", "bundled": true, "dev": true }, @@ -5000,6 +4838,11 @@ "bundled": true, "dev": true }, + "setimmediate": { + "version": "1.0.5", + "bundled": true, + "dev": true + }, "sha.js": { "version": "2.4.11", "bundled": true, @@ -5023,7 +4866,7 @@ "dev": true }, "signal-exit": { - "version": "3.0.2", + "version": "3.0.3", "bundled": true, "dev": true }, @@ -5051,6 +4894,14 @@ "strip-ansi": "^5.1.0" } }, + "string_decoder": { + "version": "1.3.0", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, "strip-ansi": { "version": "5.2.0", "bundled": true, @@ -5072,6 +4923,11 @@ "is-hex-prefixed": "1.0.0" } }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, "which": { "version": "1.3.1", "bundled": true, @@ -5124,7 +4980,7 @@ } }, "yargs-parser": { - "version": "13.1.1", + "version": "13.1.2", "bundled": true, "dev": true, "requires": { @@ -5144,6 +5000,16 @@ "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=" }, + "get-intrinsic": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.1.tgz", + "integrity": "sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, "get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", @@ -5174,6 +5040,37 @@ "requires": { "chalk": "^2.4.2", "node-emoji": "^1.10.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, "glob": { @@ -5197,40 +5094,15 @@ "requires": { "glob-parent": "^2.0.0", "is-glob": "^2.0.0" - }, - "dependencies": { - "glob-parent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", - "optional": true, - "requires": { - "is-glob": "^2.0.0" - } - }, - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "optional": true - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "optional": true, - "requires": { - "is-extglob": "^1.0.0" - } - } } }, "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "optional": true, "requires": { - "is-glob": "^4.0.1" + "is-glob": "^2.0.0" } }, "global": { @@ -5260,6 +5132,14 @@ "ini": "^1.3.5", "kind-of": "^6.0.2", "which": "^1.3.1" + }, + "dependencies": { + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + } } }, "globals": { @@ -5281,6 +5161,14 @@ "ignore": "^5.1.1", "merge2": "^1.2.3", "slash": "^3.0.0" + }, + "dependencies": { + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + } } }, "got": { @@ -5306,11 +5194,6 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" }, - "graceful-readlink": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", - "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" - }, "growl": { "version": "1.10.5", "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", @@ -5343,11 +5226,11 @@ "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" }, "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", "requires": { - "ajv": "^6.5.5", + "ajv": "^6.12.3", "har-schema": "^2.0.0" } }, @@ -5365,13 +5248,6 @@ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "requires": { "ansi-regex": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - } } }, "has-flag": { @@ -5465,6 +5341,18 @@ "inherits": "^2.0.4", "readable-stream": "^3.6.0", "safe-buffer": "^5.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } } }, "hash.js": { @@ -5563,9 +5451,9 @@ } }, "ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" }, "ignore": { "version": "5.1.8", @@ -5625,17 +5513,6 @@ "optional": true, "requires": { "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "optional": true, - "requires": { - "is-buffer": "^1.1.5" - } - } } }, "is-arguments": { @@ -5659,9 +5536,17 @@ "optional": true }, "is-callable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", - "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==" + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", + "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==" + }, + "is-core-module": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.1.0.tgz", + "integrity": "sha512-YcV7BgVMRFRua2FqQzKtTDMz8iCuLEyGKjr70q8Zm1yy2qKcurbFEd79PAdHV77oL3NrAaOVQIbMmiHQCHB7ZA==", + "requires": { + "has": "^1.0.3" + } }, "is-data-descriptor": { "version": "0.1.4", @@ -5670,17 +5555,6 @@ "optional": true, "requires": { "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "optional": true, - "requires": { - "is-buffer": "^1.1.5" - } - } } }, "is-date-object": { @@ -5729,9 +5603,10 @@ "optional": true }, "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "optional": true }, "is-finite": { "version": "1.1.0", @@ -5745,10 +5620,9 @@ "dev": true }, "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" }, "is-function": { "version": "1.0.2", @@ -5761,11 +5635,12 @@ "integrity": "sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw==" }, "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "optional": true, "requires": { - "is-extglob": "^2.1.1" + "is-extglob": "^1.0.0" } }, "is-hex-prefixed": { @@ -5786,10 +5661,19 @@ "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", "integrity": "sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=" }, + "is-negative-zero": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz", + "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=" + }, "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "optional": true, + "requires": { + "kind-of": "^3.0.2" + } }, "is-object": { "version": "1.0.1", @@ -5831,9 +5715,9 @@ "optional": true }, "is-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", - "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", "requires": { "has-symbols": "^1.0.1" } @@ -5865,6 +5749,26 @@ "es-abstract": "^1.17.4", "foreach": "^2.0.5", "has-symbols": "^1.0.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", + "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } } }, "is-typedarray": { @@ -5912,9 +5816,9 @@ } }, "js-sha3": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", - "integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc=" + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" }, "js-tokens": { "version": "3.0.2", @@ -5922,10 +5826,9 @@ "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" }, "js-yaml": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", - "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", - "dev": true, + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -5947,9 +5850,9 @@ "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" }, "json-rpc-engine": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-5.3.0.tgz", - "integrity": "sha512-+diJ9s8rxB+fbJhT7ZEf8r8spaLRignLd8jTgQ/h5JSGppAHGtNMZtCoabipCaleR1B3GTGxbXBOqhaJSGmPGQ==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-5.4.0.tgz", + "integrity": "sha512-rAffKbPoNDjuRnXkecTjnsE3xLLrb00rEkdgalINhaYVYIxDwWtvYBr9UFbhTvPB1B2qUOLoFd/cV6f4Q7mh7g==", "dev": true, "requires": { "eth-rpc-errors": "^3.0.0", @@ -5992,9 +5895,9 @@ "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" }, "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", "requires": { "graceful-fs": "^4.1.6" } @@ -6006,9 +5909,9 @@ "dev": true }, "jsonschema": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.2.6.tgz", - "integrity": "sha512-SqhURKZG07JyKKeo/ir24QnS4/BV7a6gQy93bUSe4lUdNp0QNpIz2c9elWJQ9dpc5cQYY6cvCzgRwy0MQCLyqA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.0.tgz", + "integrity": "sha512-/YgW6pRMr6M7C+4o8kS+B/2myEpHCrxO4PEWnqJNBFMjn7EWXqlQ4tGwL6xTHeRplwuZmcAncdvfOad1nT2yMw==", "dev": true }, "jsprim": { @@ -6023,9 +5926,9 @@ } }, "keccak": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.0.tgz", - "integrity": "sha512-/4h4FIfFEpTEuySXi/nVFM5rqSKPnnhI7cL4K3MFSwoI3VyM7AhPSq3SsysARtnEBEeIKMBUWD8cTh9nHE8AkA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.1.tgz", + "integrity": "sha512-epq90L9jlFWCW7+pQa6JOnKn2Xgl2mtI664seYR6MHskvI9agt7AnDqmAlp9TqU4/caMYbA08Hi5DMZAl5zdkA==", "requires": { "node-addon-api": "^2.0.0", "node-gyp-build": "^4.2.0" @@ -6040,9 +5943,13 @@ } }, "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } }, "klaw": { "version": "1.3.1", @@ -6221,6 +6128,34 @@ "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", "requires": { "chalk": "^2.4.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } } }, "loose-envify": { @@ -6361,6 +6296,12 @@ "semaphore": ">=1.0.1" }, "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, "bn.js": { "version": "4.11.9", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", @@ -6381,46 +6322,6 @@ "rlp": "^2.0.0", "safe-buffer": "^5.1.1" } - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - } - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - } - } } } }, @@ -6430,13 +6331,24 @@ "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" }, "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "optional": true, "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" } }, "miller-rabin": { @@ -6548,9 +6460,12 @@ } }, "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } }, "mkdirp-promise": { "version": "5.0.1", @@ -6601,9 +6516,17 @@ } }, "binary-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", - "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==" + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } }, "chokidar": { "version": "3.3.0", @@ -6628,10 +6551,13 @@ "ms": "^2.1.1" } }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } }, "fsevents": { "version": "2.1.3", @@ -6652,6 +6578,14 @@ "path-is-absolute": "^1.0.0" } }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "requires": { + "is-glob": "^4.0.1" + } + }, "is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -6660,22 +6594,23 @@ "binary-extensions": "^2.0.0" } }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "is-extglob": "^2.1.1" } }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "requires": { - "minimist": "^1.2.5" - } + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, "ms": { "version": "2.1.1", @@ -6687,6 +6622,17 @@ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, "readdirp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", @@ -6702,18 +6648,26 @@ "requires": { "has-flag": "^3.0.0" } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } } } }, "mock-fs": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.12.0.tgz", - "integrity": "sha512-/P/HtrlvBxY4o/PzXY9cCNBrdylDNxg7gnrv2sMNxj+UJ2m8jSpl0/A6fuJeNAWr99ZvGWH8XCbE0vmnM5KupQ==" + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.13.0.tgz", + "integrity": "sha512-DD0vOdofJdoaRNtnWcrXe6RQbpHkPPmtqGq14uRX0F8ZKJ5nv89CVTYl/BZdppDxBDaV0hl75htg3abpEWlPZA==" }, "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "multibase": { "version": "0.6.1", @@ -6733,9 +6687,9 @@ } }, "multihashes": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/multihashes/-/multihashes-0.4.19.tgz", - "integrity": "sha512-ej74GAfA20imjj00RO5h34aY3pGUFyzn9FJZFWwdeUHlHTkKmv90FrNpvYT4jYf1XXCy5O/5EjVnxTaESgOM6A==", + "version": "0.4.21", + "resolved": "https://registry.npmjs.org/multihashes/-/multihashes-0.4.21.tgz", + "integrity": "sha512-uVSvmeCWf36pU2nB4/1kzYZjsXD9vofZKpgudqkceYY5g2aZZXJ5r9lxuzoRLl1OAp28XljXsEJ/X/85ZsKmKw==", "requires": { "buffer": "^5.5.0", "multibase": "^0.7.0", @@ -6754,9 +6708,9 @@ } }, "nan": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", - "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==" + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", + "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==" }, "nano-json-stream-parser": { "version": "0.1.2", @@ -6793,6 +6747,12 @@ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", "optional": true + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "optional": true } } }, @@ -6802,9 +6762,9 @@ "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" }, "neo-async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", - "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, "next-tick": { @@ -6813,9 +6773,9 @@ "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" }, "node-addon-api": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.1.tgz", - "integrity": "sha512-2WVfwRfIr1AVn3dRq4yRc2Hn35ND+mPJH6inC6bjpYCZVrpXPB4j3T6i//OGVfqVsR1t/X/axRulDsheq4F0LQ==" + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==" }, "node-emoji": { "version": "1.10.0", @@ -6833,13 +6793,6 @@ "requires": { "object.getownpropertydescriptors": "^2.0.3", "semver": "^5.7.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } } }, "node-fetch": { @@ -6853,9 +6806,9 @@ } }, "node-gyp-build": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.2.2.tgz", - "integrity": "sha512-Lqh7mrByWCM8Cf9UPqpeoVBBo5Ugx+RKu885GAzmLBVYjeywScxHXPGLa4JfYNZmcNGwzR0Glu5/9GaQZMFqyA==" + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.2.3.tgz", + "integrity": "sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg==" }, "nopt": { "version": "3.0.6", @@ -6925,30 +6878,21 @@ "requires": { "is-descriptor": "^0.1.0" } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "optional": true, - "requires": { - "is-buffer": "^1.1.5" - } } } }, "object-inspect": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", - "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==" }, "object-is": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.2.tgz", - "integrity": "sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.3.tgz", + "integrity": "sha512-teyqLvFWzLkq5B9ki8FVWA902UER2qkxmdA4nLf+wjOLAWgxzCWZNCxpDq9MvE8MmhWNr+I8w3BN49Vx36Y6Xg==", "requires": { "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" + "es-abstract": "^1.18.0-next.1" } }, "object-keys": { @@ -6974,14 +6918,14 @@ } }, "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" } }, "object.getownpropertydescriptors": { @@ -6991,6 +6935,26 @@ "requires": { "define-properties": "^1.1.3", "es-abstract": "^1.17.0-next.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", + "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } } }, "object.omit": { @@ -7076,16 +7040,6 @@ "graceful-fs": "^4.1.4", "mkdirp": "^0.5.1", "object-assign": "^4.1.0" - }, - "dependencies": { - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "requires": { - "minimist": "^1.2.5" - } - } } }, "p-cancelable": { @@ -7128,13 +7082,12 @@ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" }, "parse-asn1": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", - "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", "requires": { - "asn1.js": "^4.0.0", + "asn1.js": "^5.2.0", "browserify-aes": "^1.0.0", - "create-hash": "^1.1.0", "evp_bytestokey": "^1.0.0", "pbkdf2": "^3.0.3", "safe-buffer": "^5.1.1" @@ -7156,23 +7109,6 @@ "is-dotfile": "^1.0.0", "is-extglob": "^1.0.0", "is-glob": "^2.0.0" - }, - "dependencies": { - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "optional": true - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "optional": true, - "requires": { - "is-extglob": "^1.0.0" - } - } } }, "parse-headers": { @@ -7223,9 +7159,9 @@ "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=" }, "pbkdf2": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.0.tgz", - "integrity": "sha512-wHMFZ6HTLGlB9f/WsQBs5OwMQJoLXYuJUzbA+j+hRBf7+Y8KcXpatzIviIcTy1OAyhWQp08nyiPO8Dnv0z4Sww==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz", + "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==", "requires": { "create-hash": "^1.1.2", "create-hmac": "^1.1.4", @@ -7250,10 +7186,9 @@ "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==" }, "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" }, "pinkie": { "version": "2.0.4", @@ -7298,18 +7233,18 @@ "optional": true }, "prettier": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.5.tgz", - "integrity": "sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.1.2.tgz", + "integrity": "sha512-16c7K+x4qVlJg9rEbXl7HEGmQyZlG4R9AgP+oHKRMsMsuk8s+ATStlf1NpDqyBI1HpVyfjLOeMhH2LvuNvV5Vg==", "dev": true }, "prettier-plugin-solidity": { - "version": "1.0.0-alpha.52", - "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.0.0-alpha.52.tgz", - "integrity": "sha512-3Ep3GP+OHbDltvXX60GauvsFLS4TliGLohkWZ5CLGjKeUIikYsB7jlkiRMgVS2K+/eisu4O09hRNYdBaFqcX+g==", + "version": "1.0.0-alpha.59", + "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.0.0-alpha.59.tgz", + "integrity": "sha512-6cE0SWaiYCBoJY4clCfsbWlEEOU4K42Ny6Tg4Jwprgts/q+AVfYnPQ5coRs7zIjYzc4RVspifYPeh+oAg8RpLw==", "dev": true, "requires": { - "@solidity-parser/parser": "^0.6.1", + "@solidity-parser/parser": "^0.8.1", "dir-to-object": "^2.0.0", "emoji-regex": "^9.0.0", "escape-string-regexp": "^4.0.0", @@ -7317,6 +7252,66 @@ "prettier": "^2.0.5", "semver": "^7.3.2", "string-width": "^4.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.0.tgz", + "integrity": "sha512-DNc3KFPK18bPdElMJnf/Pkv5TXhxFU3YFDEuGLDRtPmV4rkmCjBkCSEp22u6rBHdSN9Vlp/GK7k98prmE1Jgug==", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + } + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } } }, "private": { @@ -7429,6 +7424,12 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", "optional": true + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "optional": true } } }, @@ -7471,13 +7472,24 @@ } }, "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } } }, "readdirp": { @@ -7747,6 +7759,12 @@ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "optional": true }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "optional": true + }, "micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", @@ -7767,52 +7785,6 @@ "snapdragon": "^0.8.1", "to-regex": "^3.0.2" } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "optional": true - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "optional": true - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "optional": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } } } }, @@ -7915,11 +7887,6 @@ "version": "6.5.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" } } }, @@ -7939,10 +7906,13 @@ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" }, "resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", - "dev": true + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz", + "integrity": "sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA==", + "requires": { + "is-core-module": "^2.0.0", + "path-parse": "^1.0.6" + } }, "resolve-url": { "version": "0.2.1", @@ -7988,9 +7958,9 @@ } }, "rlp": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.5.tgz", - "integrity": "sha512-y1QxTQOp0OZnjn19FxBmped4p+BSKPHwGndaqrESseyd2xXZtcgR3yuTIosh8CaMaOii9SKIYerBXnV/CpJ3qw==", + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.6.tgz", + "integrity": "sha512-HAfAmL6SDYNWPUOJNrM500x4Thn4PZsEy5pijPh40U9WfNk0z15hUYzO9xVIMAdIHdFtD8CBDHd75Td1g36Mjg==", "requires": { "bn.js": "^4.11.1" }, @@ -8003,9 +7973,9 @@ } }, "run-parallel": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", - "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.10.tgz", + "integrity": "sha512-zb/1OuZ6flOlH6tQyMPUrE3x3Ulxjlo9WIVXR4yVYi4H9UXQaeIsPbLn2R3O3vQCnDKkAl2qHiuocKKX4Tz/Sw==", "dev": true }, "rustbn.js": { @@ -8064,6 +8034,12 @@ "wordwrap": "^1.0.0" }, "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, "esprima": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", @@ -8089,14 +8065,11 @@ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", "dev": true }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true }, "supports-color": { "version": "3.2.3", @@ -8110,10 +8083,9 @@ } }, "scrypt-js": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.4.tgz", - "integrity": "sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw==", - "dev": true + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==" }, "scrypt-shim": { "version": "github:web3-js/scrypt-shim#aafdadda13e660e25e1c525d1f5b2443f5eb1ebb", @@ -8138,9 +8110,9 @@ "integrity": "sha512-1CdSqHQowJBnMAFyPEBRfqag/YP9OF394FV+4YREIJX4ljD7OxvQRDayyoyyCk+senRjSkP6VnUNQmVQqB6g7w==" }, "secp256k1": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.1.tgz", - "integrity": "sha512-iGRjbGAKfXMqhtdkkuNxsgJQfJO8Oo78Rm7DAvsG3XKngq+nJIOGqrCSXcQqIVsmCj0wFanE5uTKFxV3T9j2wg==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.2.tgz", + "integrity": "sha512-UDar4sKvWAksIlfX3xIaQReADn+WFnHvbVujpcbr+9Sf/69odMwy2MUsz5CKLQgX9nsIyrjuxL2imVyoNHa3fg==", "requires": { "elliptic": "^6.5.2", "node-addon-api": "^2.0.0", @@ -8148,11 +8120,11 @@ } }, "seek-bzip": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.5.tgz", - "integrity": "sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w=", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.6.tgz", + "integrity": "sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ==", "requires": { - "commander": "~2.8.1" + "commander": "^2.8.1" } }, "semaphore": { @@ -8162,10 +8134,9 @@ "dev": true }, "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" }, "send": { "version": "0.17.1", @@ -8267,9 +8238,9 @@ } }, "setimmediate": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz", - "integrity": "sha1-IOgd5iLUoCWIzgyNqJc8vPHTE48=" + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" }, "setprototypeof": { "version": "1.1.1", @@ -8297,9 +8268,9 @@ } }, "simple-concat": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz", - "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" }, "simple-get": { "version": "2.8.1", @@ -8312,10 +8283,9 @@ } }, "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" }, "snapdragon": { "version": "0.8.2", @@ -8359,18 +8329,6 @@ "requires": { "is-extendable": "^0.1.0" } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "optional": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "optional": true } } }, @@ -8428,6 +8386,12 @@ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "optional": true + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "optional": true } } }, @@ -8438,17 +8402,6 @@ "optional": true, "requires": { "kind-of": "^3.2.0" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "optional": true, - "requires": { - "is-buffer": "^1.1.5" - } - } } }, "solc": { @@ -8470,52 +8423,22 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==" - }, - "fs-extra": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", - "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=", - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0", - "path-is-absolute": "^1.0.0", - "rimraf": "^2.2.8" - } - }, - "js-sha3": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", - "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" - }, - "jsonfile": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" } } }, "solidity-coverage": { - "version": "0.7.7", - "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.7.7.tgz", - "integrity": "sha512-hD043l+Hy8cNMqrI6k5wZNEc7ceVJIWaWztE8D7u8QqbaObZldpknDJPRXHnRGniI5t6HeOQ+8F4ifiNCn2BeA==", + "version": "0.7.11", + "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.7.11.tgz", + "integrity": "sha512-HtBhXNTK2pO6hj82lf3txZ8afoyIGSmduJHJSoeZ71RjiuNzjGFj4duEZY/kfqxYSq1yARERC6jOTZGfIAeRyA==", "dev": true, "requires": { - "@solidity-parser/parser": "^0.6.0", + "@solidity-parser/parser": "^0.7.0", "@truffle/provider": "^0.1.17", "chalk": "^2.4.2", "death": "^1.1.0", "detect-port": "^1.3.0", "fs-extra": "^8.1.0", - "ganache-cli": "6.9.0", + "ganache-cli": "^6.11.0", "ghost-testrpc": "^0.0.2", "global-modules": "^2.0.0", "globby": "^10.0.1", @@ -8526,1077 +8449,76 @@ "recursive-readdir": "^2.2.2", "sc-istanbul": "^0.4.5", "shelljs": "^0.8.3", - "web3": "1.2.6" + "web3": "^1.3.0" }, "dependencies": { - "@types/node": { - "version": "12.12.47", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.47.tgz", - "integrity": "sha512-yzBInQFhdY8kaZmqoL2+3U5dSTMrKaYcb561VU+lDzAYvqt+2lojvBEy+hmpSNuXnPTx7m9+04CzWYOUqWME2A==", + "@solidity-parser/parser": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.7.1.tgz", + "integrity": "sha512-5ma2uuwPAEX1TPl2rAPAAuGlBkKnn2oUKQvnhTFlDIB8U/KDWX77FpHtL6Rcz+OwqSCWx9IClxACgyIEJ/GhIw==", "dev": true }, - "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true }, - "eth-lib": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.7.tgz", - "integrity": "sha1-L5Pxex4jrsN1nNSj/iDBKGo/wco=", + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { - "bn.js": "^4.11.6", - "elliptic": "^6.4.0", - "xhr-request-promise": "^0.1.2" - } - }, - "ethers": { - "version": "4.0.0-beta.3", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.0-beta.3.tgz", - "integrity": "sha512-YYPogooSknTwvHg3+Mv71gM/3Wcrx+ZpCzarBj3mqs9njjRkrOo2/eufzhHloOCo3JSoNI4TQJJ6yU5ABm3Uog==", - "dev": true, - "requires": { - "@types/node": "^10.3.2", - "aes-js": "3.0.0", - "bn.js": "^4.4.0", - "elliptic": "6.3.3", - "hash.js": "1.1.3", - "js-sha3": "0.5.7", - "scrypt-js": "2.0.3", - "setimmediate": "1.0.4", - "uuid": "2.0.1", - "xmlhttprequest": "1.8.0" - }, - "dependencies": { - "@types/node": { - "version": "10.17.26", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.26.tgz", - "integrity": "sha512-myMwkO2Cr82kirHY8uknNRHEVtn0wV3DTQfkrjx17jmkstDRZ24gNUdl8AHXVyVclTYI/bNjgTPTAWvWLqXqkw==", - "dev": true - }, - "elliptic": { - "version": "6.3.3", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.3.3.tgz", - "integrity": "sha1-VILZZG1UvLif19mU/J4ulWiHbj8=", - "dev": true, - "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "inherits": "^2.0.1" - } - } - } - }, - "ganache-cli": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/ganache-cli/-/ganache-cli-6.9.0.tgz", - "integrity": "sha512-ZdL6kPrApXF/O+f6uU431OJcwxMk69H3KPDSHHrMP82ZvZRNpDHbR+rVv7XX/YUeoQ5q6nZ2AFiGiFAVn9pfzA==", - "dev": true, - "requires": { - "ethereumjs-util": "6.1.0", - "source-map-support": "0.5.12", - "yargs": "13.2.4" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "bundled": true, - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "bundled": true, - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "bindings": { - "version": "1.5.0", - "bundled": true, - "dev": true, - "requires": { - "file-uri-to-path": "1.0.0" - } - }, - "bip66": { - "version": "1.1.5", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "bn.js": { - "version": "4.11.8", - "bundled": true, - "dev": true - }, - "brorand": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "browserify-aes": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "requires": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "buffer-from": { - "version": "1.1.1", - "bundled": true, - "dev": true - }, - "buffer-xor": { - "version": "1.0.3", - "bundled": true, - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "bundled": true, - "dev": true - }, - "cipher-base": { - "version": "1.0.4", - "bundled": true, - "dev": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "cliui": { - "version": "5.0.0", - "bundled": true, - "dev": true, - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } - }, - "color-convert": { - "version": "1.9.3", - "bundled": true, - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "bundled": true, - "dev": true - }, - "create-hash": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "requires": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "create-hmac": { - "version": "1.1.7", - "bundled": true, - "dev": true, - "requires": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "cross-spawn": { - "version": "6.0.5", - "bundled": true, - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "decamelize": { - "version": "1.2.0", - "bundled": true, - "dev": true - }, - "drbg.js": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "browserify-aes": "^1.0.6", - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4" - } - }, - "elliptic": { - "version": "6.5.0", - "bundled": true, - "dev": true, - "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" - } - }, - "emoji-regex": { - "version": "7.0.3", - "bundled": true, - "dev": true - }, - "end-of-stream": { - "version": "1.4.1", - "bundled": true, - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "ethereumjs-util": { - "version": "6.1.0", - "bundled": true, - "dev": true, - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "ethjs-util": "0.1.6", - "keccak": "^1.0.2", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" - } - }, - "ethjs-util": { - "version": "0.1.6", - "bundled": true, - "dev": true, - "requires": { - "is-hex-prefixed": "1.0.0", - "strip-hex-prefix": "1.0.0" - } - }, - "evp_bytestokey": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "requires": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, - "execa": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "file-uri-to-path": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "find-up": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "get-caller-file": { - "version": "2.0.5", - "bundled": true, - "dev": true - }, - "get-stream": { - "version": "4.1.0", - "bundled": true, - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "hash-base": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "hash.js": { - "version": "1.1.7", - "bundled": true, - "dev": true, - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "hmac-drbg": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "inherits": { - "version": "2.0.4", - "bundled": true, - "dev": true - }, - "invert-kv": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "is-hex-prefixed": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "is-stream": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "isexe": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "keccak": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "requires": { - "bindings": "^1.2.1", - "inherits": "^2.0.3", - "nan": "^2.2.1", - "safe-buffer": "^5.1.0" - } - }, - "lcid": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "invert-kv": "^2.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "map-age-cleaner": { - "version": "0.1.3", - "bundled": true, - "dev": true, - "requires": { - "p-defer": "^1.0.0" - } - }, - "md5.js": { - "version": "1.3.5", - "bundled": true, - "dev": true, - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "mem": { - "version": "4.3.0", - "bundled": true, - "dev": true, - "requires": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^2.0.0", - "p-is-promise": "^2.0.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "bundled": true, - "dev": true - }, - "minimalistic-assert": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "nan": { - "version": "2.14.0", - "bundled": true, - "dev": true - }, - "nice-try": { - "version": "1.0.5", - "bundled": true, - "dev": true - }, - "npm-run-path": { - "version": "2.0.2", - "bundled": true, - "dev": true, - "requires": { - "path-key": "^2.0.0" - } - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "os-locale": { - "version": "3.1.0", - "bundled": true, - "dev": true, - "requires": { - "execa": "^1.0.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" - } - }, - "p-defer": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "p-finally": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "p-is-promise": { - "version": "2.1.0", - "bundled": true, - "dev": true - }, - "p-limit": { - "version": "2.2.0", - "bundled": true, - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "bundled": true, - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "path-key": { - "version": "2.0.1", - "bundled": true, - "dev": true - }, - "pump": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "require-directory": { - "version": "2.1.1", - "bundled": true, - "dev": true - }, - "require-main-filename": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "ripemd160": { - "version": "2.0.2", - "bundled": true, - "dev": true, - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "rlp": { - "version": "2.2.3", - "bundled": true, - "dev": true, - "requires": { - "bn.js": "^4.11.1", - "safe-buffer": "^5.1.1" - } - }, - "safe-buffer": { - "version": "5.2.0", - "bundled": true, - "dev": true - }, - "secp256k1": { - "version": "3.7.1", - "bundled": true, - "dev": true, - "requires": { - "bindings": "^1.5.0", - "bip66": "^1.1.5", - "bn.js": "^4.11.8", - "create-hash": "^1.2.0", - "drbg.js": "^1.0.1", - "elliptic": "^6.4.1", - "nan": "^2.14.0", - "safe-buffer": "^5.1.2" - } - }, - "semver": { - "version": "5.7.0", - "bundled": true, - "dev": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "sha.js": { - "version": "2.4.11", - "bundled": true, - "dev": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "shebang-command": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true - }, - "source-map": { - "version": "0.6.1", - "bundled": true, - "dev": true - }, - "source-map-support": { - "version": "0.5.12", - "bundled": true, - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "string-width": { - "version": "3.1.0", - "bundled": true, - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - }, - "strip-eof": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "strip-hex-prefix": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "is-hex-prefixed": "1.0.0" - } - }, - "which": { - "version": "1.3.1", - "bundled": true, - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "wrap-ansi": { - "version": "5.1.0", - "bundled": true, - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "y18n": { - "version": "4.0.0", - "bundled": true, - "dev": true - }, - "yargs": { - "version": "13.2.4", - "bundled": true, - "dev": true, - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "os-locale": "^3.1.0", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.0" - } - }, - "yargs-parser": { - "version": "13.1.1", - "bundled": true, - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } - }, - "hash.js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", - "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.0" - } - }, - "scrypt-js": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.3.tgz", - "integrity": "sha1-uwBAvgMEPamgEqLOqfyfhSz8h9Q=", - "dev": true - }, - "web3": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/web3/-/web3-1.2.6.tgz", - "integrity": "sha512-tpu9fLIComgxGrFsD8LUtA4s4aCZk7px8UfcdEy6kS2uDi/ZfR07KJqpXZMij7Jvlq+cQrTAhsPSiBVvoMaivA==", - "dev": true, - "requires": { - "@types/node": "^12.6.1", - "web3-bzz": "1.2.6", - "web3-core": "1.2.6", - "web3-eth": "1.2.6", - "web3-eth-personal": "1.2.6", - "web3-net": "1.2.6", - "web3-shh": "1.2.6", - "web3-utils": "1.2.6" - } - }, - "web3-bzz": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.2.6.tgz", - "integrity": "sha512-9NiHLlxdI1XeFtbPJAmi2jnnIHVF+GNy517wvOS72P7ZfuJTPwZaSNXfT01vWgPPE9R96/uAHDWHOg+T4WaDQQ==", - "dev": true, - "requires": { - "@types/node": "^10.12.18", - "got": "9.6.0", - "swarm-js": "0.1.39", - "underscore": "1.9.1" - }, - "dependencies": { - "@types/node": { - "version": "10.17.26", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.26.tgz", - "integrity": "sha512-myMwkO2Cr82kirHY8uknNRHEVtn0wV3DTQfkrjx17jmkstDRZ24gNUdl8AHXVyVclTYI/bNjgTPTAWvWLqXqkw==", - "dev": true - } - } - }, - "web3-core": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.2.6.tgz", - "integrity": "sha512-y/QNBFtr5cIR8vxebnotbjWJpOnO8LDYEAzZjeRRUJh2ijmhjoYk7dSNx9ExgC0UCfNFRoNCa9dGRu/GAxwRlw==", - "dev": true, - "requires": { - "@types/bn.js": "^4.11.4", - "@types/node": "^12.6.1", - "web3-core-helpers": "1.2.6", - "web3-core-method": "1.2.6", - "web3-core-requestmanager": "1.2.6", - "web3-utils": "1.2.6" - } - }, - "web3-core-helpers": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.6.tgz", - "integrity": "sha512-gYKWmC2HmO7RcDzpo4L1K8EIoy5L8iubNDuTC6q69UxczwqKF/Io0kbK/1Z10Av++NlzOSiuyGp2gc4t4UOsDw==", - "dev": true, - "requires": { - "underscore": "1.9.1", - "web3-eth-iban": "1.2.6", - "web3-utils": "1.2.6" - } - }, - "web3-core-method": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.2.6.tgz", - "integrity": "sha512-r2dzyPEonqkBg7Mugq5dknhV5PGaZTHBZlS/C+aMxNyQs3T3eaAsCTqlQDitwNUh/sUcYPEGF0Vo7ahYK4k91g==", - "dev": true, - "requires": { - "underscore": "1.9.1", - "web3-core-helpers": "1.2.6", - "web3-core-promievent": "1.2.6", - "web3-core-subscriptions": "1.2.6", - "web3-utils": "1.2.6" - } - }, - "web3-core-promievent": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.2.6.tgz", - "integrity": "sha512-km72kJef/qtQNiSjDJJVHIZvoVOm6ytW3FCYnOcCs7RIkviAb5JYlPiye0o4pJOLzCXYID7DK7Q9bhY8qWb1lw==", - "dev": true, - "requires": { - "any-promise": "1.3.0", - "eventemitter3": "3.1.2" - } - }, - "web3-core-requestmanager": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.2.6.tgz", - "integrity": "sha512-QU2cbsj9Dm0r6om40oSwk8Oqbp3wTa08tXuMpSmeOTkGZ3EMHJ1/4LiJ8shwg1AvPMrKVU0Nri6+uBNCdReZ+g==", - "dev": true, - "requires": { - "underscore": "1.9.1", - "web3-core-helpers": "1.2.6", - "web3-providers-http": "1.2.6", - "web3-providers-ipc": "1.2.6", - "web3-providers-ws": "1.2.6" - } - }, - "web3-core-subscriptions": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.2.6.tgz", - "integrity": "sha512-M0PzRrP2Ct13x3wPulFtc5kENH4UtnPxO9YxkfQlX2WRKENWjt4Rfq+BCVGYEk3rTutDfWrjfzjmqMRvXqEY5Q==", - "dev": true, - "requires": { - "eventemitter3": "3.1.2", - "underscore": "1.9.1", - "web3-core-helpers": "1.2.6" - } - }, - "web3-eth": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.2.6.tgz", - "integrity": "sha512-ROWlDPzh4QX6tlGGGlAK6X4kA2n0/cNj/4kb0nNVWkRouGmYO0R8k6s47YxYHvGiXt0s0++FUUv5vAbWovtUQw==", - "dev": true, - "requires": { - "underscore": "1.9.1", - "web3-core": "1.2.6", - "web3-core-helpers": "1.2.6", - "web3-core-method": "1.2.6", - "web3-core-subscriptions": "1.2.6", - "web3-eth-abi": "1.2.6", - "web3-eth-accounts": "1.2.6", - "web3-eth-contract": "1.2.6", - "web3-eth-ens": "1.2.6", - "web3-eth-iban": "1.2.6", - "web3-eth-personal": "1.2.6", - "web3-net": "1.2.6", - "web3-utils": "1.2.6" - } - }, - "web3-eth-abi": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.2.6.tgz", - "integrity": "sha512-w9GAyyikn8nSifSDZxAvU9fxtQSX+W2xQWMmrtTXmBGCaE4/ywKOSPAO78gq8AoU4Wq5yqVGKZLLbfpt7/sHlA==", - "dev": true, - "requires": { - "ethers": "4.0.0-beta.3", - "underscore": "1.9.1", - "web3-utils": "1.2.6" - } - }, - "web3-eth-accounts": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.2.6.tgz", - "integrity": "sha512-cDVtonHRgzqi/ZHOOf8kfCQWFEipcfQNAMzXIaKZwc0UUD9mgSI5oJrN45a89Ze+E6Lz9m77cDG5Ax9zscSkcw==", - "dev": true, - "requires": { - "@web3-js/scrypt-shim": "^0.1.0", - "any-promise": "1.3.0", - "crypto-browserify": "3.12.0", - "eth-lib": "^0.2.8", - "ethereumjs-common": "^1.3.2", - "ethereumjs-tx": "^2.1.1", - "underscore": "1.9.1", - "uuid": "3.3.2", - "web3-core": "1.2.6", - "web3-core-helpers": "1.2.6", - "web3-core-method": "1.2.6", - "web3-utils": "1.2.6" - }, - "dependencies": { - "eth-lib": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz", - "integrity": "sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw==", - "dev": true, - "requires": { - "bn.js": "^4.11.6", - "elliptic": "^6.4.0", - "xhr-request-promise": "^0.1.2" - } - }, - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", - "dev": true - } - } - }, - "web3-eth-contract": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.2.6.tgz", - "integrity": "sha512-ak4xbHIhWgsbdPCkSN+HnQc1SH4c856y7Ly+S57J/DQVzhFZemK5HvWdpwadJrQTcHET3ZeId1vq3kmW7UYodw==", - "dev": true, - "requires": { - "@types/bn.js": "^4.11.4", - "underscore": "1.9.1", - "web3-core": "1.2.6", - "web3-core-helpers": "1.2.6", - "web3-core-method": "1.2.6", - "web3-core-promievent": "1.2.6", - "web3-core-subscriptions": "1.2.6", - "web3-eth-abi": "1.2.6", - "web3-utils": "1.2.6" - } - }, - "web3-eth-ens": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.2.6.tgz", - "integrity": "sha512-8UEqt6fqR/dji/jBGPFAyBs16OJjwi0t2dPWXPyGXmty/fH+osnXwWXE4HRUyj4xuafiM5P1YkXMsPhKEadjiw==", - "dev": true, - "requires": { - "eth-ens-namehash": "2.0.8", - "underscore": "1.9.1", - "web3-core": "1.2.6", - "web3-core-helpers": "1.2.6", - "web3-core-promievent": "1.2.6", - "web3-eth-abi": "1.2.6", - "web3-eth-contract": "1.2.6", - "web3-utils": "1.2.6" - } - }, - "web3-eth-iban": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.2.6.tgz", - "integrity": "sha512-TPMc3BW9Iso7H+9w+ytbqHK9wgOmtocyCD3PaAe5Eie50KQ/j7ThA60dGJnxItVo6yyRv5pZAYxPVob9x/fJlg==", - "dev": true, - "requires": { - "bn.js": "4.11.8", - "web3-utils": "1.2.6" - } - }, - "web3-eth-personal": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.2.6.tgz", - "integrity": "sha512-T2NUkh1plY8d7wePXSoHnaiKOd8dLNFaQfgBl9JHU6S7IJrG9jnYD9bVxLEgRUfHs9gKf9tQpDf7AcPFdq/A8g==", - "dev": true, - "requires": { - "@types/node": "^12.6.1", - "web3-core": "1.2.6", - "web3-core-helpers": "1.2.6", - "web3-core-method": "1.2.6", - "web3-net": "1.2.6", - "web3-utils": "1.2.6" - } - }, - "web3-net": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.2.6.tgz", - "integrity": "sha512-hsNHAPddrhgjWLmbESW0KxJi2GnthPcow0Sqpnf4oB6+/+ZnQHU9OsIyHb83bnC1OmunrK2vf9Ye2mLPdFIu3A==", - "dev": true, - "requires": { - "web3-core": "1.2.6", - "web3-core-method": "1.2.6", - "web3-utils": "1.2.6" - } - }, - "web3-providers-http": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.2.6.tgz", - "integrity": "sha512-2+SaFCspb5f82QKuHB3nEPQOF9iSWxRf7c18fHtmnLNVkfG9SwLN1zh67bYn3tZGUdOI3gj8aX4Uhfpwx9Ezpw==", - "dev": true, - "requires": { - "web3-core-helpers": "1.2.6", - "xhr2-cookies": "1.1.0" - } - }, - "web3-providers-ipc": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.2.6.tgz", - "integrity": "sha512-b0Es+/GTZyk5FG3SgUDW+2/mBwJAXWt5LuppODptiOas8bB2khLjG6+Gm1K4uwOb+1NJGPt5mZZ8Wi7vibtQ+A==", - "dev": true, - "requires": { - "oboe": "2.1.4", - "underscore": "1.9.1", - "web3-core-helpers": "1.2.6" - } - }, - "web3-providers-ws": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.2.6.tgz", - "integrity": "sha512-20waSYX+gb5M5yKhug5FIwxBBvkKzlJH7sK6XEgdOx6BZ9YYamLmvg9wcRVtnSZO8hV/3cWenO/tRtTrHVvIgQ==", - "dev": true, - "requires": { - "@web3-js/websocket": "^1.0.29", - "underscore": "1.9.1", - "web3-core-helpers": "1.2.6" - } - }, - "web3-shh": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.2.6.tgz", - "integrity": "sha512-rouWyOOM6YMbLQd65grpj8BBezQfgNeRRX+cGyW4xsn6Xgu+B73Zvr6OtA/ftJwwa9bqHGpnLrrLMeWyy4YLUw==", - "dev": true, - "requires": { - "web3-core": "1.2.6", - "web3-core-method": "1.2.6", - "web3-core-subscriptions": "1.2.6", - "web3-net": "1.2.6" - } - }, - "web3-utils": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.2.6.tgz", - "integrity": "sha512-8/HnqG/l7dGmKMgEL9JeKPTtjScxOePTzopv5aaKFExPfaBrYRkgoMqhoowCiAl/s16QaTn4DoIF1QC4YsT7Mg==", - "dev": true, - "requires": { - "bn.js": "4.11.8", - "eth-lib": "0.2.7", - "ethereum-bloom-filters": "^1.0.6", - "ethjs-unit": "0.1.6", - "number-to-bn": "1.7.0", - "randombytes": "^2.1.0", - "underscore": "1.9.1", - "utf8": "3.0.0" + "has-flag": "^3.0.0" } } } }, "source-map": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", - "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", - "dev": true, - "optional": true, - "requires": { - "amdefine": ">=0.0.4" - } + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" }, "source-map-resolve": { "version": "0.5.3", @@ -9617,13 +8539,6 @@ "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", "requires": { "source-map": "^0.5.6" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" - } } }, "source-map-url": { @@ -9694,57 +8609,68 @@ "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" }, "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "dev": true, + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" }, "dependencies": { - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "^3.0.0" + } } } }, "string.prototype.trimend": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", - "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.2.tgz", + "integrity": "sha512-8oAG/hi14Z4nOVP0z6mdiVZ/wqjDtWSLygMigTzAb+7aPEDTleeFf+WrF+alzecxIRkckkJVn+dTlwzJXORATw==", "requires": { "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" + "es-abstract": "^1.18.0-next.1" } }, "string.prototype.trimstart": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", - "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.2.tgz", + "integrity": "sha512-7F6CdBTl5zyu30BJFdzSTlSlLPwODC23Od+iLoVH8X6+3fvDPPuBVVj9iaB1GOsSTSIgVfsfm27R2FGrAPznWg==", "requires": { "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" + "es-abstract": "^1.18.0-next.1" } }, "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "~5.2.0" + "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } } }, "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^2.0.0" } }, "strip-dirs": { @@ -9769,12 +8695,9 @@ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" }, "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" }, "swarm-js": { "version": "0.1.39", @@ -9831,6 +8754,14 @@ "url-to-options": "^1.0.1" } }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "requires": { + "graceful-fs": "^4.1.6" + } + }, "p-cancelable": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz", @@ -9841,11 +8772,6 @@ "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" - }, "url-parse-lax": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", @@ -9868,16 +8794,6 @@ "mkdirp": "^0.5.0", "safe-buffer": "^5.1.2", "yallist": "^3.0.3" - }, - "dependencies": { - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "requires": { - "minimist": "^1.2.5" - } - } } }, "tar-stream": { @@ -9892,35 +8808,6 @@ "readable-stream": "^2.3.0", "to-buffer": "^1.1.1", "xtend": "^4.0.0" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } } }, "through": { @@ -9958,17 +8845,6 @@ "optional": true, "requires": { "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "optional": true, - "requires": { - "is-buffer": "^1.1.5" - } - } } }, "to-readable-stream": { @@ -9989,11 +8865,24 @@ } }, "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "optional": true, "requires": { - "is-number": "^7.0.0" + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "optional": true, + "requires": { + "kind-of": "^3.0.2" + } + } } }, "toidentifier": { @@ -10026,88 +8915,6 @@ "websocket": "^1.0.28" }, "dependencies": { - "@types/node": { - "version": "10.17.24", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.24.tgz", - "integrity": "sha512-5SCfvCxV74kzR3uWgTYiGxrd69TbT1I6+cMx1A5kEly/IVveJBimtAMlXiEyVFn5DvUFewQWxOOiJhlxeQwxgA==" - }, - "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "eth-lib": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.7.tgz", - "integrity": "sha1-L5Pxex4jrsN1nNSj/iDBKGo/wco=", - "requires": { - "bn.js": "^4.11.6", - "elliptic": "^6.4.0", - "xhr-request-promise": "^0.1.2" - } - }, - "ethers": { - "version": "4.0.0-beta.3", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.0-beta.3.tgz", - "integrity": "sha512-YYPogooSknTwvHg3+Mv71gM/3Wcrx+ZpCzarBj3mqs9njjRkrOo2/eufzhHloOCo3JSoNI4TQJJ6yU5ABm3Uog==", - "requires": { - "@types/node": "^10.3.2", - "aes-js": "3.0.0", - "bn.js": "^4.4.0", - "elliptic": "6.3.3", - "hash.js": "1.1.3", - "js-sha3": "0.5.7", - "scrypt-js": "2.0.3", - "setimmediate": "1.0.4", - "uuid": "2.0.1", - "xmlhttprequest": "1.8.0" - }, - "dependencies": { - "elliptic": { - "version": "6.3.3", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.3.3.tgz", - "integrity": "sha1-VILZZG1UvLif19mU/J4ulWiHbj8=", - "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "inherits": "^2.0.1" - } - } - } - }, - "hash.js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", - "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "scrypt-js": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.3.tgz", - "integrity": "sha1-uwBAvgMEPamgEqLOqfyfhSz8h9Q=" - }, - "semver": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.2.0.tgz", - "integrity": "sha512-jdFC1VdUGT/2Scgbimf7FSx9iJLXoqfglSF+gJeuNWVpiE37OIbc1jywR/GJyFdz3mnkz2/id0L0J/cr0izR5A==" - }, "web3": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/web3/-/web3-1.2.1.tgz", @@ -10121,275 +8928,6 @@ "web3-shh": "1.2.1", "web3-utils": "1.2.1" } - }, - "web3-bzz": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.2.1.tgz", - "integrity": "sha512-LdOO44TuYbGIPfL4ilkuS89GQovxUpmLz6C1UC7VYVVRILeZS740FVB3j9V4P4FHUk1RenaDfKhcntqgVCHtjw==", - "requires": { - "got": "9.6.0", - "swarm-js": "0.1.39", - "underscore": "1.9.1" - } - }, - "web3-core": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.2.1.tgz", - "integrity": "sha512-5ODwIqgl8oIg/0+Ai4jsLxkKFWJYE0uLuE1yUKHNVCL4zL6n3rFjRMpKPokd6id6nJCNgeA64KdWQ4XfpnjdMg==", - "requires": { - "web3-core-helpers": "1.2.1", - "web3-core-method": "1.2.1", - "web3-core-requestmanager": "1.2.1", - "web3-utils": "1.2.1" - } - }, - "web3-core-helpers": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.1.tgz", - "integrity": "sha512-Gx3sTEajD5r96bJgfuW377PZVFmXIH4TdqDhgGwd2lZQCcMi+DA4TgxJNJGxn0R3aUVzyyE76j4LBrh412mXrw==", - "requires": { - "underscore": "1.9.1", - "web3-eth-iban": "1.2.1", - "web3-utils": "1.2.1" - } - }, - "web3-core-method": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.2.1.tgz", - "integrity": "sha512-Ghg2WS23qi6Xj8Od3VCzaImLHseEA7/usvnOItluiIc5cKs00WYWsNy2YRStzU9a2+z8lwQywPYp0nTzR/QXdQ==", - "requires": { - "underscore": "1.9.1", - "web3-core-helpers": "1.2.1", - "web3-core-promievent": "1.2.1", - "web3-core-subscriptions": "1.2.1", - "web3-utils": "1.2.1" - } - }, - "web3-core-promievent": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.2.1.tgz", - "integrity": "sha512-IVUqgpIKoeOYblwpex4Hye6npM0aMR+kU49VP06secPeN0rHMyhGF0ZGveWBrGvf8WDPI7jhqPBFIC6Jf3Q3zw==", - "requires": { - "any-promise": "1.3.0", - "eventemitter3": "3.1.2" - } - }, - "web3-core-requestmanager": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.2.1.tgz", - "integrity": "sha512-xfknTC69RfYmLKC+83Jz73IC3/sS2ZLhGtX33D4Q5nQ8yc39ElyAolxr9sJQS8kihOcM6u4J+8gyGMqsLcpIBg==", - "requires": { - "underscore": "1.9.1", - "web3-core-helpers": "1.2.1", - "web3-providers-http": "1.2.1", - "web3-providers-ipc": "1.2.1", - "web3-providers-ws": "1.2.1" - } - }, - "web3-core-subscriptions": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.2.1.tgz", - "integrity": "sha512-nmOwe3NsB8V8UFsY1r+sW6KjdOS68h8nuh7NzlWxBQT/19QSUGiERRTaZXWu5BYvo1EoZRMxCKyCQpSSXLc08g==", - "requires": { - "eventemitter3": "3.1.2", - "underscore": "1.9.1", - "web3-core-helpers": "1.2.1" - } - }, - "web3-eth": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.2.1.tgz", - "integrity": "sha512-/2xly4Yry5FW1i+uygPjhfvgUP/MS/Dk+PDqmzp5M88tS86A+j8BzKc23GrlA8sgGs0645cpZK/999LpEF5UdA==", - "requires": { - "underscore": "1.9.1", - "web3-core": "1.2.1", - "web3-core-helpers": "1.2.1", - "web3-core-method": "1.2.1", - "web3-core-subscriptions": "1.2.1", - "web3-eth-abi": "1.2.1", - "web3-eth-accounts": "1.2.1", - "web3-eth-contract": "1.2.1", - "web3-eth-ens": "1.2.1", - "web3-eth-iban": "1.2.1", - "web3-eth-personal": "1.2.1", - "web3-net": "1.2.1", - "web3-utils": "1.2.1" - } - }, - "web3-eth-abi": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.2.1.tgz", - "integrity": "sha512-jI/KhU2a/DQPZXHjo2GW0myEljzfiKOn+h1qxK1+Y9OQfTcBMxrQJyH5AP89O6l6NZ1QvNdq99ThAxBFoy5L+g==", - "requires": { - "ethers": "4.0.0-beta.3", - "underscore": "1.9.1", - "web3-utils": "1.2.1" - } - }, - "web3-eth-accounts": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.2.1.tgz", - "integrity": "sha512-26I4qq42STQ8IeKUyur3MdQ1NzrzCqPsmzqpux0j6X/XBD7EjZ+Cs0lhGNkSKH5dI3V8CJasnQ5T1mNKeWB7nQ==", - "requires": { - "any-promise": "1.3.0", - "crypto-browserify": "3.12.0", - "eth-lib": "0.2.7", - "scryptsy": "2.1.0", - "semver": "6.2.0", - "underscore": "1.9.1", - "uuid": "3.3.2", - "web3-core": "1.2.1", - "web3-core-helpers": "1.2.1", - "web3-core-method": "1.2.1", - "web3-utils": "1.2.1" - }, - "dependencies": { - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" - } - } - }, - "web3-eth-contract": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.2.1.tgz", - "integrity": "sha512-kYFESbQ3boC9bl2rYVghj7O8UKMiuKaiMkxvRH5cEDHil8V7MGEGZNH0slSdoyeftZVlaWSMqkRP/chfnKND0g==", - "requires": { - "underscore": "1.9.1", - "web3-core": "1.2.1", - "web3-core-helpers": "1.2.1", - "web3-core-method": "1.2.1", - "web3-core-promievent": "1.2.1", - "web3-core-subscriptions": "1.2.1", - "web3-eth-abi": "1.2.1", - "web3-utils": "1.2.1" - } - }, - "web3-eth-ens": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.2.1.tgz", - "integrity": "sha512-lhP1kFhqZr2nnbu3CGIFFrAnNxk2veXpOXBY48Tub37RtobDyHijHgrj+xTh+mFiPokyrapVjpFsbGa+Xzye4Q==", - "requires": { - "eth-ens-namehash": "2.0.8", - "underscore": "1.9.1", - "web3-core": "1.2.1", - "web3-core-helpers": "1.2.1", - "web3-core-promievent": "1.2.1", - "web3-eth-abi": "1.2.1", - "web3-eth-contract": "1.2.1", - "web3-utils": "1.2.1" - } - }, - "web3-eth-iban": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.2.1.tgz", - "integrity": "sha512-9gkr4QPl1jCU+wkgmZ8EwODVO3ovVj6d6JKMos52ggdT2YCmlfvFVF6wlGLwi0VvNa/p+0BjJzaqxnnG/JewjQ==", - "requires": { - "bn.js": "4.11.8", - "web3-utils": "1.2.1" - } - }, - "web3-eth-personal": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.2.1.tgz", - "integrity": "sha512-RNDVSiaSoY4aIp8+Hc7z+X72H7lMb3fmAChuSBADoEc7DsJrY/d0R5qQDK9g9t2BO8oxgLrLNyBP/9ub2Hc6Bg==", - "requires": { - "web3-core": "1.2.1", - "web3-core-helpers": "1.2.1", - "web3-core-method": "1.2.1", - "web3-net": "1.2.1", - "web3-utils": "1.2.1" - } - }, - "web3-net": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.2.1.tgz", - "integrity": "sha512-Yt1Bs7WgnLESPe0rri/ZoPWzSy55ovioaP35w1KZydrNtQ5Yq4WcrAdhBzcOW7vAkIwrsLQsvA+hrOCy7mNauw==", - "requires": { - "web3-core": "1.2.1", - "web3-core-method": "1.2.1", - "web3-utils": "1.2.1" - } - }, - "web3-providers-http": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.2.1.tgz", - "integrity": "sha512-BDtVUVolT9b3CAzeGVA/np1hhn7RPUZ6YYGB/sYky+GjeO311Yoq8SRDUSezU92x8yImSC2B+SMReGhd1zL+bQ==", - "requires": { - "web3-core-helpers": "1.2.1", - "xhr2-cookies": "1.1.0" - } - }, - "web3-providers-ipc": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.2.1.tgz", - "integrity": "sha512-oPEuOCwxVx8L4CPD0TUdnlOUZwGBSRKScCz/Ws2YHdr9Ium+whm+0NLmOZjkjQp5wovQbyBzNa6zJz1noFRvFA==", - "requires": { - "oboe": "2.1.4", - "underscore": "1.9.1", - "web3-core-helpers": "1.2.1" - } - }, - "web3-providers-ws": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.2.1.tgz", - "integrity": "sha512-oqsQXzu+ejJACVHy864WwIyw+oB21nw/pI65/sD95Zi98+/HQzFfNcIFneF1NC4bVF3VNX4YHTNq2I2o97LAiA==", - "requires": { - "underscore": "1.9.1", - "web3-core-helpers": "1.2.1", - "websocket": "github:web3-js/WebSocket-Node#polyfill/globalThis" - }, - "dependencies": { - "websocket": { - "version": "github:web3-js/WebSocket-Node#ef5ea2f41daf4a2113b80c9223df884b4d56c400", - "from": "github:web3-js/WebSocket-Node#polyfill/globalThis", - "requires": { - "debug": "^2.2.0", - "es5-ext": "^0.10.50", - "nan": "^2.14.0", - "typedarray-to-buffer": "^3.1.5", - "yaeti": "^0.0.6" - } - } - } - }, - "web3-shh": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.2.1.tgz", - "integrity": "sha512-/3Cl04nza5kuFn25bV3FJWa0s3Vafr5BlT933h26xovQ6HIIz61LmvNQlvX1AhFL+SNJOTcQmK1SM59vcyC8bA==", - "requires": { - "web3-core": "1.2.1", - "web3-core-method": "1.2.1", - "web3-core-subscriptions": "1.2.1", - "web3-net": "1.2.1" - } - }, - "web3-utils": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.2.1.tgz", - "integrity": "sha512-Mrcn3l58L+yCKz3zBryM6JZpNruWuT0OCbag8w+reeNROSGVlXzUQkU+gtAwc9JCZ7tKUyg67+2YUGqUjVcyBA==", - "requires": { - "bn.js": "4.11.8", - "eth-lib": "0.2.7", - "ethjs-unit": "0.1.6", - "number-to-bn": "1.7.0", - "randomhex": "0.1.5", - "underscore": "1.9.1", - "utf8": "3.0.0" - } - }, - "websocket": { - "version": "1.0.31", - "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.31.tgz", - "integrity": "sha512-VAouplvGKPiKFDTeCCO65vYHsyay8DqoBSlzIO3fayrfOgU94lQN5a1uWVnFrMLceTJw/+fQXR5PGbUVRaHshQ==", - "requires": { - "debug": "^2.2.0", - "es5-ext": "^0.10.50", - "nan": "^2.14.0", - "typedarray-to-buffer": "^3.1.5", - "yaeti": "^0.0.6" - } } } }, @@ -10476,28 +9014,16 @@ } }, "typescript": { - "version": "3.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.5.tgz", - "integrity": "sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==" + "version": "3.9.7", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz", + "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==" }, "uglify-js": { - "version": "3.9.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.9.4.tgz", - "integrity": "sha512-8RZBJq5smLOa7KslsNsVcSH+KOXf1uDU8yqLeNuVKwmT0T3FA0ZoXlinQfRad7SDcbZZRZE4ov+2v71EnxNyCA==", + "version": "3.11.5", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.11.5.tgz", + "integrity": "sha512-btvv/baMqe7HxP7zJSF7Uc16h1mSfuuSplT0/qdjxseesDU+yYzH33eHBH+eMdeRXwujXspaCTooWHQVVBh09w==", "dev": true, - "optional": true, - "requires": { - "commander": "~2.20.3" - }, - "dependencies": { - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true, - "optional": true - } - } + "optional": true }, "ultron": { "version": "1.1.1", @@ -10587,9 +9113,9 @@ } }, "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", + "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", "requires": { "punycode": "^2.1.0" } @@ -10629,6 +9155,14 @@ "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=" }, + "utf-8-validate": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.3.tgz", + "integrity": "sha512-jtJM6fpGv8C1SoH4PtG22pGto6x+Y8uPprW0tw3//gGFhDDTiuksgradgFN6yRayDP4SyZZa6ZMGHLIa17+M8A==", + "requires": { + "node-gyp-build": "^4.2.0" + } + }, "utf8": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", @@ -10658,9 +9192,9 @@ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, "uuid": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", - "integrity": "sha1-wqMN7bPlNdcsz4LjQ5QaULqFM6w=" + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" }, "v8flags": { "version": "2.1.1", @@ -10671,9 +9205,9 @@ } }, "varint": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.0.tgz", - "integrity": "sha1-2Ca4n3SQcy+rwMDtaT7Uddyynr8=" + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.2.tgz", + "integrity": "sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow==" }, "vary": { "version": "1.1.2", @@ -10691,36 +9225,33 @@ } }, "web3": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3/-/web3-1.2.9.tgz", - "integrity": "sha512-Mo5aBRm0JrcNpN/g4VOrDzudymfOnHRC3s2VarhYxRA8aWgF5rnhQ0ziySaugpic1gksbXPe105pUWyRqw8HUA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.3.0.tgz", + "integrity": "sha512-4q9dna0RecnrlgD/bD1C5S+81Untbd6Z/TBD7rb+D5Bvvc0Wxjr4OP70x+LlnwuRDjDtzBwJbNUblh2grlVArw==", "requires": { - "web3-bzz": "1.2.9", - "web3-core": "1.2.9", - "web3-eth": "1.2.9", - "web3-eth-personal": "1.2.9", - "web3-net": "1.2.9", - "web3-shh": "1.2.9", - "web3-utils": "1.2.9" + "web3-bzz": "1.3.0", + "web3-core": "1.3.0", + "web3-eth": "1.3.0", + "web3-eth-personal": "1.3.0", + "web3-net": "1.3.0", + "web3-shh": "1.3.0", + "web3-utils": "1.3.0" }, "dependencies": { "@types/node": { - "version": "10.17.26", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.26.tgz", - "integrity": "sha512-myMwkO2Cr82kirHY8uknNRHEVtn0wV3DTQfkrjx17jmkstDRZ24gNUdl8AHXVyVclTYI/bNjgTPTAWvWLqXqkw==" + "version": "12.19.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.3.tgz", + "integrity": "sha512-8Jduo8wvvwDzEVJCOvS/G6sgilOLvvhn1eMmK3TW8/T217O7u1jdrK6ImKLv80tVryaPSVeKu6sjDEiFjd4/eg==" }, "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } + "eventemitter3": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", + "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==" }, "fs-extra": { "version": "4.0.3", @@ -10737,10 +9268,21 @@ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "oboe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.5.tgz", + "integrity": "sha1-VVQoTFQ6ImbXo48X4HOCH73jk80=", + "requires": { + "http-https": "^1.0.0" + } }, "p-cancelable": { "version": "0.3.0", @@ -10752,16 +9294,6 @@ "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" }, - "scrypt-js": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", - "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==" - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" - }, "swarm-js": { "version": "0.1.40", "resolved": "https://registry.npmjs.org/swarm-js/-/swarm-js-0.1.40.tgz", @@ -10817,126 +9349,119 @@ "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" }, "web3-bzz": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.2.9.tgz", - "integrity": "sha512-ogVQr9jHodu9HobARtvUSmWG22cv2EUQzlPeejGWZ7j5h20HX40EDuWyomGY5VclIj5DdLY76Tmq88RTf/6nxA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.3.0.tgz", + "integrity": "sha512-ibYAnKab+sgTo/UdfbrvYfWblXjjgSMgyy9/FHa6WXS14n/HVB+HfWqGz2EM3fok8Wy5XoKGMvdqvERQ/mzq1w==", "requires": { - "@types/node": "^10.12.18", + "@types/node": "^12.12.6", "got": "9.6.0", "swarm-js": "^0.1.40", "underscore": "1.9.1" } }, "web3-core": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.2.9.tgz", - "integrity": "sha512-fSYv21IP658Ty2wAuU9iqmW7V+75DOYMVZsDH/c14jcF/1VXnedOcxzxSj3vArsCvXZNe6XC5/wAuGZyQwR9RA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.3.0.tgz", + "integrity": "sha512-BwWvAaKJf4KFG9QsKRi3MNoNgzjI6szyUlgme1qNPxUdCkaS3Rdpa0VKYNHP7M/YTk82/59kNE66mH5vmoaXjA==", "requires": { - "@types/bn.js": "^4.11.4", - "@types/node": "^12.6.1", + "@types/bn.js": "^4.11.5", + "@types/node": "^12.12.6", "bignumber.js": "^9.0.0", - "web3-core-helpers": "1.2.9", - "web3-core-method": "1.2.9", - "web3-core-requestmanager": "1.2.9", - "web3-utils": "1.2.9" - }, - "dependencies": { - "@types/node": { - "version": "12.12.47", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.47.tgz", - "integrity": "sha512-yzBInQFhdY8kaZmqoL2+3U5dSTMrKaYcb561VU+lDzAYvqt+2lojvBEy+hmpSNuXnPTx7m9+04CzWYOUqWME2A==" - } + "web3-core-helpers": "1.3.0", + "web3-core-method": "1.3.0", + "web3-core-requestmanager": "1.3.0", + "web3-utils": "1.3.0" } }, "web3-core-method": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.2.9.tgz", - "integrity": "sha512-bjsIoqP3gs7A/gP8+QeLUCyOKJ8bopteCSNbCX36Pxk6TYfYWNuC6hP+2GzUuqdP3xaZNe+XEElQFUNpR3oyAg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.3.0.tgz", + "integrity": "sha512-h0yFDrYVzy5WkLxC/C3q+hiMnzxdWm9p1T1rslnuHgOp6nYfqzu/6mUIXrsS4h/OWiGJt+BZ0xVZmtC31HDWtg==", "requires": { "@ethersproject/transactions": "^5.0.0-beta.135", "underscore": "1.9.1", - "web3-core-helpers": "1.2.9", - "web3-core-promievent": "1.2.9", - "web3-core-subscriptions": "1.2.9", - "web3-utils": "1.2.9" + "web3-core-helpers": "1.3.0", + "web3-core-promievent": "1.3.0", + "web3-core-subscriptions": "1.3.0", + "web3-utils": "1.3.0" } }, "web3-core-promievent": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.2.9.tgz", - "integrity": "sha512-0eAUA2zjgXTleSrnc1wdoKQPPIHU6KHf4fAscu4W9kKrR+mqP1KsjYrxY9wUyjNnXxfQ+5M29ipvbiaK8OqdOw==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.3.0.tgz", + "integrity": "sha512-blv69wrXw447TP3iPvYJpllkhW6B18nfuEbrfcr3n2Y0v1Jx8VJacNZFDFsFIcgXcgUIVCtOpimU7w9v4+rtaw==", "requires": { - "eventemitter3": "3.1.2" + "eventemitter3": "4.0.4" } }, "web3-core-requestmanager": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.2.9.tgz", - "integrity": "sha512-1PwKV2m46ALUnIN5VPPgjOj8yMLJhhqZYvYJE34hTN5SErOkwhzx5zScvo5MN7v7KyQGFnpVCZKKGCiEnDmtFA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.3.0.tgz", + "integrity": "sha512-3yMbuGcomtzlmvTVqNRydxsx7oPlw3ioRL6ReF9PeNYDkUsZaUib+6Dp5eBt7UXh5X+SIn/xa1smhDHz5/HpAw==", "requires": { "underscore": "1.9.1", - "web3-core-helpers": "1.2.9", - "web3-providers-http": "1.2.9", - "web3-providers-ipc": "1.2.9", - "web3-providers-ws": "1.2.9" + "web3-core-helpers": "1.3.0", + "web3-providers-http": "1.3.0", + "web3-providers-ipc": "1.3.0", + "web3-providers-ws": "1.3.0" } }, "web3-core-subscriptions": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.2.9.tgz", - "integrity": "sha512-Y48TvXPSPxEM33OmXjGVDMzTd0j8X0t2+sDw66haeBS8eYnrEzasWuBZZXDq0zNUsqyxItgBGDn+cszkgEnFqg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.3.0.tgz", + "integrity": "sha512-MUUQUAhJDb+Nz3S97ExVWveH4utoUnsbPWP+q1HJH437hEGb4vunIb9KvN3hFHLB+aHJfPeStM/4yYTz5PeuyQ==", "requires": { - "eventemitter3": "3.1.2", + "eventemitter3": "4.0.4", "underscore": "1.9.1", - "web3-core-helpers": "1.2.9" + "web3-core-helpers": "1.3.0" } }, "web3-eth": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.2.9.tgz", - "integrity": "sha512-sIKO4iE9FEBa/CYUd6GdPd7GXt/wISqxUd8PlIld6+hvMJj02lgO7Z7p5T9mZIJcIZJGvZX81ogx8oJ9yif+Ag==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.3.0.tgz", + "integrity": "sha512-/bzJcxXPM9EM18JM5kO2JjZ3nEqVo3HxqU93aWAEgJNqaP/Lltmufl2GpvIB2Hvj+FXAjAXquxUdQ2/xP7BzHQ==", "requires": { "underscore": "1.9.1", - "web3-core": "1.2.9", - "web3-core-helpers": "1.2.9", - "web3-core-method": "1.2.9", - "web3-core-subscriptions": "1.2.9", - "web3-eth-abi": "1.2.9", - "web3-eth-accounts": "1.2.9", - "web3-eth-contract": "1.2.9", - "web3-eth-ens": "1.2.9", - "web3-eth-iban": "1.2.9", - "web3-eth-personal": "1.2.9", - "web3-net": "1.2.9", - "web3-utils": "1.2.9" + "web3-core": "1.3.0", + "web3-core-helpers": "1.3.0", + "web3-core-method": "1.3.0", + "web3-core-subscriptions": "1.3.0", + "web3-eth-abi": "1.3.0", + "web3-eth-accounts": "1.3.0", + "web3-eth-contract": "1.3.0", + "web3-eth-ens": "1.3.0", + "web3-eth-iban": "1.3.0", + "web3-eth-personal": "1.3.0", + "web3-net": "1.3.0", + "web3-utils": "1.3.0" } }, "web3-eth-abi": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.2.9.tgz", - "integrity": "sha512-3YwUYbh/DMfDbhMWEebAdjSd5bj3ZQieOjLzWFHU23CaLEqT34sUix1lba+hgUH/EN6A7bKAuKOhR3p0OvTn7Q==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.3.0.tgz", + "integrity": "sha512-1OrZ9+KGrBeBRd3lO8upkpNua9+7cBsQAgor9wbA25UrcUYSyL8teV66JNRu9gFxaTbkpdrGqM7J/LXpraXWrg==", "requires": { "@ethersproject/abi": "5.0.0-beta.153", "underscore": "1.9.1", - "web3-utils": "1.2.9" + "web3-utils": "1.3.0" } }, "web3-eth-accounts": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.2.9.tgz", - "integrity": "sha512-jkbDCZoA1qv53mFcRHCinoCsgg8WH+M0YUO1awxmqWXRmCRws1wW0TsuSQ14UThih5Dxolgl+e+aGWxG58LMwg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.3.0.tgz", + "integrity": "sha512-/Q7EVW4L2wWUbNRtOTwAIrYvJid/5UnKMw67x/JpvRMwYC+e+744P536Ja6SG4X3MnzFvd3E/jruV4qa6k+zIw==", "requires": { "crypto-browserify": "3.12.0", - "eth-lib": "^0.2.8", + "eth-lib": "0.2.8", "ethereumjs-common": "^1.3.2", "ethereumjs-tx": "^2.1.1", "scrypt-js": "^3.0.1", "underscore": "1.9.1", "uuid": "3.3.2", - "web3-core": "1.2.9", - "web3-core-helpers": "1.2.9", - "web3-core-method": "1.2.9", - "web3-utils": "1.2.9" + "web3-core": "1.3.0", + "web3-core-helpers": "1.3.0", + "web3-core-method": "1.3.0", + "web3-utils": "1.3.0" }, "dependencies": { "eth-lib": { @@ -10952,115 +9477,101 @@ } }, "web3-eth-ens": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.2.9.tgz", - "integrity": "sha512-kG4+ZRgZ8I1WYyOBGI8QVRHfUSbbJjvJAGA1AF/NOW7JXQ+x7gBGeJw6taDWJhSshMoEKWcsgvsiuoG4870YxQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.3.0.tgz", + "integrity": "sha512-WnOru+EcuM5dteiVYJcHXo/I7Wq+ei8RrlS2nir49M0QpYvUPGbCGgTbifcjJQTWamgORtWdljSA1s2Asdb74w==", "requires": { "content-hash": "^2.5.2", "eth-ens-namehash": "2.0.8", "underscore": "1.9.1", - "web3-core": "1.2.9", - "web3-core-helpers": "1.2.9", - "web3-core-promievent": "1.2.9", - "web3-eth-abi": "1.2.9", - "web3-eth-contract": "1.2.9", - "web3-utils": "1.2.9" + "web3-core": "1.3.0", + "web3-core-helpers": "1.3.0", + "web3-core-promievent": "1.3.0", + "web3-eth-abi": "1.3.0", + "web3-eth-contract": "1.3.0", + "web3-utils": "1.3.0" } }, "web3-eth-iban": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.2.9.tgz", - "integrity": "sha512-RtdVvJE0pyg9dHLy0GzDiqgnLnssSzfz/JYguhC1wsj9+Gnq1M6Diy3NixACWUAp6ty/zafyOaZnNQ+JuH9TjQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.3.0.tgz", + "integrity": "sha512-v9mZWhR4fPF17/KhHLiWir4YHWLe09O3B/NTdhWqw3fdAMJNztzMHGzgHxA/4fU+rhrs/FhDzc4yt32zMEXBZw==", "requires": { - "bn.js": "4.11.8", - "web3-utils": "1.2.9" + "bn.js": "^4.11.9", + "web3-utils": "1.3.0" } }, "web3-eth-personal": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.2.9.tgz", - "integrity": "sha512-cFiNrktxZ1C/rIdJFzQTvFn3/0zcsR3a+Jf8Y3KxeQDHszQtosjLWptP7bsUmDwEh4hzh0Cy3KpOxlYBWB8bJQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.3.0.tgz", + "integrity": "sha512-2czUhElsJdLpuNfun9GeLiClo5O6Xw+bLSjl3f4bNG5X2V4wcIjX2ygep/nfstLLtkz8jSkgl/bV7esANJyeRA==", "requires": { - "@types/node": "^12.6.1", - "web3-core": "1.2.9", - "web3-core-helpers": "1.2.9", - "web3-core-method": "1.2.9", - "web3-net": "1.2.9", - "web3-utils": "1.2.9" - }, - "dependencies": { - "@types/node": { - "version": "12.12.47", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.47.tgz", - "integrity": "sha512-yzBInQFhdY8kaZmqoL2+3U5dSTMrKaYcb561VU+lDzAYvqt+2lojvBEy+hmpSNuXnPTx7m9+04CzWYOUqWME2A==" - } + "@types/node": "^12.12.6", + "web3-core": "1.3.0", + "web3-core-helpers": "1.3.0", + "web3-core-method": "1.3.0", + "web3-net": "1.3.0", + "web3-utils": "1.3.0" } }, "web3-net": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.2.9.tgz", - "integrity": "sha512-d2mTn8jPlg+SI2hTj2b32Qan6DmtU9ap/IUlJTeQbZQSkTLf0u9suW8Vjwyr4poJYXTurdSshE7OZsPNn30/ZA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.3.0.tgz", + "integrity": "sha512-Xz02KylOyrB2YZzCkysEDrY7RbKxb7LADzx3Zlovfvuby7HBwtXVexXKtoGqksa+ns1lvjQLLQGb+OeLi7Sr7w==", "requires": { - "web3-core": "1.2.9", - "web3-core-method": "1.2.9", - "web3-utils": "1.2.9" + "web3-core": "1.3.0", + "web3-core-method": "1.3.0", + "web3-utils": "1.3.0" } }, "web3-providers-http": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.2.9.tgz", - "integrity": "sha512-F956tCIj60Ttr0UvEHWFIhx+be3He8msoPzyA44/kfzzYoMAsCFRn5cf0zQG6al0znE75g6HlWVSN6s3yAh51A==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.3.0.tgz", + "integrity": "sha512-cMKhUI6PqlY/EC+ZDacAxajySBu8AzW8jOjt1Pe/mbRQgS0rcZyvLePGTTuoyaA8C21F8UW+EE5jj7YsNgOuqA==", "requires": { - "web3-core-helpers": "1.2.9", + "web3-core-helpers": "1.3.0", "xhr2-cookies": "1.1.0" } }, "web3-providers-ipc": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.2.9.tgz", - "integrity": "sha512-NQ8QnBleoHA2qTJlqoWu7EJAD/FR5uimf7Ielzk4Z2z+m+6UAuJdJMSuQNj+Umhz9L/Ys6vpS1vHx9NizFl+aQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.3.0.tgz", + "integrity": "sha512-0CrLuRofR+1J38nEj4WsId/oolwQEM6Yl1sOt41S/6bNI7htdkwgVhSloFIMJMDFHtRw229QIJ6wIaKQz0X1Og==", "requires": { - "oboe": "2.1.4", + "oboe": "2.1.5", "underscore": "1.9.1", - "web3-core-helpers": "1.2.9" + "web3-core-helpers": "1.3.0" } }, "web3-providers-ws": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.2.9.tgz", - "integrity": "sha512-6+UpvINeI//dglZoAKStUXqxDOXJy6Iitv2z3dbgInG4zb8tkYl/VBDL80UjUg3ZvzWG0g7EKY2nRPEpON2TFA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.3.0.tgz", + "integrity": "sha512-Im5MthhJnJst8nSoq0TgbyOdaiFQFa5r6sHPOVllhgIgViDqzbnlAFW9sNzQ0Q8VXPNfPIQKi9cOrHlSRNPjRw==", "requires": { - "eventemitter3": "^4.0.0", + "eventemitter3": "4.0.4", "underscore": "1.9.1", - "web3-core-helpers": "1.2.9", - "websocket": "^1.0.31" - }, - "dependencies": { - "eventemitter3": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", - "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==" - } + "web3-core-helpers": "1.3.0", + "websocket": "^1.0.32" } }, "web3-shh": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.2.9.tgz", - "integrity": "sha512-PWa8b/EaxaMinFaxy6cV0i0EOi2M7a/ST+9k9nhyhCjVa2vzXuNoBNo2IUOmeZ0WP2UQB8ByJ2+p4htlJaDOjA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.3.0.tgz", + "integrity": "sha512-IZTojA4VCwVq+7eEIHuL1tJXtU+LJDhO8Y2QmuwetEWW1iBgWCGPHZasipWP+7kDpSm/5lo5GRxL72FF/Os/tA==", "requires": { - "web3-core": "1.2.9", - "web3-core-method": "1.2.9", - "web3-core-subscriptions": "1.2.9", - "web3-net": "1.2.9" + "web3-core": "1.3.0", + "web3-core-method": "1.3.0", + "web3-core-subscriptions": "1.3.0", + "web3-net": "1.3.0" } }, "web3-utils": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.2.9.tgz", - "integrity": "sha512-9hcpuis3n/LxFzEVjwnVgvJzTirS2S9/MiNAa7l4WOEoywY+BSNwnRX4MuHnjkh9NY25B6QOjuNG6FNnSjTw1w==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.3.0.tgz", + "integrity": "sha512-2mS5axFCbkhicmoDRuJeuo0TVGQDgC2sPi/5dblfVC+PMtX0efrb8Xlttv/eGkq7X4E83Pds34FH98TP2WOUZA==", "requires": { - "bn.js": "4.11.8", - "eth-lib": "0.2.7", + "bn.js": "^4.11.9", + "eth-lib": "0.2.8", "ethereum-bloom-filters": "^1.0.6", "ethjs-unit": "0.1.6", "number-to-bn": "1.7.0", @@ -11070,9 +9581,9 @@ }, "dependencies": { "eth-lib": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.7.tgz", - "integrity": "sha1-L5Pxex4jrsN1nNSj/iDBKGo/wco=", + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz", + "integrity": "sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw==", "requires": { "bn.js": "^4.11.6", "elliptic": "^6.4.0", @@ -11080,93 +9591,61 @@ } } } - }, - "websocket": { - "version": "1.0.31", - "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.31.tgz", - "integrity": "sha512-VAouplvGKPiKFDTeCCO65vYHsyay8DqoBSlzIO3fayrfOgU94lQN5a1uWVnFrMLceTJw/+fQXR5PGbUVRaHshQ==", - "requires": { - "debug": "^2.2.0", - "es5-ext": "^0.10.50", - "nan": "^2.14.0", - "typedarray-to-buffer": "^3.1.5", - "yaeti": "^0.0.6" - } } } }, "web3-bzz": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.2.2.tgz", - "integrity": "sha512-b1O2ObsqUN1lJxmFSjvnEC4TsaCbmh7Owj3IAIWTKqL9qhVgx7Qsu5O9cD13pBiSPNZJ68uJPaKq380QB4NWeA==", - "dev": true, + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.2.1.tgz", + "integrity": "sha512-LdOO44TuYbGIPfL4ilkuS89GQovxUpmLz6C1UC7VYVVRILeZS740FVB3j9V4P4FHUk1RenaDfKhcntqgVCHtjw==", "requires": { - "@types/node": "^10.12.18", "got": "9.6.0", "swarm-js": "0.1.39", "underscore": "1.9.1" - }, - "dependencies": { - "@types/node": { - "version": "10.17.26", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.26.tgz", - "integrity": "sha512-myMwkO2Cr82kirHY8uknNRHEVtn0wV3DTQfkrjx17jmkstDRZ24gNUdl8AHXVyVclTYI/bNjgTPTAWvWLqXqkw==", - "dev": true - } } }, "web3-core": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.2.2.tgz", - "integrity": "sha512-miHAX3qUgxV+KYfaOY93Hlc3kLW2j5fH8FJy6kSxAv+d4d5aH0wwrU2IIoJylQdT+FeenQ38sgsCnFu9iZ1hCQ==", - "dev": true, + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.2.1.tgz", + "integrity": "sha512-5ODwIqgl8oIg/0+Ai4jsLxkKFWJYE0uLuE1yUKHNVCL4zL6n3rFjRMpKPokd6id6nJCNgeA64KdWQ4XfpnjdMg==", "requires": { - "@types/bn.js": "^4.11.4", - "@types/node": "^12.6.1", - "web3-core-helpers": "1.2.2", - "web3-core-method": "1.2.2", - "web3-core-requestmanager": "1.2.2", - "web3-utils": "1.2.2" + "web3-core-helpers": "1.2.1", + "web3-core-method": "1.2.1", + "web3-core-requestmanager": "1.2.1", + "web3-utils": "1.2.1" }, "dependencies": { - "@types/node": { - "version": "12.12.47", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.47.tgz", - "integrity": "sha512-yzBInQFhdY8kaZmqoL2+3U5dSTMrKaYcb561VU+lDzAYvqt+2lojvBEy+hmpSNuXnPTx7m9+04CzWYOUqWME2A==", - "dev": true - }, "web3-core-helpers": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.2.tgz", - "integrity": "sha512-HJrRsIGgZa1jGUIhvGz4S5Yh6wtOIo/TMIsSLe+Xay+KVnbseJpPprDI5W3s7H2ODhMQTbogmmUFquZweW2ImQ==", - "dev": true, + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.1.tgz", + "integrity": "sha512-Gx3sTEajD5r96bJgfuW377PZVFmXIH4TdqDhgGwd2lZQCcMi+DA4TgxJNJGxn0R3aUVzyyE76j4LBrh412mXrw==", "requires": { "underscore": "1.9.1", - "web3-eth-iban": "1.2.2", - "web3-utils": "1.2.2" + "web3-eth-iban": "1.2.1", + "web3-utils": "1.2.1" } } } }, "web3-core-helpers": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.9.tgz", - "integrity": "sha512-t0WAG3orLCE3lqi77ZoSRNFok3VQWZXTniZigDQjyOJYMAX7BU3F3js8HKbjVnAxlX3tiKoDxI0KBk9F3AxYuw==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.3.0.tgz", + "integrity": "sha512-+MFb1kZCrRctf7UYE7NCG4rGhSXaQJ/KF07di9GVK1pxy1K0+rFi61ZobuV1ky9uQp+uhhSPts4Zp55kRDB5sw==", "requires": { "underscore": "1.9.1", - "web3-eth-iban": "1.2.9", - "web3-utils": "1.2.9" + "web3-eth-iban": "1.3.0", + "web3-utils": "1.3.0" }, "dependencies": { "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" }, "eth-lib": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.7.tgz", - "integrity": "sha1-L5Pxex4jrsN1nNSj/iDBKGo/wco=", + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz", + "integrity": "sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw==", "requires": { "bn.js": "^4.11.6", "elliptic": "^6.4.0", @@ -11174,21 +9653,21 @@ } }, "web3-eth-iban": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.2.9.tgz", - "integrity": "sha512-RtdVvJE0pyg9dHLy0GzDiqgnLnssSzfz/JYguhC1wsj9+Gnq1M6Diy3NixACWUAp6ty/zafyOaZnNQ+JuH9TjQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.3.0.tgz", + "integrity": "sha512-v9mZWhR4fPF17/KhHLiWir4YHWLe09O3B/NTdhWqw3fdAMJNztzMHGzgHxA/4fU+rhrs/FhDzc4yt32zMEXBZw==", "requires": { - "bn.js": "4.11.8", - "web3-utils": "1.2.9" + "bn.js": "^4.11.9", + "web3-utils": "1.3.0" } }, "web3-utils": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.2.9.tgz", - "integrity": "sha512-9hcpuis3n/LxFzEVjwnVgvJzTirS2S9/MiNAa7l4WOEoywY+BSNwnRX4MuHnjkh9NY25B6QOjuNG6FNnSjTw1w==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.3.0.tgz", + "integrity": "sha512-2mS5axFCbkhicmoDRuJeuo0TVGQDgC2sPi/5dblfVC+PMtX0efrb8Xlttv/eGkq7X4E83Pds34FH98TP2WOUZA==", "requires": { - "bn.js": "4.11.8", - "eth-lib": "0.2.7", + "bn.js": "^4.11.9", + "eth-lib": "0.2.8", "ethereum-bloom-filters": "^1.0.6", "ethjs-unit": "0.1.6", "number-to-bn": "1.7.0", @@ -11200,295 +9679,504 @@ } }, "web3-core-method": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.2.2.tgz", - "integrity": "sha512-szR4fDSBxNHaF1DFqE+j6sFR/afv9Aa36OW93saHZnrh+iXSrYeUUDfugeNcRlugEKeUCkd4CZylfgbK2SKYJA==", - "dev": true, + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.2.1.tgz", + "integrity": "sha512-Ghg2WS23qi6Xj8Od3VCzaImLHseEA7/usvnOItluiIc5cKs00WYWsNy2YRStzU9a2+z8lwQywPYp0nTzR/QXdQ==", "requires": { "underscore": "1.9.1", - "web3-core-helpers": "1.2.2", - "web3-core-promievent": "1.2.2", - "web3-core-subscriptions": "1.2.2", - "web3-utils": "1.2.2" + "web3-core-helpers": "1.2.1", + "web3-core-promievent": "1.2.1", + "web3-core-subscriptions": "1.2.1", + "web3-utils": "1.2.1" }, "dependencies": { "web3-core-helpers": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.2.tgz", - "integrity": "sha512-HJrRsIGgZa1jGUIhvGz4S5Yh6wtOIo/TMIsSLe+Xay+KVnbseJpPprDI5W3s7H2ODhMQTbogmmUFquZweW2ImQ==", - "dev": true, + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.1.tgz", + "integrity": "sha512-Gx3sTEajD5r96bJgfuW377PZVFmXIH4TdqDhgGwd2lZQCcMi+DA4TgxJNJGxn0R3aUVzyyE76j4LBrh412mXrw==", "requires": { "underscore": "1.9.1", - "web3-eth-iban": "1.2.2", - "web3-utils": "1.2.2" + "web3-eth-iban": "1.2.1", + "web3-utils": "1.2.1" } } } }, "web3-core-promievent": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.2.2.tgz", - "integrity": "sha512-tKvYeT8bkUfKABcQswK6/X79blKTKYGk949urZKcLvLDEaWrM3uuzDwdQT3BNKzQ3vIvTggFPX9BwYh0F1WwqQ==", - "dev": true, + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.2.1.tgz", + "integrity": "sha512-IVUqgpIKoeOYblwpex4Hye6npM0aMR+kU49VP06secPeN0rHMyhGF0ZGveWBrGvf8WDPI7jhqPBFIC6Jf3Q3zw==", "requires": { "any-promise": "1.3.0", "eventemitter3": "3.1.2" } }, "web3-core-requestmanager": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.2.2.tgz", - "integrity": "sha512-a+gSbiBRHtHvkp78U2bsntMGYGF2eCb6219aMufuZWeAZGXJ63Wc2321PCbA8hF9cQrZI4EoZ4kVLRI4OF15Hw==", - "dev": true, + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.2.1.tgz", + "integrity": "sha512-xfknTC69RfYmLKC+83Jz73IC3/sS2ZLhGtX33D4Q5nQ8yc39ElyAolxr9sJQS8kihOcM6u4J+8gyGMqsLcpIBg==", "requires": { "underscore": "1.9.1", - "web3-core-helpers": "1.2.2", - "web3-providers-http": "1.2.2", - "web3-providers-ipc": "1.2.2", - "web3-providers-ws": "1.2.2" + "web3-core-helpers": "1.2.1", + "web3-providers-http": "1.2.1", + "web3-providers-ipc": "1.2.1", + "web3-providers-ws": "1.2.1" }, "dependencies": { "web3-core-helpers": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.2.tgz", - "integrity": "sha512-HJrRsIGgZa1jGUIhvGz4S5Yh6wtOIo/TMIsSLe+Xay+KVnbseJpPprDI5W3s7H2ODhMQTbogmmUFquZweW2ImQ==", - "dev": true, + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.1.tgz", + "integrity": "sha512-Gx3sTEajD5r96bJgfuW377PZVFmXIH4TdqDhgGwd2lZQCcMi+DA4TgxJNJGxn0R3aUVzyyE76j4LBrh412mXrw==", "requires": { "underscore": "1.9.1", - "web3-eth-iban": "1.2.2", - "web3-utils": "1.2.2" + "web3-eth-iban": "1.2.1", + "web3-utils": "1.2.1" } } } }, "web3-core-subscriptions": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.2.2.tgz", - "integrity": "sha512-QbTgigNuT4eicAWWr7ahVpJyM8GbICsR1Ys9mJqzBEwpqS+RXTRVSkwZ2IsxO+iqv6liMNwGregbJLq4urMFcQ==", - "dev": true, + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.2.1.tgz", + "integrity": "sha512-nmOwe3NsB8V8UFsY1r+sW6KjdOS68h8nuh7NzlWxBQT/19QSUGiERRTaZXWu5BYvo1EoZRMxCKyCQpSSXLc08g==", "requires": { "eventemitter3": "3.1.2", "underscore": "1.9.1", - "web3-core-helpers": "1.2.2" + "web3-core-helpers": "1.2.1" }, "dependencies": { "web3-core-helpers": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.2.tgz", - "integrity": "sha512-HJrRsIGgZa1jGUIhvGz4S5Yh6wtOIo/TMIsSLe+Xay+KVnbseJpPprDI5W3s7H2ODhMQTbogmmUFquZweW2ImQ==", - "dev": true, + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.1.tgz", + "integrity": "sha512-Gx3sTEajD5r96bJgfuW377PZVFmXIH4TdqDhgGwd2lZQCcMi+DA4TgxJNJGxn0R3aUVzyyE76j4LBrh412mXrw==", "requires": { "underscore": "1.9.1", - "web3-eth-iban": "1.2.2", - "web3-utils": "1.2.2" + "web3-eth-iban": "1.2.1", + "web3-utils": "1.2.1" } } } }, "web3-eth": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.2.2.tgz", - "integrity": "sha512-UXpC74mBQvZzd4b+baD4Ocp7g+BlwxhBHumy9seyE/LMIcMlePXwCKzxve9yReNpjaU16Mmyya6ZYlyiKKV8UA==", - "dev": true, + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.2.1.tgz", + "integrity": "sha512-/2xly4Yry5FW1i+uygPjhfvgUP/MS/Dk+PDqmzp5M88tS86A+j8BzKc23GrlA8sgGs0645cpZK/999LpEF5UdA==", "requires": { "underscore": "1.9.1", - "web3-core": "1.2.2", - "web3-core-helpers": "1.2.2", - "web3-core-method": "1.2.2", - "web3-core-subscriptions": "1.2.2", - "web3-eth-abi": "1.2.2", - "web3-eth-accounts": "1.2.2", - "web3-eth-contract": "1.2.2", - "web3-eth-ens": "1.2.2", - "web3-eth-iban": "1.2.2", - "web3-eth-personal": "1.2.2", - "web3-net": "1.2.2", - "web3-utils": "1.2.2" + "web3-core": "1.2.1", + "web3-core-helpers": "1.2.1", + "web3-core-method": "1.2.1", + "web3-core-subscriptions": "1.2.1", + "web3-eth-abi": "1.2.1", + "web3-eth-accounts": "1.2.1", + "web3-eth-contract": "1.2.1", + "web3-eth-ens": "1.2.1", + "web3-eth-iban": "1.2.1", + "web3-eth-personal": "1.2.1", + "web3-net": "1.2.1", + "web3-utils": "1.2.1" }, "dependencies": { "web3-core-helpers": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.2.tgz", - "integrity": "sha512-HJrRsIGgZa1jGUIhvGz4S5Yh6wtOIo/TMIsSLe+Xay+KVnbseJpPprDI5W3s7H2ODhMQTbogmmUFquZweW2ImQ==", - "dev": true, + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.1.tgz", + "integrity": "sha512-Gx3sTEajD5r96bJgfuW377PZVFmXIH4TdqDhgGwd2lZQCcMi+DA4TgxJNJGxn0R3aUVzyyE76j4LBrh412mXrw==", "requires": { "underscore": "1.9.1", - "web3-eth-iban": "1.2.2", - "web3-utils": "1.2.2" + "web3-eth-iban": "1.2.1", + "web3-utils": "1.2.1" } }, "web3-eth-contract": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.2.2.tgz", - "integrity": "sha512-EKT2yVFws3FEdotDQoNsXTYL798+ogJqR2//CaGwx3p0/RvQIgfzEwp8nbgA6dMxCsn9KOQi7OtklzpnJMkjtA==", - "dev": true, + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.2.1.tgz", + "integrity": "sha512-kYFESbQ3boC9bl2rYVghj7O8UKMiuKaiMkxvRH5cEDHil8V7MGEGZNH0slSdoyeftZVlaWSMqkRP/chfnKND0g==", "requires": { - "@types/bn.js": "^4.11.4", "underscore": "1.9.1", - "web3-core": "1.2.2", - "web3-core-helpers": "1.2.2", - "web3-core-method": "1.2.2", - "web3-core-promievent": "1.2.2", - "web3-core-subscriptions": "1.2.2", - "web3-eth-abi": "1.2.2", - "web3-utils": "1.2.2" + "web3-core": "1.2.1", + "web3-core-helpers": "1.2.1", + "web3-core-method": "1.2.1", + "web3-core-promievent": "1.2.1", + "web3-core-subscriptions": "1.2.1", + "web3-eth-abi": "1.2.1", + "web3-utils": "1.2.1" } } } }, "web3-eth-abi": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.2.2.tgz", - "integrity": "sha512-Yn/ZMgoOLxhTVxIYtPJ0eS6pnAnkTAaJgUJh1JhZS4ekzgswMfEYXOwpMaD5eiqPJLpuxmZFnXnBZlnQ1JMXsw==", - "dev": true, + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.2.1.tgz", + "integrity": "sha512-jI/KhU2a/DQPZXHjo2GW0myEljzfiKOn+h1qxK1+Y9OQfTcBMxrQJyH5AP89O6l6NZ1QvNdq99ThAxBFoy5L+g==", "requires": { "ethers": "4.0.0-beta.3", "underscore": "1.9.1", - "web3-utils": "1.2.2" - }, - "dependencies": { - "@types/node": { - "version": "10.17.26", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.26.tgz", - "integrity": "sha512-myMwkO2Cr82kirHY8uknNRHEVtn0wV3DTQfkrjx17jmkstDRZ24gNUdl8AHXVyVclTYI/bNjgTPTAWvWLqXqkw==", - "dev": true - }, - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", - "dev": true - }, - "elliptic": { - "version": "6.3.3", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.3.3.tgz", - "integrity": "sha1-VILZZG1UvLif19mU/J4ulWiHbj8=", - "dev": true, - "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "inherits": "^2.0.1" - } - }, - "ethers": { - "version": "4.0.0-beta.3", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.0-beta.3.tgz", - "integrity": "sha512-YYPogooSknTwvHg3+Mv71gM/3Wcrx+ZpCzarBj3mqs9njjRkrOo2/eufzhHloOCo3JSoNI4TQJJ6yU5ABm3Uog==", - "dev": true, - "requires": { - "@types/node": "^10.3.2", - "aes-js": "3.0.0", - "bn.js": "^4.4.0", - "elliptic": "6.3.3", - "hash.js": "1.1.3", - "js-sha3": "0.5.7", - "scrypt-js": "2.0.3", - "setimmediate": "1.0.4", - "uuid": "2.0.1", - "xmlhttprequest": "1.8.0" - } - }, - "hash.js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", - "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.0" - } - }, - "scrypt-js": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.3.tgz", - "integrity": "sha1-uwBAvgMEPamgEqLOqfyfhSz8h9Q=", - "dev": true - } + "web3-utils": "1.2.1" } }, "web3-eth-accounts": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.2.2.tgz", - "integrity": "sha512-KzHOEyXOEZ13ZOkWN3skZKqSo5f4Z1ogPFNn9uZbKCz+kSp+gCAEKxyfbOsB/JMAp5h7o7pb6eYsPCUBJmFFiA==", - "dev": true, + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.2.1.tgz", + "integrity": "sha512-26I4qq42STQ8IeKUyur3MdQ1NzrzCqPsmzqpux0j6X/XBD7EjZ+Cs0lhGNkSKH5dI3V8CJasnQ5T1mNKeWB7nQ==", "requires": { "any-promise": "1.3.0", "crypto-browserify": "3.12.0", "eth-lib": "0.2.7", - "ethereumjs-common": "^1.3.2", - "ethereumjs-tx": "^2.1.1", - "scrypt-shim": "github:web3-js/scrypt-shim", + "scryptsy": "2.1.0", + "semver": "6.2.0", "underscore": "1.9.1", "uuid": "3.3.2", - "web3-core": "1.2.2", - "web3-core-helpers": "1.2.2", - "web3-core-method": "1.2.2", - "web3-utils": "1.2.2" + "web3-core": "1.2.1", + "web3-core-helpers": "1.2.1", + "web3-core-method": "1.2.1", + "web3-utils": "1.2.1" }, "dependencies": { "bn.js": { "version": "4.11.9", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", - "dev": true + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" }, "eth-lib": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.7.tgz", "integrity": "sha1-L5Pxex4jrsN1nNSj/iDBKGo/wco=", - "dev": true, "requires": { "bn.js": "^4.11.6", "elliptic": "^6.4.0", "xhr-request-promise": "^0.1.2" } }, + "semver": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.2.0.tgz", + "integrity": "sha512-jdFC1VdUGT/2Scgbimf7FSx9iJLXoqfglSF+gJeuNWVpiE37OIbc1jywR/GJyFdz3mnkz2/id0L0J/cr0izR5A==" + }, "uuid": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", - "dev": true + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" }, "web3-core-helpers": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.2.tgz", - "integrity": "sha512-HJrRsIGgZa1jGUIhvGz4S5Yh6wtOIo/TMIsSLe+Xay+KVnbseJpPprDI5W3s7H2ODhMQTbogmmUFquZweW2ImQ==", - "dev": true, + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.1.tgz", + "integrity": "sha512-Gx3sTEajD5r96bJgfuW377PZVFmXIH4TdqDhgGwd2lZQCcMi+DA4TgxJNJGxn0R3aUVzyyE76j4LBrh412mXrw==", "requires": { "underscore": "1.9.1", - "web3-eth-iban": "1.2.2", - "web3-utils": "1.2.2" + "web3-eth-iban": "1.2.1", + "web3-utils": "1.2.1" } } } }, "web3-eth-contract": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.2.9.tgz", - "integrity": "sha512-PYMvJf7EG/HyssUZa+pXrc8IB06K/YFfWYyW4R7ed3sab+9wWUys1TlWxBCBuiBXOokSAyM6H6P6/cKEx8FT8Q==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.3.0.tgz", + "integrity": "sha512-3SCge4SRNCnzLxf0R+sXk6vyTOl05g80Z5+9/B5pERwtPpPWaQGw8w01vqYqsYBKC7zH+dxhMaUgVzU2Dgf7bQ==", "requires": { - "@types/bn.js": "^4.11.4", + "@types/bn.js": "^4.11.5", "underscore": "1.9.1", - "web3-core": "1.2.9", - "web3-core-helpers": "1.2.9", - "web3-core-method": "1.2.9", - "web3-core-promievent": "1.2.9", - "web3-core-subscriptions": "1.2.9", - "web3-eth-abi": "1.2.9", - "web3-utils": "1.2.9" + "web3-core": "1.3.0", + "web3-core-helpers": "1.3.0", + "web3-core-method": "1.3.0", + "web3-core-promievent": "1.3.0", + "web3-core-subscriptions": "1.3.0", + "web3-eth-abi": "1.3.0", + "web3-utils": "1.3.0" }, "dependencies": { "@types/node": { - "version": "12.12.47", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.47.tgz", - "integrity": "sha512-yzBInQFhdY8kaZmqoL2+3U5dSTMrKaYcb561VU+lDzAYvqt+2lojvBEy+hmpSNuXnPTx7m9+04CzWYOUqWME2A==" + "version": "12.19.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.3.tgz", + "integrity": "sha512-8Jduo8wvvwDzEVJCOvS/G6sgilOLvvhn1eMmK3TW8/T217O7u1jdrK6ImKLv80tVryaPSVeKu6sjDEiFjd4/eg==" }, + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + }, + "eth-lib": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz", + "integrity": "sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw==", + "requires": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + } + }, + "eventemitter3": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", + "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==" + }, + "oboe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.5.tgz", + "integrity": "sha1-VVQoTFQ6ImbXo48X4HOCH73jk80=", + "requires": { + "http-https": "^1.0.0" + } + }, + "web3-core": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.3.0.tgz", + "integrity": "sha512-BwWvAaKJf4KFG9QsKRi3MNoNgzjI6szyUlgme1qNPxUdCkaS3Rdpa0VKYNHP7M/YTk82/59kNE66mH5vmoaXjA==", + "requires": { + "@types/bn.js": "^4.11.5", + "@types/node": "^12.12.6", + "bignumber.js": "^9.0.0", + "web3-core-helpers": "1.3.0", + "web3-core-method": "1.3.0", + "web3-core-requestmanager": "1.3.0", + "web3-utils": "1.3.0" + } + }, + "web3-core-method": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.3.0.tgz", + "integrity": "sha512-h0yFDrYVzy5WkLxC/C3q+hiMnzxdWm9p1T1rslnuHgOp6nYfqzu/6mUIXrsS4h/OWiGJt+BZ0xVZmtC31HDWtg==", + "requires": { + "@ethersproject/transactions": "^5.0.0-beta.135", + "underscore": "1.9.1", + "web3-core-helpers": "1.3.0", + "web3-core-promievent": "1.3.0", + "web3-core-subscriptions": "1.3.0", + "web3-utils": "1.3.0" + } + }, + "web3-core-promievent": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.3.0.tgz", + "integrity": "sha512-blv69wrXw447TP3iPvYJpllkhW6B18nfuEbrfcr3n2Y0v1Jx8VJacNZFDFsFIcgXcgUIVCtOpimU7w9v4+rtaw==", + "requires": { + "eventemitter3": "4.0.4" + } + }, + "web3-core-requestmanager": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.3.0.tgz", + "integrity": "sha512-3yMbuGcomtzlmvTVqNRydxsx7oPlw3ioRL6ReF9PeNYDkUsZaUib+6Dp5eBt7UXh5X+SIn/xa1smhDHz5/HpAw==", + "requires": { + "underscore": "1.9.1", + "web3-core-helpers": "1.3.0", + "web3-providers-http": "1.3.0", + "web3-providers-ipc": "1.3.0", + "web3-providers-ws": "1.3.0" + } + }, + "web3-core-subscriptions": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.3.0.tgz", + "integrity": "sha512-MUUQUAhJDb+Nz3S97ExVWveH4utoUnsbPWP+q1HJH437hEGb4vunIb9KvN3hFHLB+aHJfPeStM/4yYTz5PeuyQ==", + "requires": { + "eventemitter3": "4.0.4", + "underscore": "1.9.1", + "web3-core-helpers": "1.3.0" + } + }, + "web3-eth-abi": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.3.0.tgz", + "integrity": "sha512-1OrZ9+KGrBeBRd3lO8upkpNua9+7cBsQAgor9wbA25UrcUYSyL8teV66JNRu9gFxaTbkpdrGqM7J/LXpraXWrg==", + "requires": { + "@ethersproject/abi": "5.0.0-beta.153", + "underscore": "1.9.1", + "web3-utils": "1.3.0" + } + }, + "web3-providers-http": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.3.0.tgz", + "integrity": "sha512-cMKhUI6PqlY/EC+ZDacAxajySBu8AzW8jOjt1Pe/mbRQgS0rcZyvLePGTTuoyaA8C21F8UW+EE5jj7YsNgOuqA==", + "requires": { + "web3-core-helpers": "1.3.0", + "xhr2-cookies": "1.1.0" + } + }, + "web3-providers-ipc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.3.0.tgz", + "integrity": "sha512-0CrLuRofR+1J38nEj4WsId/oolwQEM6Yl1sOt41S/6bNI7htdkwgVhSloFIMJMDFHtRw229QIJ6wIaKQz0X1Og==", + "requires": { + "oboe": "2.1.5", + "underscore": "1.9.1", + "web3-core-helpers": "1.3.0" + } + }, + "web3-providers-ws": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.3.0.tgz", + "integrity": "sha512-Im5MthhJnJst8nSoq0TgbyOdaiFQFa5r6sHPOVllhgIgViDqzbnlAFW9sNzQ0Q8VXPNfPIQKi9cOrHlSRNPjRw==", + "requires": { + "eventemitter3": "4.0.4", + "underscore": "1.9.1", + "web3-core-helpers": "1.3.0", + "websocket": "^1.0.32" + } + }, + "web3-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.3.0.tgz", + "integrity": "sha512-2mS5axFCbkhicmoDRuJeuo0TVGQDgC2sPi/5dblfVC+PMtX0efrb8Xlttv/eGkq7X4E83Pds34FH98TP2WOUZA==", + "requires": { + "bn.js": "^4.11.9", + "eth-lib": "0.2.8", + "ethereum-bloom-filters": "^1.0.6", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "underscore": "1.9.1", + "utf8": "3.0.0" + } + } + } + }, + "web3-eth-ens": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.2.1.tgz", + "integrity": "sha512-lhP1kFhqZr2nnbu3CGIFFrAnNxk2veXpOXBY48Tub37RtobDyHijHgrj+xTh+mFiPokyrapVjpFsbGa+Xzye4Q==", + "requires": { + "eth-ens-namehash": "2.0.8", + "underscore": "1.9.1", + "web3-core": "1.2.1", + "web3-core-helpers": "1.2.1", + "web3-core-promievent": "1.2.1", + "web3-eth-abi": "1.2.1", + "web3-eth-contract": "1.2.1", + "web3-utils": "1.2.1" + }, + "dependencies": { + "web3-core-helpers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.1.tgz", + "integrity": "sha512-Gx3sTEajD5r96bJgfuW377PZVFmXIH4TdqDhgGwd2lZQCcMi+DA4TgxJNJGxn0R3aUVzyyE76j4LBrh412mXrw==", + "requires": { + "underscore": "1.9.1", + "web3-eth-iban": "1.2.1", + "web3-utils": "1.2.1" + } + }, + "web3-eth-contract": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.2.1.tgz", + "integrity": "sha512-kYFESbQ3boC9bl2rYVghj7O8UKMiuKaiMkxvRH5cEDHil8V7MGEGZNH0slSdoyeftZVlaWSMqkRP/chfnKND0g==", + "requires": { + "underscore": "1.9.1", + "web3-core": "1.2.1", + "web3-core-helpers": "1.2.1", + "web3-core-method": "1.2.1", + "web3-core-promievent": "1.2.1", + "web3-core-subscriptions": "1.2.1", + "web3-eth-abi": "1.2.1", + "web3-utils": "1.2.1" + } + } + } + }, + "web3-eth-iban": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.2.1.tgz", + "integrity": "sha512-9gkr4QPl1jCU+wkgmZ8EwODVO3ovVj6d6JKMos52ggdT2YCmlfvFVF6wlGLwi0VvNa/p+0BjJzaqxnnG/JewjQ==", + "requires": { + "bn.js": "4.11.8", + "web3-utils": "1.2.1" + }, + "dependencies": { "bn.js": { "version": "4.11.8", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" - }, + } + } + }, + "web3-eth-personal": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.2.1.tgz", + "integrity": "sha512-RNDVSiaSoY4aIp8+Hc7z+X72H7lMb3fmAChuSBADoEc7DsJrY/d0R5qQDK9g9t2BO8oxgLrLNyBP/9ub2Hc6Bg==", + "requires": { + "web3-core": "1.2.1", + "web3-core-helpers": "1.2.1", + "web3-core-method": "1.2.1", + "web3-net": "1.2.1", + "web3-utils": "1.2.1" + }, + "dependencies": { + "web3-core-helpers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.1.tgz", + "integrity": "sha512-Gx3sTEajD5r96bJgfuW377PZVFmXIH4TdqDhgGwd2lZQCcMi+DA4TgxJNJGxn0R3aUVzyyE76j4LBrh412mXrw==", + "requires": { + "underscore": "1.9.1", + "web3-eth-iban": "1.2.1", + "web3-utils": "1.2.1" + } + } + } + }, + "web3-net": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.2.1.tgz", + "integrity": "sha512-Yt1Bs7WgnLESPe0rri/ZoPWzSy55ovioaP35w1KZydrNtQ5Yq4WcrAdhBzcOW7vAkIwrsLQsvA+hrOCy7mNauw==", + "requires": { + "web3-core": "1.2.1", + "web3-core-method": "1.2.1", + "web3-utils": "1.2.1" + } + }, + "web3-providers-http": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.2.1.tgz", + "integrity": "sha512-BDtVUVolT9b3CAzeGVA/np1hhn7RPUZ6YYGB/sYky+GjeO311Yoq8SRDUSezU92x8yImSC2B+SMReGhd1zL+bQ==", + "requires": { + "web3-core-helpers": "1.2.1", + "xhr2-cookies": "1.1.0" + }, + "dependencies": { + "web3-core-helpers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.1.tgz", + "integrity": "sha512-Gx3sTEajD5r96bJgfuW377PZVFmXIH4TdqDhgGwd2lZQCcMi+DA4TgxJNJGxn0R3aUVzyyE76j4LBrh412mXrw==", + "requires": { + "underscore": "1.9.1", + "web3-eth-iban": "1.2.1", + "web3-utils": "1.2.1" + } + } + } + }, + "web3-providers-ipc": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.2.1.tgz", + "integrity": "sha512-oPEuOCwxVx8L4CPD0TUdnlOUZwGBSRKScCz/Ws2YHdr9Ium+whm+0NLmOZjkjQp5wovQbyBzNa6zJz1noFRvFA==", + "requires": { + "oboe": "2.1.4", + "underscore": "1.9.1", + "web3-core-helpers": "1.2.1" + }, + "dependencies": { + "web3-core-helpers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.1.tgz", + "integrity": "sha512-Gx3sTEajD5r96bJgfuW377PZVFmXIH4TdqDhgGwd2lZQCcMi+DA4TgxJNJGxn0R3aUVzyyE76j4LBrh412mXrw==", + "requires": { + "underscore": "1.9.1", + "web3-eth-iban": "1.2.1", + "web3-utils": "1.2.1" + } + } + } + }, + "web3-providers-ws": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.2.1.tgz", + "integrity": "sha512-oqsQXzu+ejJACVHy864WwIyw+oB21nw/pI65/sD95Zi98+/HQzFfNcIFneF1NC4bVF3VNX4YHTNq2I2o97LAiA==", + "requires": { + "underscore": "1.9.1", + "web3-core-helpers": "1.2.1", + "websocket": "github:web3-js/WebSocket-Node#polyfill/globalThis" + }, + "dependencies": { "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -11497,144 +10185,19 @@ "ms": "2.0.0" } }, - "eth-lib": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.7.tgz", - "integrity": "sha1-L5Pxex4jrsN1nNSj/iDBKGo/wco=", - "requires": { - "bn.js": "^4.11.6", - "elliptic": "^6.4.0", - "xhr-request-promise": "^0.1.2" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "web3-core": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.2.9.tgz", - "integrity": "sha512-fSYv21IP658Ty2wAuU9iqmW7V+75DOYMVZsDH/c14jcF/1VXnedOcxzxSj3vArsCvXZNe6XC5/wAuGZyQwR9RA==", - "requires": { - "@types/bn.js": "^4.11.4", - "@types/node": "^12.6.1", - "bignumber.js": "^9.0.0", - "web3-core-helpers": "1.2.9", - "web3-core-method": "1.2.9", - "web3-core-requestmanager": "1.2.9", - "web3-utils": "1.2.9" - } - }, - "web3-core-method": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.2.9.tgz", - "integrity": "sha512-bjsIoqP3gs7A/gP8+QeLUCyOKJ8bopteCSNbCX36Pxk6TYfYWNuC6hP+2GzUuqdP3xaZNe+XEElQFUNpR3oyAg==", - "requires": { - "@ethersproject/transactions": "^5.0.0-beta.135", - "underscore": "1.9.1", - "web3-core-helpers": "1.2.9", - "web3-core-promievent": "1.2.9", - "web3-core-subscriptions": "1.2.9", - "web3-utils": "1.2.9" - } - }, - "web3-core-promievent": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.2.9.tgz", - "integrity": "sha512-0eAUA2zjgXTleSrnc1wdoKQPPIHU6KHf4fAscu4W9kKrR+mqP1KsjYrxY9wUyjNnXxfQ+5M29ipvbiaK8OqdOw==", - "requires": { - "eventemitter3": "3.1.2" - } - }, - "web3-core-requestmanager": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.2.9.tgz", - "integrity": "sha512-1PwKV2m46ALUnIN5VPPgjOj8yMLJhhqZYvYJE34hTN5SErOkwhzx5zScvo5MN7v7KyQGFnpVCZKKGCiEnDmtFA==", + "web3-core-helpers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.1.tgz", + "integrity": "sha512-Gx3sTEajD5r96bJgfuW377PZVFmXIH4TdqDhgGwd2lZQCcMi+DA4TgxJNJGxn0R3aUVzyyE76j4LBrh412mXrw==", "requires": { "underscore": "1.9.1", - "web3-core-helpers": "1.2.9", - "web3-providers-http": "1.2.9", - "web3-providers-ipc": "1.2.9", - "web3-providers-ws": "1.2.9" - } - }, - "web3-core-subscriptions": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.2.9.tgz", - "integrity": "sha512-Y48TvXPSPxEM33OmXjGVDMzTd0j8X0t2+sDw66haeBS8eYnrEzasWuBZZXDq0zNUsqyxItgBGDn+cszkgEnFqg==", - "requires": { - "eventemitter3": "3.1.2", - "underscore": "1.9.1", - "web3-core-helpers": "1.2.9" - } - }, - "web3-eth-abi": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.2.9.tgz", - "integrity": "sha512-3YwUYbh/DMfDbhMWEebAdjSd5bj3ZQieOjLzWFHU23CaLEqT34sUix1lba+hgUH/EN6A7bKAuKOhR3p0OvTn7Q==", - "requires": { - "@ethersproject/abi": "5.0.0-beta.153", - "underscore": "1.9.1", - "web3-utils": "1.2.9" - } - }, - "web3-providers-http": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.2.9.tgz", - "integrity": "sha512-F956tCIj60Ttr0UvEHWFIhx+be3He8msoPzyA44/kfzzYoMAsCFRn5cf0zQG6al0znE75g6HlWVSN6s3yAh51A==", - "requires": { - "web3-core-helpers": "1.2.9", - "xhr2-cookies": "1.1.0" - } - }, - "web3-providers-ipc": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.2.9.tgz", - "integrity": "sha512-NQ8QnBleoHA2qTJlqoWu7EJAD/FR5uimf7Ielzk4Z2z+m+6UAuJdJMSuQNj+Umhz9L/Ys6vpS1vHx9NizFl+aQ==", - "requires": { - "oboe": "2.1.4", - "underscore": "1.9.1", - "web3-core-helpers": "1.2.9" - } - }, - "web3-providers-ws": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.2.9.tgz", - "integrity": "sha512-6+UpvINeI//dglZoAKStUXqxDOXJy6Iitv2z3dbgInG4zb8tkYl/VBDL80UjUg3ZvzWG0g7EKY2nRPEpON2TFA==", - "requires": { - "eventemitter3": "^4.0.0", - "underscore": "1.9.1", - "web3-core-helpers": "1.2.9", - "websocket": "^1.0.31" - }, - "dependencies": { - "eventemitter3": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", - "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==" - } - } - }, - "web3-utils": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.2.9.tgz", - "integrity": "sha512-9hcpuis3n/LxFzEVjwnVgvJzTirS2S9/MiNAa7l4WOEoywY+BSNwnRX4MuHnjkh9NY25B6QOjuNG6FNnSjTw1w==", - "requires": { - "bn.js": "4.11.8", - "eth-lib": "0.2.7", - "ethereum-bloom-filters": "^1.0.6", - "ethjs-unit": "0.1.6", - "number-to-bn": "1.7.0", - "randombytes": "^2.1.0", - "underscore": "1.9.1", - "utf8": "3.0.0" + "web3-eth-iban": "1.2.1", + "web3-utils": "1.2.1" } }, "websocket": { - "version": "1.0.31", - "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.31.tgz", - "integrity": "sha512-VAouplvGKPiKFDTeCCO65vYHsyay8DqoBSlzIO3fayrfOgU94lQN5a1uWVnFrMLceTJw/+fQXR5PGbUVRaHshQ==", + "version": "github:web3-js/WebSocket-Node#ef5ea2f41daf4a2113b80c9223df884b4d56c400", + "from": "github:web3-js/WebSocket-Node#polyfill/globalThis", "requires": { "debug": "^2.2.0", "es5-ext": "^0.10.50", @@ -11645,209 +10208,27 @@ } } }, - "web3-eth-ens": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.2.2.tgz", - "integrity": "sha512-CFjkr2HnuyMoMFBoNUWojyguD4Ef+NkyovcnUc/iAb9GP4LHohKrODG4pl76R5u61TkJGobC2ij6TyibtsyVYg==", - "dev": true, - "requires": { - "eth-ens-namehash": "2.0.8", - "underscore": "1.9.1", - "web3-core": "1.2.2", - "web3-core-helpers": "1.2.2", - "web3-core-promievent": "1.2.2", - "web3-eth-abi": "1.2.2", - "web3-eth-contract": "1.2.2", - "web3-utils": "1.2.2" - }, - "dependencies": { - "web3-core-helpers": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.2.tgz", - "integrity": "sha512-HJrRsIGgZa1jGUIhvGz4S5Yh6wtOIo/TMIsSLe+Xay+KVnbseJpPprDI5W3s7H2ODhMQTbogmmUFquZweW2ImQ==", - "dev": true, - "requires": { - "underscore": "1.9.1", - "web3-eth-iban": "1.2.2", - "web3-utils": "1.2.2" - } - }, - "web3-eth-contract": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.2.2.tgz", - "integrity": "sha512-EKT2yVFws3FEdotDQoNsXTYL798+ogJqR2//CaGwx3p0/RvQIgfzEwp8nbgA6dMxCsn9KOQi7OtklzpnJMkjtA==", - "dev": true, - "requires": { - "@types/bn.js": "^4.11.4", - "underscore": "1.9.1", - "web3-core": "1.2.2", - "web3-core-helpers": "1.2.2", - "web3-core-method": "1.2.2", - "web3-core-promievent": "1.2.2", - "web3-core-subscriptions": "1.2.2", - "web3-eth-abi": "1.2.2", - "web3-utils": "1.2.2" - } - } - } - }, - "web3-eth-iban": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.2.2.tgz", - "integrity": "sha512-gxKXBoUhaTFHr0vJB/5sd4i8ejF/7gIsbM/VvemHT3tF5smnmY6hcwSMmn7sl5Gs+83XVb/BngnnGkf+I/rsrQ==", - "dev": true, - "requires": { - "bn.js": "4.11.8", - "web3-utils": "1.2.2" - }, - "dependencies": { - "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", - "dev": true - } - } - }, - "web3-eth-personal": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.2.2.tgz", - "integrity": "sha512-4w+GLvTlFqW3+q4xDUXvCEMU7kRZ+xm/iJC8gm1Li1nXxwwFbs+Y+KBK6ZYtoN1qqAnHR+plYpIoVo27ixI5Rg==", - "dev": true, - "requires": { - "@types/node": "^12.6.1", - "web3-core": "1.2.2", - "web3-core-helpers": "1.2.2", - "web3-core-method": "1.2.2", - "web3-net": "1.2.2", - "web3-utils": "1.2.2" - }, - "dependencies": { - "@types/node": { - "version": "12.12.47", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.47.tgz", - "integrity": "sha512-yzBInQFhdY8kaZmqoL2+3U5dSTMrKaYcb561VU+lDzAYvqt+2lojvBEy+hmpSNuXnPTx7m9+04CzWYOUqWME2A==", - "dev": true - }, - "web3-core-helpers": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.2.tgz", - "integrity": "sha512-HJrRsIGgZa1jGUIhvGz4S5Yh6wtOIo/TMIsSLe+Xay+KVnbseJpPprDI5W3s7H2ODhMQTbogmmUFquZweW2ImQ==", - "dev": true, - "requires": { - "underscore": "1.9.1", - "web3-eth-iban": "1.2.2", - "web3-utils": "1.2.2" - } - } - } - }, - "web3-net": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.2.2.tgz", - "integrity": "sha512-K07j2DXq0x4UOJgae65rWZKraOznhk8v5EGSTdFqASTx7vWE/m+NqBijBYGEsQY1lSMlVaAY9UEQlcXK5HzXTw==", - "dev": true, - "requires": { - "web3-core": "1.2.2", - "web3-core-method": "1.2.2", - "web3-utils": "1.2.2" - } - }, - "web3-providers-http": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.2.2.tgz", - "integrity": "sha512-BNZ7Hguy3eBszsarH5gqr9SIZNvqk9eKwqwmGH1LQS1FL3NdoOn7tgPPdddrXec4fL94CwgNk4rCU+OjjZRNDg==", - "dev": true, - "requires": { - "web3-core-helpers": "1.2.2", - "xhr2-cookies": "1.1.0" - }, - "dependencies": { - "web3-core-helpers": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.2.tgz", - "integrity": "sha512-HJrRsIGgZa1jGUIhvGz4S5Yh6wtOIo/TMIsSLe+Xay+KVnbseJpPprDI5W3s7H2ODhMQTbogmmUFquZweW2ImQ==", - "dev": true, - "requires": { - "underscore": "1.9.1", - "web3-eth-iban": "1.2.2", - "web3-utils": "1.2.2" - } - } - } - }, - "web3-providers-ipc": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.2.2.tgz", - "integrity": "sha512-t97w3zi5Kn/LEWGA6D9qxoO0LBOG+lK2FjlEdCwDQatffB/+vYrzZ/CLYVQSoyFZAlsDoBasVoYSWZK1n39aHA==", - "dev": true, - "requires": { - "oboe": "2.1.4", - "underscore": "1.9.1", - "web3-core-helpers": "1.2.2" - }, - "dependencies": { - "web3-core-helpers": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.2.tgz", - "integrity": "sha512-HJrRsIGgZa1jGUIhvGz4S5Yh6wtOIo/TMIsSLe+Xay+KVnbseJpPprDI5W3s7H2ODhMQTbogmmUFquZweW2ImQ==", - "dev": true, - "requires": { - "underscore": "1.9.1", - "web3-eth-iban": "1.2.2", - "web3-utils": "1.2.2" - } - } - } - }, - "web3-providers-ws": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.2.2.tgz", - "integrity": "sha512-Wb1mrWTGMTXOpJkL0yGvL/WYLt8fUIXx8k/l52QB2IiKzvyd42dTWn4+j8IKXGSYYzOm7NMqv6nhA5VDk12VfA==", - "dev": true, - "requires": { - "underscore": "1.9.1", - "web3-core-helpers": "1.2.2", - "websocket": "github:web3-js/WebSocket-Node#polyfill/globalThis" - }, - "dependencies": { - "web3-core-helpers": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.2.tgz", - "integrity": "sha512-HJrRsIGgZa1jGUIhvGz4S5Yh6wtOIo/TMIsSLe+Xay+KVnbseJpPprDI5W3s7H2ODhMQTbogmmUFquZweW2ImQ==", - "dev": true, - "requires": { - "underscore": "1.9.1", - "web3-eth-iban": "1.2.2", - "web3-utils": "1.2.2" - } - } - } - }, "web3-shh": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.2.2.tgz", - "integrity": "sha512-og258NPhlBn8yYrDWjoWBBb6zo1OlBgoWGT+LL5/LPqRbjPe09hlOYHgscAAr9zZGtohTOty7RrxYw6Z6oDWCg==", - "dev": true, + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.2.1.tgz", + "integrity": "sha512-/3Cl04nza5kuFn25bV3FJWa0s3Vafr5BlT933h26xovQ6HIIz61LmvNQlvX1AhFL+SNJOTcQmK1SM59vcyC8bA==", "requires": { - "web3-core": "1.2.2", - "web3-core-method": "1.2.2", - "web3-core-subscriptions": "1.2.2", - "web3-net": "1.2.2" + "web3-core": "1.2.1", + "web3-core-method": "1.2.1", + "web3-core-subscriptions": "1.2.1", + "web3-net": "1.2.1" } }, "web3-utils": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.2.2.tgz", - "integrity": "sha512-joF+s3243TY5cL7Z7y4h1JsJpUCf/kmFmj+eJar7Y2yNIGVcW961VyrAms75tjUysSuHaUQ3eQXjBEUJueT52A==", - "dev": true, + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.2.1.tgz", + "integrity": "sha512-Mrcn3l58L+yCKz3zBryM6JZpNruWuT0OCbag8w+reeNROSGVlXzUQkU+gtAwc9JCZ7tKUyg67+2YUGqUjVcyBA==", "requires": { "bn.js": "4.11.8", "eth-lib": "0.2.7", - "ethereum-bloom-filters": "^1.0.6", "ethjs-unit": "0.1.6", "number-to-bn": "1.7.0", - "randombytes": "^2.1.0", + "randomhex": "0.1.5", "underscore": "1.9.1", "utf8": "3.0.0" }, @@ -11855,14 +10236,12 @@ "bn.js": { "version": "4.11.8", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", - "dev": true + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" }, "eth-lib": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.7.tgz", "integrity": "sha1-L5Pxex4jrsN1nNSj/iDBKGo/wco=", - "dev": true, "requires": { "bn.js": "^4.11.6", "elliptic": "^6.4.0", @@ -11872,14 +10251,15 @@ } }, "websocket": { - "version": "github:web3-js/WebSocket-Node#ef5ea2f41daf4a2113b80c9223df884b4d56c400", - "from": "github:web3-js/WebSocket-Node#polyfill/globalThis", - "dev": true, + "version": "1.0.32", + "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.32.tgz", + "integrity": "sha512-i4yhcllSP4wrpoPMU2N0TQ/q0O94LRG/eUQjEAamRltjQ1oT1PFFKOG4i877OlJgCG8rw6LrrowJp+TYCEWF7Q==", "requires": { + "bufferutil": "^4.0.1", "debug": "^2.2.0", "es5-ext": "^0.10.50", - "nan": "^2.14.0", "typedarray-to-buffer": "^3.1.5", + "utf-8-validate": "^5.0.2", "yaeti": "^0.0.6" }, "dependencies": { @@ -11887,16 +10267,9 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "requires": { "ms": "2.0.0" } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true } } }, @@ -11930,6 +10303,26 @@ "function-bind": "^1.1.1", "has-symbols": "^1.0.1", "is-typed-array": "^1.1.3" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", + "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } } }, "wide-align": { @@ -11938,35 +10331,6 @@ "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "requires": { "string-width": "^1.0.2 || 2" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "requires": { - "ansi-regex": "^3.0.0" - } - } } }, "word-wrap": { @@ -11996,15 +10360,13 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } }, "string-width": { "version": "3.1.0", @@ -12136,16 +10498,6 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", diff --git a/test/Route/Route.test.ts b/test/Route/Route.test.ts new file mode 100644 index 0000000..79f8a23 --- /dev/null +++ b/test/Route/Route.test.ts @@ -0,0 +1,171 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +// import * as assert from 'assert'; + +import BigNumber from 'bignumber.js'; +import { DODOContext, getDODOContext } from '../utils-v1/Context'; +import { decimalStr,MAX_UINT256 } from '../utils-v1/Converter'; +import { logGas } from '../utils-v1/Log'; + +let lp: string; +let trader: string; + +async function init(ctx: DODOContext): Promise { + await ctx.setOraclePrice(decimalStr("100")); + + lp = ctx.spareAccounts[0]; + trader = ctx.spareAccounts[1]; + await ctx.approveDODO(lp); + await ctx.approveDODO(trader); + + await ctx.mintTestToken(lp, decimalStr("10"), decimalStr("1000")); + await ctx.mintTestToken(trader, decimalStr("10"), decimalStr("1000")); + + await ctx.DODO.methods + .depositBaseTo(lp, decimalStr("10")) + .send(ctx.sendParam(lp)); + await ctx.DODO.methods + .depositQuoteTo(lp, decimalStr("1000")) + .send(ctx.sendParam(lp)); + +} + + +async function calcRoute(ctx: DODOContext) { + let fromTokenAmount = decimalStr("1"); + //路径 + let routes = [ + { + address: ctx.BASE.options.address, + decimals: 18 + }, + { + address: ctx.QUOTE.options.address, + decimals: 18 + } + ] + + //路径上交易对 + let pairs = [ + { + pair: ctx.DODO.options.address, + base: ctx.BASE.options.address + } + ] + let callPairs: string[] = [] + let datas: string = "" + let starts: number[] = [] + let gAndV: number[] = [] + let swapAmount = fromTokenAmount + for (let i = 0; i < pairs.length; i++) { + let curPair = pairs[i] + callPairs.push(curPair.pair) + //TODO: hardcode + let curContact =ctx.DODO; + let curData = '' + if (curPair.base === routes[i].address) { + curData = await curContact.methods.sellBaseToken(swapAmount, 0, []).encodeABI() + swapAmount = await curContact.methods.querySellBaseToken(swapAmount).call(); + } else { + curData = await curContact.methods.buyBaseToken(swapAmount, 0, []).encodABI() + swapAmount = await curContact.methods.queryBuyBaseToken(swapAmount).call(); + } + starts.push(datas.length) + gAndV.push(0) + datas += curData + } + + let toAmount = new BigNumber(swapAmount).multipliedBy(0.99).toFixed(0, BigNumber.ROUND_DOWN) + + return ctx.SmartSwap.methods.dodoSwap( + ctx.BASE.options.address, + ctx.QUOTE.options.address, + fromTokenAmount, + toAmount, + callPairs, + datas, + starts, + gAndV + ) +} + +describe("Trader", () => { + let snapshotId: string; + let ctx: DODOContext; + + before(async () => { + ctx = await getDODOContext(); + await init(ctx); + }); + + beforeEach(async () => { + snapshotId = await ctx.EVM.snapshot(); + }); + + afterEach(async () => { + await ctx.EVM.reset(snapshotId); + }); + + describe("hit currently pair", () => { + it("base to quote", async () => { + var beforeBalance = await ctx.BASE.methods.balanceOf(trader).call() + // await ctx.BASE.methods.approve(ctx.SmartApprove.options.address,MAX_UINT256).send(ctx.sendParam(trader)) + console.log("beforeBalance",beforeBalance) + await logGas(await calcRoute(ctx), ctx.sendParam(trader), "buy token") + var afterBalance = await ctx.BASE.methods.balanceOf(trader).call() + console.log("afterBalance",afterBalance) + // // trader balances + // assert.equal( + // await ctx.BASE.methods.balanceOf(trader).call(), + // decimalStr("11") + // ); + // assert.equal( + // await ctx.QUOTE.methods.balanceOf(trader).call(), + // "898581839502056240973" + // ); + }); + }); + + + // describe("Revert cases", () => { + // it("price limit", async () => { + // await assert.rejects( + // ctx.DODO.methods + // .buyBaseToken(decimalStr("1"), decimalStr("100"), "0x") + // .send(ctx.sendParam(trader)), + // /BUY_BASE_COST_TOO_MUCH/ + // ); + // await assert.rejects( + // ctx.DODO.methods + // .sellBaseToken(decimalStr("1"), decimalStr("100"), "0x") + // .send(ctx.sendParam(trader)), + // /SELL_BASE_RECEIVE_NOT_ENOUGH/ + // ); + // }); + + // it("base balance limit", async () => { + // await assert.rejects( + // ctx.DODO.methods + // .buyBaseToken(decimalStr("11"), decimalStr("10000"), "0x") + // .send(ctx.sendParam(trader)), + // /DODO_BASE_BALANCE_NOT_ENOUGH/ + // ); + + // await ctx.DODO.methods + // .buyBaseToken(decimalStr("1"), decimalStr("200"), "0x") + // .send(ctx.sendParam(trader)); + + // await assert.rejects( + // ctx.DODO.methods + // .buyBaseToken(decimalStr("11"), decimalStr("10000"), "0x") + // .send(ctx.sendParam(trader)), + // /DODO_BASE_BALANCE_NOT_ENOUGH/ + // ); + // }); + // }); +}); diff --git a/test/utils-v1/Context.ts b/test/utils-v1/Context.ts new file mode 100644 index 0000000..f00ba44 --- /dev/null +++ b/test/utils-v1/Context.ts @@ -0,0 +1,195 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +import BigNumber from 'bignumber.js'; +import Web3 from 'web3'; +import { Contract } from 'web3-eth-contract'; + +import * as contracts from './Contracts'; +import { decimalStr, gweiStr, MAX_UINT256 } from './Converter'; +import { EVM, getDefaultWeb3 } from './EVM'; +import * as log from './Log'; + +BigNumber.config({ + EXPONENTIAL_AT: 1000, + DECIMAL_PLACES: 80, +}); + +export interface DODOContextInitConfig { + lpFeeRate: string; + mtFeeRate: string; + k: string; + gasPriceLimit: string; +} + +/* + price curve when k=0.1 + +──────────────────────+───────────────+ + | purchase percentage | avg slippage | + +──────────────────────+───────────────+ + | 1% | 0.1% | + | 5% | 0.5% | + | 10% | 1.1% | + | 20% | 2.5% | + | 50% | 10% | + | 70% | 23.3% | + +──────────────────────+───────────────+ +*/ +export let DefaultDODOContextInitConfig = { + lpFeeRate: decimalStr("0.002"), + mtFeeRate: decimalStr("0.001"), + k: decimalStr("0.1"), + gasPriceLimit: gweiStr("100"), +}; + +export class DODOContext { + EVM: EVM; + Web3: Web3; + DODO: Contract; + DODOZoo: Contract; + BASE: Contract; + BaseCapital: Contract; + QUOTE: Contract; + QuoteCapital: Contract; + ORACLE: Contract; + SmartSwap: Contract; + SmartApprove: Contract; + Deployer: string; + Supervisor: string; + Maintainer: string; + spareAccounts: string[]; + + constructor() {} + + async init(config: DODOContextInitConfig) { + this.EVM = new EVM(); + this.Web3 = getDefaultWeb3(); + var cloneFactory = await contracts.newContract( + contracts.CLONE_FACTORY_CONTRACT_NAME + ); + + this.BASE = await contracts.newContract( + contracts.TEST_ERC20_CONTRACT_NAME, + ["TestBase", 18] + ); + this.QUOTE = await contracts.newContract( + contracts.TEST_ERC20_CONTRACT_NAME, + ["TestQuote", 18] + ); + this.ORACLE = await contracts.newContract( + contracts.NAIVE_ORACLE_CONTRACT_NAME + ); + + const allAccounts = await this.Web3.eth.getAccounts(); + this.Deployer = allAccounts[0]; + this.Supervisor = allAccounts[1]; + this.Maintainer = allAccounts[2]; + this.spareAccounts = allAccounts.slice(3, 10); + + var DODOTemplate = await contracts.newContract( + contracts.DODO_CONTRACT_NAME + ); + this.DODOZoo = await contracts.newContract( + contracts.DODO_ZOO_CONTRACT_NAME, + [ + DODOTemplate.options.address, + cloneFactory.options.address, + this.Supervisor, + ] + ); + + await this.DODOZoo.methods + .breedDODO( + this.Maintainer, + this.BASE.options.address, + this.QUOTE.options.address, + this.ORACLE.options.address, + config.lpFeeRate, + config.mtFeeRate, + config.k, + config.gasPriceLimit + ) + .send(this.sendParam(this.Deployer)); + + this.DODO = contracts.getContractWithAddress( + contracts.DODO_CONTRACT_NAME, + await this.DODOZoo.methods + .getDODO(this.BASE.options.address, this.QUOTE.options.address) + .call() + ); + await this.DODO.methods + .enableBaseDeposit() + .send(this.sendParam(this.Deployer)); + await this.DODO.methods + .enableQuoteDeposit() + .send(this.sendParam(this.Deployer)); + await this.DODO.methods.enableTrading().send(this.sendParam(this.Deployer)); + + this.BaseCapital = contracts.getContractWithAddress( + contracts.DODO_LP_TOKEN_CONTRACT_NAME, + await this.DODO.methods._BASE_CAPITAL_TOKEN_().call() + ); + this.QuoteCapital = contracts.getContractWithAddress( + contracts.DODO_LP_TOKEN_CONTRACT_NAME, + await this.DODO.methods._QUOTE_CAPITAL_TOKEN_().call() + ); + + /*v1.5*/ + this.SmartApprove = await contracts.newContract( + contracts.SMART_APPROVE + ); + + this.SmartSwap = await contracts.newContract( + contracts.SMART_SWAP, + [this.SmartApprove.options.address] + ); + + await this.SmartApprove.methods.setSmartSwap(this.SmartSwap.options.address).send(this.sendParam(this.Deployer)); + /*****/ + + console.log(log.blueText("[Init dodo context]")); + } + + sendParam(sender, value = "0") { + return { + from: sender, + gas: process.env["COVERAGE"] ? 10000000000 : 7000000, + gasPrice: process.env.GAS_PRICE, + value: decimalStr(value), + }; + } + + async setOraclePrice(price: string) { + await this.ORACLE.methods + .setPrice(price) + .send(this.sendParam(this.Deployer)); + } + + async mintTestToken(to: string, base: string, quote: string) { + await this.BASE.methods.mint(to, base).send(this.sendParam(this.Deployer)); + await this.QUOTE.methods + .mint(to, quote) + .send(this.sendParam(this.Deployer)); + } + + async approveDODO(account: string) { + await this.BASE.methods + .approve(this.DODO.options.address, MAX_UINT256) + .send(this.sendParam(account)); + await this.QUOTE.methods + .approve(this.DODO.options.address, MAX_UINT256) + .send(this.sendParam(account)); + } +} + +export async function getDODOContext( + config: DODOContextInitConfig = DefaultDODOContextInitConfig +): Promise { + var context = new DODOContext(); + await context.init(config); + return context; +} diff --git a/test/utils-v1/Contracts.ts b/test/utils-v1/Contracts.ts new file mode 100644 index 0000000..a17f6b2 --- /dev/null +++ b/test/utils-v1/Contracts.ts @@ -0,0 +1,118 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ +var jsonPath: string = "../../build-v1/contracts/" +/*v1.5*/ +var jsonPath2: string = "../../build/contracts/" +/******/ +if (process.env["COVERAGE"]) { + console.log("[Coverage mode]") + jsonPath = "../../.coverage_artifacts/contracts/" +} + +const CloneFactory = require(`${jsonPath}CloneFactory.json`) +const DODO = require(`${jsonPath}DODO.json`) +const DODOZoo = require(`${jsonPath}DODOZoo.json`) +const DODOEthProxy = require(`${jsonPath}DODOEthProxy.json`) +const WETH = require(`${jsonPath}WETH9.json`) +const TestERC20 = require(`${jsonPath}TestERC20.json`) +const NaiveOracle = require(`${jsonPath}NaiveOracle.json`) +const DODOLpToken = require(`${jsonPath}DODOLpToken.json`) +const Uniswap = require(`${jsonPath}UniswapV2Pair.json`) +const UniswapArbitrageur = require(`${jsonPath}UniswapArbitrageur.json`) +const DODOToken = require(`${jsonPath}DODOToken.json`) +const DODOMine = require(`${jsonPath}DODOMine.json`) +const DODOMineReader = require(`${jsonPath}DODOMineReader.json`) +const LockedTokenVault = require(`${jsonPath}LockedTokenVault.json`) +/*v1.5*/ +const SmartSwap = require(`${jsonPath2}SmartSwap.json`) +const SmartApprove = require(`${jsonPath2}SmartApprove.json`) +/******/ + +import { getDefaultWeb3 } from './EVM'; +import { Contract } from 'web3-eth-contract'; + +export const CLONE_FACTORY_CONTRACT_NAME = "CloneFactory" +export const DODO_CONTRACT_NAME = "DODO" +export const TEST_ERC20_CONTRACT_NAME = "TestERC20" +export const NAIVE_ORACLE_CONTRACT_NAME = "NaiveOracle" +export const DODO_LP_TOKEN_CONTRACT_NAME = "DODOLpToken" +export const DODO_ZOO_CONTRACT_NAME = "DOOZoo" +export const DODO_WILD_CONTRACT_NAME = "DOOWild" +export const DODO_ETH_PROXY_CONTRACT_NAME = "DODOEthProxy" +export const WETH_CONTRACT_NAME = "WETH" +export const UNISWAP_CONTRACT_NAME = "Uniswap" +export const UNISWAP_ARBITRAGEUR_CONTRACT_NAME = "UniswapArbitrageur" +export const DODO_TOKEN_CONTRACT_NAME = "DODOToken" +export const LOCKED_TOKEN_VAULT_CONTRACT_NAME = "LockedTokenVault" +export const DODO_MINE_NAME = "DODOMine" +export const DODO_MINE_READER_NAME = "DODOMineReader" +/*v1.5*/ +export const SMART_SWAP = "SmartSwap" +export const SMART_APPROVE = "SmartApprove" +/******/ + +var contractMap: { [name: string]: any } = {} +contractMap[CLONE_FACTORY_CONTRACT_NAME] = CloneFactory +contractMap[DODO_CONTRACT_NAME] = DODO +contractMap[TEST_ERC20_CONTRACT_NAME] = TestERC20 +contractMap[NAIVE_ORACLE_CONTRACT_NAME] = NaiveOracle +contractMap[DODO_LP_TOKEN_CONTRACT_NAME] = DODOLpToken +contractMap[DODO_ZOO_CONTRACT_NAME] = DODOZoo +contractMap[DODO_ETH_PROXY_CONTRACT_NAME] = DODOEthProxy +contractMap[WETH_CONTRACT_NAME] = WETH +contractMap[UNISWAP_CONTRACT_NAME] = Uniswap +contractMap[UNISWAP_ARBITRAGEUR_CONTRACT_NAME] = UniswapArbitrageur +contractMap[DODO_TOKEN_CONTRACT_NAME] = DODOToken +contractMap[LOCKED_TOKEN_VAULT_CONTRACT_NAME] = LockedTokenVault +contractMap[DODO_MINE_NAME] = DODOMine +contractMap[DODO_MINE_READER_NAME] = DODOMineReader +/*v1.5*/ +contractMap[SMART_SWAP] = SmartSwap +contractMap[SMART_APPROVE] = SmartApprove +/******/ + +interface ContractJson { + abi: any; + networks: { [network: number]: any }; + byteCode: string; +} + +export function getContractJSON(contractName: string): ContractJson { + var info = contractMap[contractName] + return { + abi: info.abi, + networks: info.networks, + byteCode: info.bytecode + } +} + +export function getContractWithAddress(contractName: string, address: string) { + var Json = getContractJSON(contractName) + var web3 = getDefaultWeb3() + return new web3.eth.Contract(Json.abi, address) +} + +export function getDepolyedContract(contractName: string): Contract { + var Json = getContractJSON(contractName) + var networkId = process.env.NETWORK_ID + var deployedAddress = getContractJSON(contractName).networks[networkId].address + var web3 = getDefaultWeb3() + return new web3.eth.Contract(Json.abi, deployedAddress) +} + +export async function newContract(contractName: string, args: any[] = []): Promise { + var web3 = getDefaultWeb3() + var Json = getContractJSON(contractName) + var contract = new web3.eth.Contract(Json.abi) + var adminAccount = (await web3.eth.getAccounts())[0] + let parameter = { + from: adminAccount, + gas: process.env["COVERAGE"] ? 10000000000 : 7000000, + gasPrice: web3.utils.toHex(web3.utils.toWei('1', 'wei')) + } + return await contract.deploy({ data: Json.byteCode, arguments: args }).send(parameter) +} \ No newline at end of file diff --git a/test/utils-v1/Converter.ts b/test/utils-v1/Converter.ts new file mode 100644 index 0000000..c7108b9 --- /dev/null +++ b/test/utils-v1/Converter.ts @@ -0,0 +1,15 @@ +import BigNumber from "bignumber.js"; + +export const MAX_UINT256 = "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + +export function decimalStr(value: string): string { + return new BigNumber(value).multipliedBy(10 ** 18).toFixed(0, BigNumber.ROUND_DOWN) +} + +export function mweiStr(value: string): string { + return new BigNumber(value).multipliedBy(10 ** 6).toFixed(0, BigNumber.ROUND_DOWN) +} + +export function gweiStr(gwei: string): string { + return new BigNumber(gwei).multipliedBy(10 ** 9).toFixed(0, BigNumber.ROUND_DOWN) +} \ No newline at end of file diff --git a/test/utils-v1/EVM.ts b/test/utils-v1/EVM.ts new file mode 100644 index 0000000..75e071a --- /dev/null +++ b/test/utils-v1/EVM.ts @@ -0,0 +1,92 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +// require('dotenv-flow').config(); + +import { JsonRpcPayload, JsonRpcResponse } from 'web3-core-helpers'; +import Web3 from 'web3'; + +export function getDefaultWeb3() { + return new Web3(process.env.RPC_NODE_URI) +} + +export class EVM { + private provider = new Web3.providers.HttpProvider(process.env.RPC_NODE_URI); + + public async reset(id: string): Promise { + if (!id) { + throw new Error('id must be set'); + } + + await this.callJsonrpcMethod('evm_revert', [id]); + + return this.snapshot(); + } + + public async snapshot(): Promise { + return this.callJsonrpcMethod('evm_snapshot'); + } + + public async evmRevert(id: string): Promise { + return this.callJsonrpcMethod('evm_revert', [id]); + } + + public async stopMining(): Promise { + return this.callJsonrpcMethod('miner_stop'); + } + + public async startMining(): Promise { + return this.callJsonrpcMethod('miner_start'); + } + + public async mineBlock(): Promise { + return this.callJsonrpcMethod('evm_mine'); + } + + public async fastMove(moveBlockNum: number): Promise { + var res: string + for (let i = 0; i < moveBlockNum; i++) { + res = await this.callJsonrpcMethod('evm_mine'); + } + return res + } + + public async increaseTime(duration: number): Promise { + await this.callJsonrpcMethod('evm_increaseTime', [duration]); + return this.callJsonrpcMethod('evm_mine'); + } + + public async callJsonrpcMethod(method: string, params?: (any[])): Promise { + const args: JsonRpcPayload = { + method, + params, + jsonrpc: '2.0', + id: new Date().getTime(), + }; + + const response = await this.send(args); + + return response.result; + } + + private async send(args: JsonRpcPayload): Promise { + return new Promise((resolve, reject) => { + const callback: any = (error: Error, val: JsonRpcResponse): void => { + if (error) { + reject(error); + } else { + resolve(val); + } + }; + + this.provider.send( + args, + callback, + ); + }); + } +} diff --git a/test/utils-v1/Log.ts b/test/utils-v1/Log.ts new file mode 100644 index 0000000..7e7c3b7 --- /dev/null +++ b/test/utils-v1/Log.ts @@ -0,0 +1,30 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +export const blueText = x => `\x1b[36m${x}\x1b[0m`; +export const yellowText = x => `\x1b[33m${x}\x1b[0m`; +export const greenText = x => `\x1b[32m${x}\x1b[0m`; +export const redText = x => `\x1b[31m${x}\x1b[0m`; +export const numberWithCommas = x => x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); + +export async function logGas(funcCall: any, params: any, desc: string) { + const estimatedGas = await funcCall.estimateGas(params) + const receipt = await funcCall.send(params) + const gasUsed = receipt.gasUsed; + let colorFn; + + if (gasUsed < 80000) { + colorFn = greenText; + } else if (gasUsed < 200000) { + colorFn = yellowText; + } else { + colorFn = redText; + } + + console.log(("Gas estimated:" + numberWithCommas(estimatedGas)).padEnd(60, '.'), blueText(desc) + " ", colorFn(numberWithCommas(gasUsed).padStart(5))); + return receipt +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 3e1de7f..fc9a05e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,7 +7,7 @@ "sourceMap": true, "declaration": true, "downlevelIteration": true, - "noUnusedLocals": true, + // "noUnusedLocals": true, "esModuleInterop": true, "outDir": "dist", "resolveJsonModule": true, diff --git a/yarn.lock b/yarn.lock deleted file mode 100644 index 1739e46..0000000 --- a/yarn.lock +++ /dev/null @@ -1,6820 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.1.tgz#d5481c5095daa1c57e16e54c6f9198443afb49ff" - dependencies: - "@babel/highlight" "^7.10.1" - -"@babel/generator@^7.10.1": - version "7.10.2" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.10.2.tgz#0fa5b5b2389db8bfdfcc3492b551ee20f5dd69a9" - dependencies: - "@babel/types" "^7.10.2" - jsesc "^2.5.1" - lodash "^4.17.13" - source-map "^0.5.0" - -"@babel/helper-function-name@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.1.tgz#92bd63829bfc9215aca9d9defa85f56b539454f4" - dependencies: - "@babel/helper-get-function-arity" "^7.10.1" - "@babel/template" "^7.10.1" - "@babel/types" "^7.10.1" - -"@babel/helper-get-function-arity@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.1.tgz#7303390a81ba7cb59613895a192b93850e373f7d" - dependencies: - "@babel/types" "^7.10.1" - -"@babel/helper-module-imports@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.3.tgz#766fa1d57608e53e5676f23ae498ec7a95e1b11a" - dependencies: - "@babel/types" "^7.10.3" - -"@babel/helper-plugin-utils@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.3.tgz#aac45cccf8bc1873b99a85f34bceef3beb5d3244" - -"@babel/helper-split-export-declaration@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.1.tgz#c6f4be1cbc15e3a868e4c64a17d5d31d754da35f" - dependencies: - "@babel/types" "^7.10.1" - -"@babel/helper-validator-identifier@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.1.tgz#5770b0c1a826c4f53f5ede5e153163e0318e94b5" - -"@babel/helper-validator-identifier@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.3.tgz#60d9847f98c4cea1b279e005fdb7c28be5412d15" - -"@babel/highlight@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.1.tgz#841d098ba613ba1a427a2b383d79e35552c38ae0" - dependencies: - "@babel/helper-validator-identifier" "^7.10.1" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@babel/parser@^7.10.1", "@babel/parser@^7.7.0": - version "7.10.2" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.10.2.tgz#871807f10442b92ff97e4783b9b54f6a0ca812d0" - -"@babel/plugin-transform-runtime@^7.5.5": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.10.3.tgz#3b287b06acc534a7cb6e6c71d6b1d88b1922dd6c" - dependencies: - "@babel/helper-module-imports" "^7.10.3" - "@babel/helper-plugin-utils" "^7.10.3" - resolve "^1.8.1" - semver "^5.5.1" - -"@babel/runtime@^7.5.5": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.3.tgz#670d002655a7c366540c67f6fd3342cd09500364" - dependencies: - regenerator-runtime "^0.13.4" - -"@babel/template@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.1.tgz#e167154a94cb5f14b28dc58f5356d2162f539811" - dependencies: - "@babel/code-frame" "^7.10.1" - "@babel/parser" "^7.10.1" - "@babel/types" "^7.10.1" - -"@babel/traverse@^7.7.0": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.10.1.tgz#bbcef3031e4152a6c0b50147f4958df54ca0dd27" - dependencies: - "@babel/code-frame" "^7.10.1" - "@babel/generator" "^7.10.1" - "@babel/helper-function-name" "^7.10.1" - "@babel/helper-split-export-declaration" "^7.10.1" - "@babel/parser" "^7.10.1" - "@babel/types" "^7.10.1" - debug "^4.1.0" - globals "^11.1.0" - lodash "^4.17.13" - -"@babel/types@^7.10.1", "@babel/types@^7.10.2", "@babel/types@^7.7.0": - version "7.10.2" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.10.2.tgz#30283be31cad0dbf6fb00bd40641ca0ea675172d" - dependencies: - "@babel/helper-validator-identifier" "^7.10.1" - lodash "^4.17.13" - to-fast-properties "^2.0.0" - -"@babel/types@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.10.3.tgz#6535e3b79fea86a6b09e012ea8528f935099de8e" - dependencies: - "@babel/helper-validator-identifier" "^7.10.3" - lodash "^4.17.13" - to-fast-properties "^2.0.0" - -"@ethersproject/abi@5.0.0-beta.153": - version "5.0.0-beta.153" - resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.0.0-beta.153.tgz#43a37172b33794e4562999f6e2d555b7599a8eee" - dependencies: - "@ethersproject/address" ">=5.0.0-beta.128" - "@ethersproject/bignumber" ">=5.0.0-beta.130" - "@ethersproject/bytes" ">=5.0.0-beta.129" - "@ethersproject/constants" ">=5.0.0-beta.128" - "@ethersproject/hash" ">=5.0.0-beta.128" - "@ethersproject/keccak256" ">=5.0.0-beta.127" - "@ethersproject/logger" ">=5.0.0-beta.129" - "@ethersproject/properties" ">=5.0.0-beta.131" - "@ethersproject/strings" ">=5.0.0-beta.130" - -"@ethersproject/address@>=5.0.0-beta.128": - version "5.0.0-beta.135" - resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.0.0-beta.135.tgz#8d4697c81dc27758b05e7eb7507c254f2ef0e5dc" - dependencies: - "@ethersproject/bignumber" ">=5.0.0-beta.138" - "@ethersproject/bytes" ">=5.0.0-beta.137" - "@ethersproject/keccak256" ">=5.0.0-beta.131" - "@ethersproject/logger" ">=5.0.0-beta.137" - "@ethersproject/rlp" ">=5.0.0-beta.132" - bn.js "^4.4.0" - -"@ethersproject/bignumber@>=5.0.0-beta.130", "@ethersproject/bignumber@>=5.0.0-beta.138": - version "5.0.0-beta.139" - resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.0.0-beta.139.tgz#12a4fa5a76ee90f77932326311caf04e1de1cae0" - dependencies: - "@ethersproject/bytes" ">=5.0.0-beta.137" - "@ethersproject/logger" ">=5.0.0-beta.137" - "@ethersproject/properties" ">=5.0.0-beta.140" - bn.js "^4.4.0" - -"@ethersproject/bytes@>=5.0.0-beta.129", "@ethersproject/bytes@>=5.0.0-beta.137": - version "5.0.0-beta.138" - resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.0.0-beta.138.tgz#86e1f6c4016443f2b5236627fa656e7c56077a56" - dependencies: - "@ethersproject/logger" ">=5.0.0-beta.137" - -"@ethersproject/constants@>=5.0.0-beta.128", "@ethersproject/constants@>=5.0.0-beta.133": - version "5.0.0-beta.134" - resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.0.0-beta.134.tgz#b81c42373a00cb21604a94aa8642454fb35bb764" - dependencies: - "@ethersproject/bignumber" ">=5.0.0-beta.138" - -"@ethersproject/hash@>=5.0.0-beta.128": - version "5.0.0-beta.134" - resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.0.0-beta.134.tgz#e1fdb69b42f5d31c343bcbf183043853b9b8e9dd" - dependencies: - "@ethersproject/bytes" ">=5.0.0-beta.137" - "@ethersproject/keccak256" ">=5.0.0-beta.131" - "@ethersproject/logger" ">=5.0.0-beta.137" - "@ethersproject/strings" ">=5.0.0-beta.136" - -"@ethersproject/keccak256@>=5.0.0-beta.127", "@ethersproject/keccak256@>=5.0.0-beta.131": - version "5.0.0-beta.132" - resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.0.0-beta.132.tgz#38c128194a88aba690b6aca43cae57df420408d7" - dependencies: - "@ethersproject/bytes" ">=5.0.0-beta.137" - js-sha3 "0.5.7" - -"@ethersproject/logger@>=5.0.0-beta.129", "@ethersproject/logger@>=5.0.0-beta.137": - version "5.0.0-beta.137" - resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.0.0-beta.137.tgz#781582b8b04d0ced01e9c1608c9887d31d95b8ee" - -"@ethersproject/properties@>=5.0.0-beta.131", "@ethersproject/properties@>=5.0.0-beta.140": - version "5.0.0-beta.143" - resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.0.0-beta.143.tgz#604ba072ee91e386e1bfab70413c34165fa9c913" - dependencies: - "@ethersproject/logger" ">=5.0.0-beta.137" - -"@ethersproject/rlp@>=5.0.0-beta.132": - version "5.0.0-beta.133" - resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.0.0-beta.133.tgz#e51b2e8d51fd70a5872f85f11741193a6b118110" - dependencies: - "@ethersproject/bytes" ">=5.0.0-beta.137" - "@ethersproject/logger" ">=5.0.0-beta.137" - -"@ethersproject/strings@>=5.0.0-beta.130", "@ethersproject/strings@>=5.0.0-beta.136": - version "5.0.0-beta.137" - resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.0.0-beta.137.tgz#1e9730a701e7a44c3f1b4e1c7e134665cdd51d7b" - dependencies: - "@ethersproject/bytes" ">=5.0.0-beta.137" - "@ethersproject/constants" ">=5.0.0-beta.133" - "@ethersproject/logger" ">=5.0.0-beta.137" - -"@nodelib/fs.scandir@2.1.3": - version "2.1.3" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b" - dependencies: - "@nodelib/fs.stat" "2.0.3" - run-parallel "^1.1.9" - -"@nodelib/fs.stat@2.0.3", "@nodelib/fs.stat@^2.0.2": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz#34dc5f4cabbc720f4e60f75a747e7ecd6c175bd3" - -"@nodelib/fs.walk@^1.2.3": - version "1.2.4" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz#011b9202a70a6366e436ca5c065844528ab04976" - dependencies: - "@nodelib/fs.scandir" "2.1.3" - fastq "^1.6.0" - -"@sindresorhus/is@^0.14.0": - version "0.14.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" - -"@solidity-parser/parser@^0.6.0", "@solidity-parser/parser@^0.6.1": - version "0.6.2" - resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.6.2.tgz#49707fc4e06649d39d6b25bdab2e9093d372ce50" - -"@szmarczak/http-timer@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" - dependencies: - defer-to-connect "^1.0.1" - -"@truffle/error@^0.0.7": - version "0.0.7" - resolved "https://registry.yarnpkg.com/@truffle/error/-/error-0.0.7.tgz#e9db39885575647ef08bf624b0c13fe46d41a209" - -"@truffle/hdwallet-provider@^1.0.36": - version "1.0.36" - resolved "https://registry.yarnpkg.com/@truffle/hdwallet-provider/-/hdwallet-provider-1.0.36.tgz#d8f2abec2004a3174c0c62f5d5e01a792c894fdc" - dependencies: - "@trufflesuite/web3-provider-engine" "14.0.6" - any-promise "^1.3.0" - bindings "^1.5.0" - bip39 "^2.4.2" - ethereum-protocol "^1.0.1" - ethereumjs-tx "^1.0.0" - ethereumjs-util "^6.1.0" - ethereumjs-wallet "^0.6.3" - source-map-support "^0.5.19" - web3 "1.2.1" - -"@truffle/interface-adapter@^0.3.0": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@truffle/interface-adapter/-/interface-adapter-0.3.3.tgz#61305378cf81776769ef36c60d394e568ac4a2ee" - dependencies: - bn.js "^4.11.8" - ethers "^4.0.32" - lodash "^4.17.13" - web3 "1.2.2" - -"@truffle/provider@^0.1.17": - version "0.1.19" - resolved "https://registry.yarnpkg.com/@truffle/provider/-/provider-0.1.19.tgz#3e6f15fdd8475ca5d0c846d2b412cc823f1fb767" - dependencies: - "@truffle/error" "^0.0.7" - "@truffle/interface-adapter" "^0.3.0" - web3 "1.2.1" - -"@trufflesuite/web3-provider-engine@14.0.6": - version "14.0.6" - resolved "https://registry.yarnpkg.com/@trufflesuite/web3-provider-engine/-/web3-provider-engine-14.0.6.tgz#024d192cde9534a778e5d2436be1caf3c553a2e0" - dependencies: - async "^2.5.0" - backoff "^2.5.0" - clone "^2.0.0" - cross-fetch "^2.1.0" - eth-block-tracker "^4.2.0" - eth-json-rpc-filters "^4.0.2" - eth-json-rpc-infura "^3.1.0" - eth-json-rpc-middleware "^4.1.1" - eth-sig-util "^1.4.2" - ethereumjs-block "^1.2.2" - ethereumjs-tx "^1.2.0" - ethereumjs-util "^5.1.5" - ethereumjs-vm "^2.3.4" - json-rpc-error "^2.0.0" - json-stable-stringify "^1.0.1" - promise-to-callback "^1.0.0" - readable-stream "^2.2.9" - request "^2.85.0" - semaphore "^1.0.3" - ws "^5.1.1" - xhr "^2.2.0" - xtend "^4.0.1" - -"@types/bn.js@^4.11.3", "@types/bn.js@^4.11.4": - version "4.11.6" - resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c" - dependencies: - "@types/node" "*" - -"@types/chai@^4.2.11": - version "4.2.11" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.11.tgz#d3614d6c5f500142358e6ed24e1bf16657536c50" - -"@types/es6-promisify@^6.0.0": - version "6.0.0" - resolved "https://registry.yarnpkg.com/@types/es6-promisify/-/es6-promisify-6.0.0.tgz#a554e8c9c28466720a96b20c9f6b139249b7d375" - -"@types/events@*": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" - -"@types/glob@^7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575" - dependencies: - "@types/events" "*" - "@types/minimatch" "*" - "@types/node" "*" - -"@types/minimatch@*": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" - -"@types/mocha@^7.0.2": - version "7.0.2" - resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-7.0.2.tgz#b17f16cf933597e10d6d78eae3251e692ce8b0ce" - -"@types/node@*": - version "14.0.10" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.10.tgz#dbfaa170bd9eafccccb6d7060743a761b0844afd" - -"@types/node@^10.12.18", "@types/node@^10.3.2": - version "10.17.24" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.24.tgz#c57511e3a19c4b5e9692bb2995c40a3a52167944" - -"@types/node@^12.6.1": - version "12.12.43" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.43.tgz#b60ce047822e526e7a9252e50844eee79d5386ff" - -"@web3-js/scrypt-shim@^0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@web3-js/scrypt-shim/-/scrypt-shim-0.1.0.tgz#0bf7529ab6788311d3e07586f7d89107c3bea2cc" - dependencies: - scryptsy "^2.1.0" - semver "^6.3.0" - -"@web3-js/websocket@^1.0.29": - version "1.0.30" - resolved "https://registry.yarnpkg.com/@web3-js/websocket/-/websocket-1.0.30.tgz#9ea15b7b582cf3bf3e8bc1f4d3d54c0731a87f87" - dependencies: - debug "^2.2.0" - es5-ext "^0.10.50" - nan "^2.14.0" - typedarray-to-buffer "^3.1.5" - yaeti "^0.0.6" - -abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - -abbrev@1.0.x: - version "1.0.9" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" - -abstract-leveldown@~2.6.0: - version "2.6.3" - resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-2.6.3.tgz#1c5e8c6a5ef965ae8c35dfb3a8770c476b82c4b8" - dependencies: - xtend "~4.0.0" - -abstract-leveldown@~2.7.1: - version "2.7.2" - resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-2.7.2.tgz#87a44d7ebebc341d59665204834c8b7e0932cc93" - dependencies: - xtend "~4.0.0" - -accepts@~1.3.7: - version "1.3.7" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" - dependencies: - mime-types "~2.1.24" - negotiator "0.6.2" - -address@^1.0.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/address/-/address-1.1.2.tgz#bf1116c9c758c51b7a933d296b72c221ed9428b6" - -aes-js@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" - -aes-js@^3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.1.2.tgz#db9aabde85d5caabbfc0d4f2a4446960f627146a" - -ajv@^6.5.5: - version "6.12.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.2.tgz#c629c5eced17baf314437918d2da88c99d5958cd" - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -amdefine@>=0.0.4: - version "1.0.1" - resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" - -ansi-colors@3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - -ansi-regex@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" - -ansi-regex@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" - -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - -ansi-styles@^3.2.0, ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - dependencies: - color-convert "^1.9.0" - -any-promise@1.3.0, any-promise@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" - -anymatch@^1.3.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" - dependencies: - micromatch "^2.1.5" - normalize-path "^2.0.0" - -anymatch@~3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -arg@^4.1.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - dependencies: - sprintf-js "~1.0.2" - -arr-diff@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" - dependencies: - arr-flatten "^1.0.1" - -arr-diff@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" - -arr-flatten@^1.0.1, arr-flatten@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - -arr-union@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - -array-filter@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-1.0.0.tgz#baf79e62e6ef4c2a4c0b831232daffec251f9d83" - -array-flatten@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" - -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - -array-unique@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" - -array-unique@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - -asn1.js@^4.0.0: - version "4.10.1" - resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" - dependencies: - bn.js "^4.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - -asn1@~0.2.3: - version "0.2.4" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" - dependencies: - safer-buffer "~2.1.0" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - -assert@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/assert/-/assert-2.0.0.tgz#95fc1c616d48713510680f2eaf2d10dd22e02d32" - dependencies: - es6-object-assign "^1.1.0" - is-nan "^1.2.1" - object-is "^1.0.1" - util "^0.12.0" - -assertion-error@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" - -assign-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - -async-each@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" - -async-eventemitter@^0.2.2: - version "0.2.4" - resolved "https://registry.yarnpkg.com/async-eventemitter/-/async-eventemitter-0.2.4.tgz#f5e7c8ca7d3e46aab9ec40a292baf686a0bafaca" - dependencies: - async "^2.4.0" - -async-limiter@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" - -async@1.x, async@^1.4.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" - -async@^2.0.1, async@^2.1.2, async@^2.4.0, async@^2.5.0: - version "2.6.3" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" - dependencies: - lodash "^4.17.14" - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - -atob@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" - -available-typed-arrays@^1.0.0, available-typed-arrays@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz#6b098ca9d8039079ee3f77f7b783c4480ba513f5" - dependencies: - array-filter "^1.0.0" - -await-semaphore@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/await-semaphore/-/await-semaphore-0.1.3.tgz#2b88018cc8c28e06167ae1cdff02504f1f9688d3" - -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - -aws4@^1.8.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.10.0.tgz#a17b3a8ea811060e74d47d306122400ad4497ae2" - -babel-cli@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-cli/-/babel-cli-6.26.0.tgz#502ab54874d7db88ad00b887a06383ce03d002f1" - dependencies: - babel-core "^6.26.0" - babel-polyfill "^6.26.0" - babel-register "^6.26.0" - babel-runtime "^6.26.0" - commander "^2.11.0" - convert-source-map "^1.5.0" - fs-readdir-recursive "^1.0.0" - glob "^7.1.2" - lodash "^4.17.4" - output-file-sync "^1.1.2" - path-is-absolute "^1.0.1" - slash "^1.0.0" - source-map "^0.5.6" - v8flags "^2.1.1" - optionalDependencies: - chokidar "^1.6.1" - -babel-code-frame@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" - dependencies: - chalk "^1.1.3" - esutils "^2.0.2" - js-tokens "^3.0.2" - -babel-core@^6.0.14, babel-core@^6.26.0: - version "6.26.3" - resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" - dependencies: - babel-code-frame "^6.26.0" - babel-generator "^6.26.0" - babel-helpers "^6.24.1" - babel-messages "^6.23.0" - babel-register "^6.26.0" - babel-runtime "^6.26.0" - babel-template "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - convert-source-map "^1.5.1" - debug "^2.6.9" - json5 "^0.5.1" - lodash "^4.17.4" - minimatch "^3.0.4" - path-is-absolute "^1.0.1" - private "^0.1.8" - slash "^1.0.0" - source-map "^0.5.7" - -babel-eslint@^10.1.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232" - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.7.0" - "@babel/traverse" "^7.7.0" - "@babel/types" "^7.7.0" - eslint-visitor-keys "^1.0.0" - resolve "^1.12.0" - -babel-generator@^6.26.0: - version "6.26.1" - resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" - dependencies: - babel-messages "^6.23.0" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - detect-indent "^4.0.0" - jsesc "^1.3.0" - lodash "^4.17.4" - source-map "^0.5.7" - trim-right "^1.0.1" - -babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" - dependencies: - babel-helper-explode-assignable-expression "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-call-delegate@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" - dependencies: - babel-helper-hoist-variables "^6.24.1" - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-define-map@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - lodash "^4.17.4" - -babel-helper-explode-assignable-expression@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" - dependencies: - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-function-name@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" - dependencies: - babel-helper-get-function-arity "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-get-function-arity@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-hoist-variables@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-optimise-call-expression@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-regex@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" - dependencies: - babel-runtime "^6.26.0" - babel-types "^6.26.0" - lodash "^4.17.4" - -babel-helper-remap-async-to-generator@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-replace-supers@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" - dependencies: - babel-helper-optimise-call-expression "^6.24.1" - babel-messages "^6.23.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helpers@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" - dependencies: - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-messages@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-check-es2015-constants@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-syntax-async-functions@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" - -babel-plugin-syntax-exponentiation-operator@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" - -babel-plugin-syntax-trailing-function-commas@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" - -babel-plugin-transform-async-to-generator@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" - dependencies: - babel-helper-remap-async-to-generator "^6.24.1" - babel-plugin-syntax-async-functions "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-arrow-functions@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-block-scoping@^6.23.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" - dependencies: - babel-runtime "^6.26.0" - babel-template "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - lodash "^4.17.4" - -babel-plugin-transform-es2015-classes@^6.23.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" - dependencies: - babel-helper-define-map "^6.24.1" - babel-helper-function-name "^6.24.1" - babel-helper-optimise-call-expression "^6.24.1" - babel-helper-replace-supers "^6.24.1" - babel-messages "^6.23.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-computed-properties@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" - dependencies: - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-destructuring@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-duplicate-keys@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-for-of@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-function-name@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-literals@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" - dependencies: - babel-plugin-transform-es2015-modules-commonjs "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: - version "6.26.2" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz#58a793863a9e7ca870bdc5a881117ffac27db6f3" - dependencies: - babel-plugin-transform-strict-mode "^6.24.1" - babel-runtime "^6.26.0" - babel-template "^6.26.0" - babel-types "^6.26.0" - -babel-plugin-transform-es2015-modules-systemjs@^6.23.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" - dependencies: - babel-helper-hoist-variables "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-modules-umd@^6.23.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" - dependencies: - babel-plugin-transform-es2015-modules-amd "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-object-super@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" - dependencies: - babel-helper-replace-supers "^6.24.1" - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-parameters@^6.23.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" - dependencies: - babel-helper-call-delegate "^6.24.1" - babel-helper-get-function-arity "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-shorthand-properties@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-spread@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-sticky-regex@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" - dependencies: - babel-helper-regex "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-template-literals@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-typeof-symbol@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-unicode-regex@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" - dependencies: - babel-helper-regex "^6.24.1" - babel-runtime "^6.22.0" - regexpu-core "^2.0.0" - -babel-plugin-transform-exponentiation-operator@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" - dependencies: - babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" - babel-plugin-syntax-exponentiation-operator "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-regenerator@^6.22.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" - dependencies: - regenerator-transform "^0.10.0" - -babel-plugin-transform-strict-mode@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-polyfill@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" - dependencies: - babel-runtime "^6.26.0" - core-js "^2.5.0" - regenerator-runtime "^0.10.5" - -babel-preset-env@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.7.0.tgz#dea79fa4ebeb883cd35dab07e260c1c9c04df77a" - dependencies: - babel-plugin-check-es2015-constants "^6.22.0" - babel-plugin-syntax-trailing-function-commas "^6.22.0" - babel-plugin-transform-async-to-generator "^6.22.0" - babel-plugin-transform-es2015-arrow-functions "^6.22.0" - babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" - babel-plugin-transform-es2015-block-scoping "^6.23.0" - babel-plugin-transform-es2015-classes "^6.23.0" - babel-plugin-transform-es2015-computed-properties "^6.22.0" - babel-plugin-transform-es2015-destructuring "^6.23.0" - babel-plugin-transform-es2015-duplicate-keys "^6.22.0" - babel-plugin-transform-es2015-for-of "^6.23.0" - babel-plugin-transform-es2015-function-name "^6.22.0" - babel-plugin-transform-es2015-literals "^6.22.0" - babel-plugin-transform-es2015-modules-amd "^6.22.0" - babel-plugin-transform-es2015-modules-commonjs "^6.23.0" - babel-plugin-transform-es2015-modules-systemjs "^6.23.0" - babel-plugin-transform-es2015-modules-umd "^6.23.0" - babel-plugin-transform-es2015-object-super "^6.22.0" - babel-plugin-transform-es2015-parameters "^6.23.0" - babel-plugin-transform-es2015-shorthand-properties "^6.22.0" - babel-plugin-transform-es2015-spread "^6.22.0" - babel-plugin-transform-es2015-sticky-regex "^6.22.0" - babel-plugin-transform-es2015-template-literals "^6.22.0" - babel-plugin-transform-es2015-typeof-symbol "^6.23.0" - babel-plugin-transform-es2015-unicode-regex "^6.22.0" - babel-plugin-transform-exponentiation-operator "^6.22.0" - babel-plugin-transform-regenerator "^6.22.0" - browserslist "^3.2.6" - invariant "^2.2.2" - semver "^5.3.0" - -babel-register@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" - dependencies: - babel-core "^6.26.0" - babel-runtime "^6.26.0" - core-js "^2.5.0" - home-or-tmp "^2.0.0" - lodash "^4.17.4" - mkdirp "^0.5.1" - source-map-support "^0.4.15" - -babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" - dependencies: - core-js "^2.4.0" - regenerator-runtime "^0.11.0" - -babel-template@^6.24.1, babel-template@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" - dependencies: - babel-runtime "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - lodash "^4.17.4" - -babel-traverse@^6.24.1, babel-traverse@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" - dependencies: - babel-code-frame "^6.26.0" - babel-messages "^6.23.0" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - debug "^2.6.8" - globals "^9.18.0" - invariant "^2.2.2" - lodash "^4.17.4" - -babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" - dependencies: - babel-runtime "^6.26.0" - esutils "^2.0.2" - lodash "^4.17.4" - to-fast-properties "^1.0.3" - -babelify@^7.3.0: - version "7.3.0" - resolved "https://registry.yarnpkg.com/babelify/-/babelify-7.3.0.tgz#aa56aede7067fd7bd549666ee16dc285087e88e5" - dependencies: - babel-core "^6.0.14" - object-assign "^4.0.0" - -babylon@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" - -backoff@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/backoff/-/backoff-2.5.0.tgz#f616eda9d3e4b66b8ca7fca79f695722c5f8e26f" - dependencies: - precond "0.2" - -balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - -base-x@^3.0.2, base-x@^3.0.8: - version "3.0.8" - resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.8.tgz#1e1106c2537f0162e8b52474a557ebb09000018d" - dependencies: - safe-buffer "^5.0.1" - -base64-js@^1.0.2: - version "1.3.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" - -base@^0.11.1: - version "0.11.2" - resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" - dependencies: - cache-base "^1.0.1" - class-utils "^0.3.5" - component-emitter "^1.2.1" - define-property "^1.0.0" - isobject "^3.0.1" - mixin-deep "^1.2.0" - pascalcase "^0.1.1" - -bcrypt-pbkdf@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - dependencies: - tweetnacl "^0.14.3" - -bignumber.js@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.0.tgz#805880f84a329b5eac6e7cb6f8274b6d82bdf075" - -binary-extensions@^1.0.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" - -binary-extensions@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c" - -bindings@^1.2.1, bindings@^1.3.1, bindings@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" - dependencies: - file-uri-to-path "1.0.0" - -bip39@^2.4.2: - version "2.6.0" - resolved "https://registry.yarnpkg.com/bip39/-/bip39-2.6.0.tgz#9e3a720b42ec8b3fbe4038f1e445317b6a99321c" - dependencies: - create-hash "^1.1.0" - pbkdf2 "^3.0.9" - randombytes "^2.0.1" - safe-buffer "^5.0.1" - unorm "^1.3.3" - -bip66@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/bip66/-/bip66-1.1.5.tgz#01fa8748785ca70955d5011217d1b3139969ca22" - dependencies: - safe-buffer "^5.0.1" - -bl@^1.0.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" - dependencies: - readable-stream "^2.3.5" - safe-buffer "^5.1.1" - -bluebird@^3.5.0: - version "3.7.2" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" - -bn.js@4.11.6: - version "4.11.6" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" - -bn.js@4.11.8: - version "4.11.8" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" - -bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.0, bn.js@^4.11.1, bn.js@^4.11.6, bn.js@^4.11.8, bn.js@^4.4.0: - version "4.11.9" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.9.tgz#26d556829458f9d1e81fc48952493d0ba3507828" - -bn.js@^5.1.1, bn.js@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.2.tgz#c9686902d3c9a27729f43ab10f9d79c2004da7b0" - -body-parser@1.19.0, body-parser@^1.16.0: - version "1.19.0" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" - dependencies: - bytes "3.1.0" - content-type "~1.0.4" - debug "2.6.9" - depd "~1.1.2" - http-errors "1.7.2" - iconv-lite "0.4.24" - on-finished "~2.3.0" - qs "6.7.0" - raw-body "2.4.0" - type-is "~1.6.17" - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^1.8.2: - version "1.8.5" - resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" - dependencies: - expand-range "^1.8.1" - preserve "^0.2.0" - repeat-element "^1.1.2" - -braces@^2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" - dependencies: - arr-flatten "^1.1.0" - array-unique "^0.3.2" - extend-shallow "^2.0.1" - fill-range "^4.0.0" - isobject "^3.0.1" - repeat-element "^1.1.2" - snapdragon "^0.8.1" - snapdragon-node "^2.0.1" - split-string "^3.0.2" - to-regex "^3.0.1" - -braces@^3.0.1, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - dependencies: - fill-range "^7.0.1" - -brorand@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - -browser-stdout@1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" - -browserify-aes@^1.0.0, browserify-aes@^1.0.4, browserify-aes@^1.0.6: - version "1.2.0" - resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" - dependencies: - buffer-xor "^1.0.3" - cipher-base "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.3" - inherits "^2.0.1" - safe-buffer "^5.0.1" - -browserify-cipher@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" - dependencies: - browserify-aes "^1.0.4" - browserify-des "^1.0.0" - evp_bytestokey "^1.0.0" - -browserify-des@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" - dependencies: - cipher-base "^1.0.1" - des.js "^1.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" - dependencies: - bn.js "^4.1.0" - randombytes "^2.0.1" - -browserify-sign@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.0.tgz#545d0b1b07e6b2c99211082bf1b12cce7a0b0e11" - dependencies: - bn.js "^5.1.1" - browserify-rsa "^4.0.1" - create-hash "^1.2.0" - create-hmac "^1.1.7" - elliptic "^6.5.2" - inherits "^2.0.4" - parse-asn1 "^5.1.5" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - -browserslist@^3.2.6: - version "3.2.8" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-3.2.8.tgz#b0005361d6471f0f5952797a76fc985f1f978fc6" - dependencies: - caniuse-lite "^1.0.30000844" - electron-to-chromium "^1.3.47" - -bs58@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" - dependencies: - base-x "^3.0.2" - -bs58check@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc" - dependencies: - bs58 "^4.0.0" - create-hash "^1.1.0" - safe-buffer "^5.1.2" - -btoa@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/btoa/-/btoa-1.2.1.tgz#01a9909f8b2c93f6bf680ba26131eb30f7fa3d73" - -buffer-alloc-unsafe@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" - -buffer-alloc@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" - dependencies: - buffer-alloc-unsafe "^1.1.0" - buffer-fill "^1.0.0" - -buffer-crc32@~0.2.3: - version "0.2.13" - resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" - -buffer-fill@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" - -buffer-from@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" - -buffer-to-arraybuffer@^0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz#6064a40fa76eb43c723aba9ef8f6e1216d10511a" - -buffer-xor@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" - -buffer@^5.0.5, buffer@^5.2.1, buffer@^5.5.0: - version "5.6.0" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.6.0.tgz#a31749dc7d81d84db08abf937b6b8c4033f62786" - dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" - -bytes@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" - -cache-base@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" - dependencies: - collection-visit "^1.0.0" - component-emitter "^1.2.1" - get-value "^2.0.6" - has-value "^1.0.0" - isobject "^3.0.1" - set-value "^2.0.0" - to-object-path "^0.3.0" - union-value "^1.0.0" - unset-value "^1.0.0" - -cacheable-request@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" - dependencies: - clone-response "^1.0.2" - get-stream "^5.1.0" - http-cache-semantics "^4.0.0" - keyv "^3.0.0" - lowercase-keys "^2.0.0" - normalize-url "^4.1.0" - responselike "^1.0.2" - -camelcase@^5.0.0: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - -caniuse-lite@^1.0.30000844: - version "1.0.30001088" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001088.tgz#23a6b9e192106107458528858f2c0e0dba0d9073" - -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - -chai-bignumber@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/chai-bignumber/-/chai-bignumber-3.0.0.tgz#e90cf1f468355bbb11a9acd051222586cd2648a9" - -chai@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5" - dependencies: - assertion-error "^1.1.0" - check-error "^1.0.2" - deep-eql "^3.0.1" - get-func-name "^2.0.0" - pathval "^1.1.0" - type-detect "^4.0.5" - -chalk@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - -chalk@^2.0.0, chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -check-error@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" - -checkpoint-store@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/checkpoint-store/-/checkpoint-store-1.1.0.tgz#04e4cb516b91433893581e6d4601a78e9552ea06" - dependencies: - functional-red-black-tree "^1.0.1" - -chokidar@3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.0.tgz#12c0714668c55800f659e262d4962a97faf554a6" - dependencies: - anymatch "~3.1.1" - braces "~3.0.2" - glob-parent "~5.1.0" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.2.0" - optionalDependencies: - fsevents "~2.1.1" - -chokidar@^1.6.1: - version "1.7.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" - dependencies: - anymatch "^1.3.0" - async-each "^1.0.0" - glob-parent "^2.0.0" - inherits "^2.0.1" - is-binary-path "^1.0.0" - is-glob "^2.0.0" - path-is-absolute "^1.0.0" - readdirp "^2.0.0" - optionalDependencies: - fsevents "^1.0.0" - -chownr@^1.1.1: - version "1.1.4" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" - -cids@^0.7.1: - version "0.7.5" - resolved "https://registry.yarnpkg.com/cids/-/cids-0.7.5.tgz#60a08138a99bfb69b6be4ceb63bfef7a396b28b2" - dependencies: - buffer "^5.5.0" - class-is "^1.1.0" - multibase "~0.6.0" - multicodec "^1.0.0" - multihashes "~0.4.15" - -cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -class-is@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/class-is/-/class-is-1.1.0.tgz#9d3c0fba0440d211d843cec3dedfa48055005825" - -class-utils@^0.3.5: - version "0.3.6" - resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" - dependencies: - arr-union "^3.1.0" - define-property "^0.2.5" - isobject "^3.0.0" - static-extend "^0.1.1" - -cliui@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" - dependencies: - string-width "^3.1.0" - strip-ansi "^5.2.0" - wrap-ansi "^5.1.0" - -clone-response@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" - dependencies: - mimic-response "^1.0.0" - -clone@^2.0.0, clone@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" - -collection-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - dependencies: - map-visit "^1.0.0" - object-visit "^1.0.0" - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - dependencies: - color-name "1.1.3" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - -combined-stream@^1.0.6, combined-stream@~1.0.6: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - dependencies: - delayed-stream "~1.0.0" - -commander@^2.11.0, commander@~2.20.3: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - -commander@~2.8.1: - version "2.8.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" - dependencies: - graceful-readlink ">= 1.0.0" - -component-emitter@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - -concat-stream@^1.5.1: - version "1.6.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - -content-disposition@0.5.3: - version "0.5.3" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" - dependencies: - safe-buffer "5.1.2" - -content-hash@^2.5.2: - version "2.5.2" - resolved "https://registry.yarnpkg.com/content-hash/-/content-hash-2.5.2.tgz#bbc2655e7c21f14fd3bfc7b7d4bfe6e454c9e211" - dependencies: - cids "^0.7.1" - multicodec "^0.5.5" - multihashes "^0.4.15" - -content-type@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" - -convert-source-map@^1.5.0, convert-source-map@^1.5.1: - version "1.7.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" - dependencies: - safe-buffer "~5.1.1" - -cookie-signature@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - -cookie@0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" - -cookiejar@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c" - -copy-descriptor@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - -core-js@^2.4.0, core-js@^2.5.0: - version "2.6.11" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" - -core-util-is@1.0.2, core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - -cors@^2.8.1: - version "2.8.5" - resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" - dependencies: - object-assign "^4" - vary "^1" - -create-ecdh@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" - dependencies: - bn.js "^4.1.0" - elliptic "^6.0.0" - -create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" - dependencies: - cipher-base "^1.0.1" - inherits "^2.0.1" - md5.js "^1.3.4" - ripemd160 "^2.0.1" - sha.js "^2.4.0" - -create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" - dependencies: - cipher-base "^1.0.3" - create-hash "^1.1.0" - inherits "^2.0.1" - ripemd160 "^2.0.0" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -cross-fetch@^2.1.0, cross-fetch@^2.1.1: - version "2.2.3" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-2.2.3.tgz#e8a0b3c54598136e037f8650f8e823ccdfac198e" - dependencies: - node-fetch "2.1.2" - whatwg-fetch "2.0.4" - -cross-spawn@^6.0.0: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - -crypto-browserify@3.12.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" - dependencies: - browserify-cipher "^1.0.0" - browserify-sign "^4.0.0" - create-ecdh "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.0" - diffie-hellman "^5.0.0" - inherits "^2.0.1" - pbkdf2 "^3.0.3" - public-encrypt "^4.0.0" - randombytes "^2.0.0" - randomfill "^1.0.3" - -d@1, d@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" - dependencies: - es5-ext "^0.10.50" - type "^1.0.1" - -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - dependencies: - assert-plus "^1.0.0" - -death@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/death/-/death-1.1.0.tgz#01aa9c401edd92750514470b8266390c66c67318" - -debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.8, debug@^2.6.9: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - dependencies: - ms "2.0.0" - -debug@3.2.6: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - dependencies: - ms "^2.1.1" - -debug@^4.1.0, debug@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" - dependencies: - ms "^2.1.1" - -decamelize@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - -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" - -decompress-response@^3.2.0, decompress-response@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" - dependencies: - mimic-response "^1.0.0" - -decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/decompress-tar/-/decompress-tar-4.1.1.tgz#718cbd3fcb16209716e70a26b84e7ba4592e5af1" - dependencies: - file-type "^5.2.0" - is-stream "^1.1.0" - tar-stream "^1.5.2" - -decompress-tarbz2@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz#3082a5b880ea4043816349f378b56c516be1a39b" - dependencies: - decompress-tar "^4.1.0" - file-type "^6.1.0" - is-stream "^1.1.0" - seek-bzip "^1.0.5" - unbzip2-stream "^1.0.9" - -decompress-targz@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/decompress-targz/-/decompress-targz-4.1.1.tgz#c09bc35c4d11f3de09f2d2da53e9de23e7ce1eee" - dependencies: - decompress-tar "^4.1.1" - file-type "^5.2.0" - is-stream "^1.1.0" - -decompress-unzip@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/decompress-unzip/-/decompress-unzip-4.0.1.tgz#deaaccdfd14aeaf85578f733ae8210f9b4848f69" - dependencies: - file-type "^3.8.0" - get-stream "^2.2.0" - pify "^2.3.0" - yauzl "^2.4.2" - -decompress@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/decompress/-/decompress-4.2.1.tgz#007f55cc6a62c055afa37c07eb6a4ee1b773f118" - dependencies: - decompress-tar "^4.0.0" - decompress-tarbz2 "^4.0.0" - decompress-targz "^4.0.0" - decompress-unzip "^4.0.1" - graceful-fs "^4.1.10" - make-dir "^1.0.0" - pify "^2.3.0" - strip-dirs "^2.0.0" - -deep-eql@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" - dependencies: - type-detect "^4.0.0" - -deep-equal@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" - dependencies: - is-arguments "^1.0.4" - is-date-object "^1.0.1" - is-regex "^1.0.4" - object-is "^1.0.1" - object-keys "^1.1.1" - regexp.prototype.flags "^1.2.0" - -deep-is@~0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - -defer-to-connect@^1.0.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" - -deferred-leveldown@~1.2.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-1.2.2.tgz#3acd2e0b75d1669924bc0a4b642851131173e1eb" - dependencies: - abstract-leveldown "~2.6.0" - -define-properties@^1.1.2, define-properties@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - dependencies: - object-keys "^1.0.12" - -define-property@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - dependencies: - is-descriptor "^0.1.0" - -define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - dependencies: - is-descriptor "^1.0.0" - -define-property@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" - dependencies: - is-descriptor "^1.0.2" - isobject "^3.0.1" - -defined@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - -depd@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - -des.js@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" - dependencies: - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - -destroy@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" - -detect-indent@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" - dependencies: - repeating "^2.0.0" - -detect-port@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/detect-port/-/detect-port-1.3.0.tgz#d9c40e9accadd4df5cac6a782aefd014d573d1f1" - dependencies: - address "^1.0.1" - debug "^2.6.0" - -diff@3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" - -diff@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" - -diffie-hellman@^5.0.0: - version "5.0.3" - resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" - dependencies: - bn.js "^4.1.0" - miller-rabin "^4.0.0" - randombytes "^2.0.0" - -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" - dependencies: - path-type "^4.0.0" - -dir-to-object@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/dir-to-object/-/dir-to-object-2.0.0.tgz#29723e9bd1c3e58e4f307bd04ff634c0370c8f8a" - -dom-walk@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" - -dotenv-flow@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/dotenv-flow/-/dotenv-flow-3.1.0.tgz#2abcb4661cf2d0ca5b46d8ff5e95c1045ade9938" - dependencies: - dotenv "^8.0.0" - -dotenv@^8.0.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" - -dotignore@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/dotignore/-/dotignore-0.1.2.tgz#f942f2200d28c3a76fbdd6f0ee9f3257c8a2e905" - dependencies: - minimatch "^3.0.4" - -drbg.js@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/drbg.js/-/drbg.js-1.0.1.tgz#3e36b6c42b37043823cdbc332d58f31e2445480b" - dependencies: - browserify-aes "^1.0.6" - create-hash "^1.1.2" - create-hmac "^1.1.4" - -duplexer3@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" - -ecc-jsbn@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" - -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - -electron-to-chromium@^1.3.47: - version "1.3.483" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.483.tgz#9269e7cfc1c8e72709824da171cbe47ca5e3ca9e" - -elliptic@6.3.3: - version "6.3.3" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.3.3.tgz#5482d9646d54bcb89fd7d994fc9e2e9568876e3f" - dependencies: - bn.js "^4.4.0" - brorand "^1.0.1" - hash.js "^1.0.0" - inherits "^2.0.1" - -elliptic@6.5.2, elliptic@^6.0.0, elliptic@^6.4.0, elliptic@^6.5.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.2.tgz#05c5678d7173c049d8ca433552224a495d0e3762" - dependencies: - bn.js "^4.4.0" - brorand "^1.0.1" - hash.js "^1.0.0" - hmac-drbg "^1.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.0" - -emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - -emoji-regex@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.0.0.tgz#48a2309cc8a1d2e9d23bc6a67c39b63032e76ea4" - -encodeurl@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - -encoding@^0.1.11: - version "0.1.12" - resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" - dependencies: - iconv-lite "~0.4.13" - -end-of-stream@^1.0.0, end-of-stream@^1.1.0: - version "1.4.4" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" - dependencies: - once "^1.4.0" - -errno@~0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" - dependencies: - prr "~1.0.1" - -es-abstract@^1.17.0-next.1, es-abstract@^1.17.4, es-abstract@^1.17.5: - version "1.17.5" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.5.tgz#d8c9d1d66c8981fb9200e2251d799eee92774ae9" - dependencies: - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - is-callable "^1.1.5" - is-regex "^1.0.5" - object-inspect "^1.7.0" - object-keys "^1.1.1" - object.assign "^4.1.0" - string.prototype.trimleft "^2.1.1" - string.prototype.trimright "^2.1.1" - -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - -es5-ext@^0.10.35, es5-ext@^0.10.50: - version "0.10.53" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1" - dependencies: - es6-iterator "~2.0.3" - es6-symbol "~3.1.3" - next-tick "~1.0.0" - -es6-iterator@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" - dependencies: - d "1" - es5-ext "^0.10.35" - es6-symbol "^3.1.1" - -es6-object-assign@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/es6-object-assign/-/es6-object-assign-1.1.0.tgz#c2c3582656247c39ea107cb1e6652b6f9f24523c" - -es6-promisify@^6.1.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-6.1.1.tgz#46837651b7b06bf6fff893d03f29393668d01621" - -es6-symbol@^3.1.1, es6-symbol@~3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" - dependencies: - d "^1.0.1" - ext "^1.1.2" - -escape-html@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - -escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - -escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" - -escodegen@1.8.x: - version "1.8.1" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018" - dependencies: - esprima "^2.7.1" - estraverse "^1.9.1" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.2.0" - -eslint-visitor-keys@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.2.0.tgz#74415ac884874495f78ec2a97349525344c981fa" - -esprima-extract-comments@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/esprima-extract-comments/-/esprima-extract-comments-1.1.0.tgz#0dacab567a5900240de6d344cf18c33617becbc9" - dependencies: - esprima "^4.0.0" - -esprima@2.7.x, esprima@^2.7.1: - version "2.7.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - -estraverse@^1.9.1: - version "1.9.3" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44" - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - -etag@~1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - -eth-block-tracker@^4.2.0: - version "4.4.3" - resolved "https://registry.yarnpkg.com/eth-block-tracker/-/eth-block-tracker-4.4.3.tgz#766a0a0eb4a52c867a28328e9ae21353812cf626" - dependencies: - "@babel/plugin-transform-runtime" "^7.5.5" - "@babel/runtime" "^7.5.5" - eth-query "^2.1.0" - json-rpc-random-id "^1.0.1" - pify "^3.0.0" - safe-event-emitter "^1.0.1" - -eth-ens-namehash@2.0.8: - version "2.0.8" - resolved "https://registry.yarnpkg.com/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz#229ac46eca86d52e0c991e7cb2aef83ff0f68bcf" - dependencies: - idna-uts46-hx "^2.3.1" - js-sha3 "^0.5.7" - -eth-json-rpc-errors@^1.0.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/eth-json-rpc-errors/-/eth-json-rpc-errors-1.1.1.tgz#148377ef55155585981c21ff574a8937f9d6991f" - dependencies: - fast-safe-stringify "^2.0.6" - -eth-json-rpc-errors@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/eth-json-rpc-errors/-/eth-json-rpc-errors-2.0.2.tgz#c1965de0301fe941c058e928bebaba2e1285e3c4" - dependencies: - fast-safe-stringify "^2.0.6" - -eth-json-rpc-filters@^4.0.2: - version "4.1.1" - resolved "https://registry.yarnpkg.com/eth-json-rpc-filters/-/eth-json-rpc-filters-4.1.1.tgz#15277c66790236d85f798f4d7dc6bab99a798cd2" - dependencies: - await-semaphore "^0.1.3" - eth-json-rpc-middleware "^4.1.4" - eth-query "^2.1.2" - json-rpc-engine "^5.1.3" - lodash.flatmap "^4.5.0" - safe-event-emitter "^1.0.1" - -eth-json-rpc-infura@^3.1.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/eth-json-rpc-infura/-/eth-json-rpc-infura-3.2.1.tgz#26702a821067862b72d979c016fd611502c6057f" - dependencies: - cross-fetch "^2.1.1" - eth-json-rpc-middleware "^1.5.0" - json-rpc-engine "^3.4.0" - json-rpc-error "^2.0.0" - -eth-json-rpc-middleware@^1.5.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/eth-json-rpc-middleware/-/eth-json-rpc-middleware-1.6.0.tgz#5c9d4c28f745ccb01630f0300ba945f4bef9593f" - dependencies: - async "^2.5.0" - eth-query "^2.1.2" - eth-tx-summary "^3.1.2" - ethereumjs-block "^1.6.0" - ethereumjs-tx "^1.3.3" - ethereumjs-util "^5.1.2" - ethereumjs-vm "^2.1.0" - fetch-ponyfill "^4.0.0" - json-rpc-engine "^3.6.0" - json-rpc-error "^2.0.0" - json-stable-stringify "^1.0.1" - promise-to-callback "^1.0.0" - tape "^4.6.3" - -eth-json-rpc-middleware@^4.1.1, eth-json-rpc-middleware@^4.1.4: - version "4.4.1" - resolved "https://registry.yarnpkg.com/eth-json-rpc-middleware/-/eth-json-rpc-middleware-4.4.1.tgz#07d3dd0724c24a8d31e4a172ee96271da71b4228" - dependencies: - btoa "^1.2.1" - clone "^2.1.1" - eth-json-rpc-errors "^1.0.1" - eth-query "^2.1.2" - eth-sig-util "^1.4.2" - ethereumjs-block "^1.6.0" - ethereumjs-tx "^1.3.7" - ethereumjs-util "^5.1.2" - ethereumjs-vm "^2.6.0" - fetch-ponyfill "^4.0.0" - json-rpc-engine "^5.1.3" - json-stable-stringify "^1.0.1" - pify "^3.0.0" - safe-event-emitter "^1.0.1" - -eth-lib@0.2.7: - version "0.2.7" - resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.2.7.tgz#2f93f17b1e23aec3759cd4a3fe20c1286a3fc1ca" - dependencies: - bn.js "^4.11.6" - elliptic "^6.4.0" - xhr-request-promise "^0.1.2" - -eth-lib@^0.1.26: - version "0.1.29" - resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.1.29.tgz#0c11f5060d42da9f931eab6199084734f4dbd1d9" - dependencies: - bn.js "^4.11.6" - elliptic "^6.4.0" - nano-json-stream-parser "^0.1.2" - servify "^0.1.12" - ws "^3.0.0" - xhr-request-promise "^0.1.2" - -eth-lib@^0.2.8: - version "0.2.8" - resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.2.8.tgz#b194058bef4b220ad12ea497431d6cb6aa0623c8" - dependencies: - bn.js "^4.11.6" - elliptic "^6.4.0" - xhr-request-promise "^0.1.2" - -eth-query@^2.0.2, eth-query@^2.1.0, eth-query@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/eth-query/-/eth-query-2.1.2.tgz#d6741d9000106b51510c72db92d6365456a6da5e" - dependencies: - json-rpc-random-id "^1.0.0" - xtend "^4.0.1" - -eth-sig-util@^1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/eth-sig-util/-/eth-sig-util-1.4.2.tgz#8d958202c7edbaae839707fba6f09ff327606210" - dependencies: - ethereumjs-abi "git+https://github.com/ethereumjs/ethereumjs-abi.git" - ethereumjs-util "^5.1.1" - -eth-tx-summary@^3.1.2: - version "3.2.4" - resolved "https://registry.yarnpkg.com/eth-tx-summary/-/eth-tx-summary-3.2.4.tgz#e10eb95eb57cdfe549bf29f97f1e4f1db679035c" - dependencies: - async "^2.1.2" - clone "^2.0.0" - concat-stream "^1.5.1" - end-of-stream "^1.1.0" - eth-query "^2.0.2" - ethereumjs-block "^1.4.1" - ethereumjs-tx "^1.1.1" - ethereumjs-util "^5.0.1" - ethereumjs-vm "^2.6.0" - through2 "^2.0.3" - -ethereum-bloom-filters@^1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.7.tgz#b7b80735e385dbb7f944ce6b4533e24511306060" - dependencies: - js-sha3 "^0.8.0" - -ethereum-common@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/ethereum-common/-/ethereum-common-0.2.0.tgz#13bf966131cce1eeade62a1b434249bb4cb120ca" - -ethereum-common@^0.0.18: - version "0.0.18" - resolved "https://registry.yarnpkg.com/ethereum-common/-/ethereum-common-0.0.18.tgz#2fdc3576f232903358976eb39da783213ff9523f" - -ethereum-protocol@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/ethereum-protocol/-/ethereum-protocol-1.0.1.tgz#b7d68142f4105e0ae7b5e178cf42f8d4dc4b93cf" - -"ethereumjs-abi@git+https://github.com/ethereumjs/ethereumjs-abi.git": - version "0.6.8" - resolved "git+https://github.com/ethereumjs/ethereumjs-abi.git#1cfbb13862f90f0b391d8a699544d5fe4dfb8c7b" - dependencies: - bn.js "^4.11.8" - ethereumjs-util "^6.0.0" - -ethereumjs-account@^2.0.3: - version "2.0.5" - resolved "https://registry.yarnpkg.com/ethereumjs-account/-/ethereumjs-account-2.0.5.tgz#eeafc62de544cb07b0ee44b10f572c9c49e00a84" - dependencies: - ethereumjs-util "^5.0.0" - rlp "^2.0.0" - safe-buffer "^5.1.1" - -ethereumjs-block@^1.2.2, ethereumjs-block@^1.4.1, ethereumjs-block@^1.6.0: - version "1.7.1" - resolved "https://registry.yarnpkg.com/ethereumjs-block/-/ethereumjs-block-1.7.1.tgz#78b88e6cc56de29a6b4884ee75379b6860333c3f" - dependencies: - async "^2.0.1" - ethereum-common "0.2.0" - ethereumjs-tx "^1.2.2" - ethereumjs-util "^5.0.0" - merkle-patricia-tree "^2.1.2" - -ethereumjs-block@~2.2.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/ethereumjs-block/-/ethereumjs-block-2.2.2.tgz#c7654be7e22df489fda206139ecd63e2e9c04965" - dependencies: - async "^2.0.1" - ethereumjs-common "^1.5.0" - ethereumjs-tx "^2.1.1" - ethereumjs-util "^5.0.0" - merkle-patricia-tree "^2.1.2" - -ethereumjs-common@^1.1.0, ethereumjs-common@^1.3.2, ethereumjs-common@^1.5.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/ethereumjs-common/-/ethereumjs-common-1.5.1.tgz#4e75042473a64daec0ed9fe84323dd9576aa5dba" - -ethereumjs-tx@^1.0.0, ethereumjs-tx@^1.1.1, ethereumjs-tx@^1.2.0, ethereumjs-tx@^1.2.2, ethereumjs-tx@^1.3.3, ethereumjs-tx@^1.3.7: - version "1.3.7" - resolved "https://registry.yarnpkg.com/ethereumjs-tx/-/ethereumjs-tx-1.3.7.tgz#88323a2d875b10549b8347e09f4862b546f3d89a" - dependencies: - ethereum-common "^0.0.18" - ethereumjs-util "^5.0.0" - -ethereumjs-tx@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ethereumjs-tx/-/ethereumjs-tx-2.1.2.tgz#5dfe7688bf177b45c9a23f86cf9104d47ea35fed" - dependencies: - ethereumjs-common "^1.5.0" - ethereumjs-util "^6.0.0" - -ethereumjs-util@6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-6.1.0.tgz#e9c51e5549e8ebd757a339cc00f5380507e799c8" - dependencies: - bn.js "^4.11.0" - create-hash "^1.1.2" - ethjs-util "0.1.6" - keccak "^1.0.2" - rlp "^2.0.0" - safe-buffer "^5.1.1" - secp256k1 "^3.0.1" - -ethereumjs-util@^5.0.0, ethereumjs-util@^5.0.1, ethereumjs-util@^5.1.1, ethereumjs-util@^5.1.2, ethereumjs-util@^5.1.5: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz#3e0c0d1741471acf1036052d048623dee54ad642" - dependencies: - bn.js "^4.11.0" - create-hash "^1.1.2" - ethjs-util "^0.1.3" - keccak "^1.0.2" - rlp "^2.0.0" - safe-buffer "^5.1.1" - secp256k1 "^3.0.1" - -ethereumjs-util@^6.0.0, ethereumjs-util@^6.1.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-6.2.0.tgz#23ec79b2488a7d041242f01e25f24e5ad0357960" - dependencies: - "@types/bn.js" "^4.11.3" - bn.js "^4.11.0" - create-hash "^1.1.2" - ethjs-util "0.1.6" - keccak "^2.0.0" - rlp "^2.2.3" - secp256k1 "^3.0.1" - -ethereumjs-util@^7.0.2: - version "7.0.2" - resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.0.2.tgz#7e0d9fcd225ece6e49ee4ea65609d124715f1d15" - dependencies: - "@types/bn.js" "^4.11.3" - bn.js "^5.1.2" - create-hash "^1.1.2" - ethjs-util "0.1.6" - keccak "^3.0.0" - rlp "^2.2.4" - secp256k1 "^4.0.1" - -ethereumjs-vm@^2.1.0, ethereumjs-vm@^2.3.4, ethereumjs-vm@^2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/ethereumjs-vm/-/ethereumjs-vm-2.6.0.tgz#76243ed8de031b408793ac33907fb3407fe400c6" - dependencies: - async "^2.1.2" - async-eventemitter "^0.2.2" - ethereumjs-account "^2.0.3" - ethereumjs-block "~2.2.0" - ethereumjs-common "^1.1.0" - ethereumjs-util "^6.0.0" - fake-merkle-patricia-tree "^1.0.1" - functional-red-black-tree "^1.0.1" - merkle-patricia-tree "^2.3.2" - rustbn.js "~0.2.0" - safe-buffer "^5.1.1" - -ethereumjs-wallet@^0.6.3: - version "0.6.4" - resolved "https://registry.yarnpkg.com/ethereumjs-wallet/-/ethereumjs-wallet-0.6.4.tgz#67dd013dd839e69a8eb9a8f78cacfc9bff307167" - dependencies: - aes-js "^3.1.1" - bs58check "^2.1.2" - ethereumjs-util "^6.0.0" - hdkey "^1.1.1" - randombytes "^2.0.6" - safe-buffer "^5.1.2" - scryptsy "^1.2.1" - utf8 "^3.0.0" - uuid "^3.3.2" - -ethers@4.0.0-beta.3: - version "4.0.0-beta.3" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.0-beta.3.tgz#15bef14e57e94ecbeb7f9b39dd0a4bd435bc9066" - dependencies: - "@types/node" "^10.3.2" - aes-js "3.0.0" - bn.js "^4.4.0" - elliptic "6.3.3" - hash.js "1.1.3" - js-sha3 "0.5.7" - scrypt-js "2.0.3" - setimmediate "1.0.4" - uuid "2.0.1" - xmlhttprequest "1.8.0" - -ethers@^4.0.32: - version "4.0.47" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.47.tgz#91b9cd80473b1136dd547095ff9171bd1fc68c85" - dependencies: - aes-js "3.0.0" - bn.js "^4.4.0" - elliptic "6.5.2" - hash.js "1.1.3" - js-sha3 "0.5.7" - scrypt-js "2.0.4" - setimmediate "1.0.4" - uuid "2.0.1" - xmlhttprequest "1.8.0" - -ethjs-unit@0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" - dependencies: - bn.js "4.11.6" - number-to-bn "1.7.0" - -ethjs-util@0.1.6, ethjs-util@^0.1.3: - version "0.1.6" - resolved "https://registry.yarnpkg.com/ethjs-util/-/ethjs-util-0.1.6.tgz#f308b62f185f9fe6237132fb2a9818866a5cd536" - dependencies: - is-hex-prefixed "1.0.0" - strip-hex-prefix "1.0.0" - -eventemitter3@3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7" - -eventemitter3@^4.0.0: - version "4.0.4" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.4.tgz#b5463ace635a083d018bdc7c917b4c5f10a85384" - -events@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.1.0.tgz#84279af1b34cb75aa88bf5ff291f6d0bd9b31a59" - -evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" - dependencies: - md5.js "^1.3.4" - safe-buffer "^5.1.1" - -execa@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" - dependencies: - cross-spawn "^6.0.0" - get-stream "^4.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - -expand-brackets@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" - dependencies: - is-posix-bracket "^0.1.0" - -expand-brackets@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - dependencies: - debug "^2.3.3" - define-property "^0.2.5" - extend-shallow "^2.0.1" - posix-character-classes "^0.1.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -expand-range@^1.8.1: - version "1.8.2" - resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" - dependencies: - fill-range "^2.1.0" - -express@^4.14.0: - version "4.17.1" - resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" - dependencies: - accepts "~1.3.7" - array-flatten "1.1.1" - body-parser "1.19.0" - content-disposition "0.5.3" - content-type "~1.0.4" - cookie "0.4.0" - cookie-signature "1.0.6" - debug "2.6.9" - depd "~1.1.2" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - finalhandler "~1.1.2" - fresh "0.5.2" - merge-descriptors "1.0.1" - methods "~1.1.2" - on-finished "~2.3.0" - parseurl "~1.3.3" - path-to-regexp "0.1.7" - proxy-addr "~2.0.5" - qs "6.7.0" - range-parser "~1.2.1" - safe-buffer "5.1.2" - send "0.17.1" - serve-static "1.14.1" - setprototypeof "1.1.1" - statuses "~1.5.0" - type-is "~1.6.18" - utils-merge "1.0.1" - vary "~1.1.2" - -ext@^1.1.2: - version "1.4.0" - resolved "https://registry.yarnpkg.com/ext/-/ext-1.4.0.tgz#89ae7a07158f79d35517882904324077e4379244" - dependencies: - type "^2.0.0" - -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - dependencies: - is-extendable "^0.1.0" - -extend-shallow@^3.0.0, extend-shallow@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - dependencies: - assign-symbols "^1.0.0" - is-extendable "^1.0.1" - -extend@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - -extglob@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" - dependencies: - is-extglob "^1.0.0" - -extglob@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" - dependencies: - array-unique "^0.3.2" - define-property "^1.0.0" - expand-brackets "^2.1.4" - extend-shallow "^2.0.1" - fragment-cache "^0.2.1" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -extract-comments@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/extract-comments/-/extract-comments-1.1.0.tgz#b90bca033a056bd69b8ba1c6b6b120fc2ee95c18" - dependencies: - esprima-extract-comments "^1.1.0" - parse-code-context "^1.0.0" - -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - -extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - -fake-merkle-patricia-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/fake-merkle-patricia-tree/-/fake-merkle-patricia-tree-1.0.1.tgz#4b8c3acfb520afadf9860b1f14cd8ce3402cddd3" - dependencies: - checkpoint-store "^1.1.0" - -fast-deep-equal@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4" - -fast-glob@^3.0.3: - version "3.2.2" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.2.tgz#ade1a9d91148965d4bf7c51f72e1ca662d32e63d" - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.0" - merge2 "^1.3.0" - micromatch "^4.0.2" - picomatch "^2.2.1" - -fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - -fast-levenshtein@~2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - -fast-safe-stringify@^2.0.6: - version "2.0.7" - resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz#124aa885899261f68aedb42a7c080de9da608743" - -fastq@^1.6.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.8.0.tgz#550e1f9f59bbc65fe185cb6a9b4d95357107f481" - dependencies: - reusify "^1.0.4" - -fd-slicer@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" - dependencies: - pend "~1.2.0" - -fetch-ponyfill@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/fetch-ponyfill/-/fetch-ponyfill-4.1.0.tgz#ae3ce5f732c645eab87e4ae8793414709b239893" - dependencies: - node-fetch "~1.7.1" - -file-type@^3.8.0: - version "3.9.0" - resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9" - -file-type@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/file-type/-/file-type-5.2.0.tgz#2ddbea7c73ffe36368dfae49dc338c058c2b8ad6" - -file-type@^6.1.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/file-type/-/file-type-6.2.0.tgz#e50cd75d356ffed4e306dc4f5bcf52a79903a919" - -file-uri-to-path@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" - -filename-regex@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" - -fill-range@^2.1.0: - version "2.2.4" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" - dependencies: - is-number "^2.1.0" - isobject "^2.0.0" - randomatic "^3.0.0" - repeat-element "^1.1.2" - repeat-string "^1.5.2" - -fill-range@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - dependencies: - extend-shallow "^2.0.1" - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range "^2.1.0" - -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - dependencies: - to-regex-range "^5.0.1" - -finalhandler@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" - dependencies: - debug "2.6.9" - encodeurl "~1.0.2" - escape-html "~1.0.3" - on-finished "~2.3.0" - parseurl "~1.3.3" - statuses "~1.5.0" - unpipe "~1.0.0" - -find-up@3.0.0, find-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" - dependencies: - locate-path "^3.0.0" - -flat@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2" - dependencies: - is-buffer "~2.0.3" - -for-each@~0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" - dependencies: - is-callable "^1.1.3" - -for-in@^1.0.1, for-in@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - -for-own@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" - dependencies: - for-in "^1.0.1" - -foreach@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" - -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - -form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - -forwarded@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" - -fragment-cache@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - dependencies: - map-cache "^0.2.2" - -fresh@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - -fs-constants@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" - -fs-extra@^4.0.2: - version "4.0.3" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - -fs-extra@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" - dependencies: - graceful-fs "^4.2.0" - jsonfile "^4.0.0" - universalify "^0.1.0" - -fs-minipass@^1.2.5: - version "1.2.7" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" - dependencies: - minipass "^2.6.0" - -fs-readdir-recursive@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - -fsevents@^1.0.0: - version "1.2.13" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" - dependencies: - bindings "^1.5.0" - nan "^2.12.1" - -fsevents@~2.1.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" - -function-bind@^1.1.1, function-bind@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - -ganache-cli@6.9.0: - version "6.9.0" - resolved "https://registry.yarnpkg.com/ganache-cli/-/ganache-cli-6.9.0.tgz#94d7e26964dff80b7382a33829ec75e15709a948" - dependencies: - ethereumjs-util "6.1.0" - source-map-support "0.5.12" - yargs "13.2.4" - -ganache-cli@^6.9.1: - version "6.9.1" - resolved "https://registry.yarnpkg.com/ganache-cli/-/ganache-cli-6.9.1.tgz#1e13eee098fb9f19b031a191ec3f62ae926ea8b3" - dependencies: - ethereumjs-util "6.1.0" - source-map-support "0.5.12" - yargs "13.2.4" - -get-caller-file@^2.0.1: - version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" - -get-func-name@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" - -get-stream@^2.2.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-2.3.1.tgz#5f38f93f346009666ee0150a054167f91bdd95de" - dependencies: - object-assign "^4.0.1" - pinkie-promise "^2.0.0" - -get-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" - -get-stream@^4.0.0, get-stream@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" - dependencies: - pump "^3.0.0" - -get-stream@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.1.0.tgz#01203cdc92597f9b909067c3e656cc1f4d3c4dc9" - dependencies: - pump "^3.0.0" - -get-value@^2.0.3, get-value@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - dependencies: - assert-plus "^1.0.0" - -ghost-testrpc@^0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/ghost-testrpc/-/ghost-testrpc-0.0.2.tgz#c4de9557b1d1ae7b2d20bbe474a91378ca90ce92" - dependencies: - chalk "^2.4.2" - node-emoji "^1.10.0" - -glob-base@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" - dependencies: - glob-parent "^2.0.0" - is-glob "^2.0.0" - -glob-parent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" - dependencies: - is-glob "^2.0.0" - -glob-parent@^5.1.0, glob-parent@~5.1.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" - dependencies: - is-glob "^4.0.1" - -glob@7.1.3: - version "7.1.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@^5.0.15: - version "5.0.15" - resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" - dependencies: - inflight "^1.0.4" - inherits "2" - minimatch "2 || 3" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@^7.0.0, glob@^7.1.2, glob@^7.1.3, glob@~7.1.6: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -global-modules@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" - dependencies: - global-prefix "^3.0.0" - -global-prefix@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97" - dependencies: - ini "^1.3.5" - kind-of "^6.0.2" - which "^1.3.1" - -global@~4.3.0: - version "4.3.2" - resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f" - dependencies: - min-document "^2.19.0" - process "~0.5.1" - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - -globals@^9.18.0: - version "9.18.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" - -globby@^10.0.1: - version "10.0.2" - resolved "https://registry.yarnpkg.com/globby/-/globby-10.0.2.tgz#277593e745acaa4646c3ab411289ec47a0392543" - dependencies: - "@types/glob" "^7.1.1" - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.0.3" - glob "^7.1.3" - ignore "^5.1.1" - merge2 "^1.2.3" - slash "^3.0.0" - -got@9.6.0: - version "9.6.0" - resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" - dependencies: - "@sindresorhus/is" "^0.14.0" - "@szmarczak/http-timer" "^1.1.2" - cacheable-request "^6.0.0" - decompress-response "^3.3.0" - duplexer3 "^0.1.4" - get-stream "^4.1.0" - lowercase-keys "^1.0.1" - mimic-response "^1.0.1" - p-cancelable "^1.0.0" - to-readable-stream "^1.0.0" - url-parse-lax "^3.0.0" - -got@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/got/-/got-7.1.0.tgz#05450fd84094e6bbea56f451a43a9c289166385a" - dependencies: - decompress-response "^3.2.0" - duplexer3 "^0.1.4" - get-stream "^3.0.0" - is-plain-obj "^1.1.0" - is-retry-allowed "^1.0.0" - is-stream "^1.0.0" - isurl "^1.0.0-alpha5" - lowercase-keys "^1.0.0" - p-cancelable "^0.3.0" - p-timeout "^1.1.1" - safe-buffer "^5.0.1" - timed-out "^4.0.0" - url-parse-lax "^1.0.0" - url-to-options "^1.0.1" - -graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.2.0: - version "4.2.4" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" - -"graceful-readlink@>= 1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" - -growl@1.10.5: - version "1.10.5" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" - -handlebars@^4.0.1: - version "4.7.6" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.6.tgz#d4c05c1baf90e9945f77aa68a7a219aa4a7df74e" - dependencies: - minimist "^1.2.5" - neo-async "^2.6.0" - source-map "^0.6.1" - wordwrap "^1.0.0" - optionalDependencies: - uglify-js "^3.1.4" - -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - -har-validator@~5.1.3: - version "5.1.3" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" - dependencies: - ajv "^6.5.5" - har-schema "^2.0.0" - -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - dependencies: - ansi-regex "^2.0.0" - -has-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - -has-symbol-support-x@^1.4.1: - version "1.4.2" - resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" - -has-symbols@^1.0.0, has-symbols@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" - -has-to-string-tag-x@^1.2.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" - dependencies: - has-symbol-support-x "^1.4.1" - -has-value@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - dependencies: - get-value "^2.0.3" - has-values "^0.1.4" - isobject "^2.0.0" - -has-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - dependencies: - get-value "^2.0.6" - has-values "^1.0.0" - isobject "^3.0.0" - -has-values@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - -has-values@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - -has@^1.0.3, has@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - dependencies: - function-bind "^1.1.1" - -hash-base@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" - dependencies: - inherits "^2.0.4" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - -hash.js@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.3.tgz#340dedbe6290187151c1ea1d777a3448935df846" - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.0" - -hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" - -hdkey@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/hdkey/-/hdkey-1.1.2.tgz#c60f9cf6f90fbf24a8a52ea06893f36a0108cd3e" - dependencies: - bs58check "^2.1.2" - safe-buffer "^5.1.1" - secp256k1 "^3.0.1" - -he@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" - -hmac-drbg@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - -home-or-tmp@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.1" - -http-cache-semantics@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" - -http-errors@1.7.2: - version "1.7.2" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" - dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.1" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.0" - -http-errors@~1.7.2: - version "1.7.3" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" - dependencies: - depd "~1.1.2" - inherits "2.0.4" - setprototypeof "1.1.1" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.0" - -http-https@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/http-https/-/http-https-1.0.0.tgz#2f908dd5f1db4068c058cd6e6d4ce392c913389b" - -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - -iconv-lite@0.4.24, iconv-lite@~0.4.13: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - dependencies: - safer-buffer ">= 2.1.2 < 3" - -idna-uts46-hx@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz#a1dc5c4df37eee522bf66d969cc980e00e8711f9" - dependencies: - punycode "2.1.0" - -ieee754@^1.1.4: - version "1.1.13" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" - -ignore@^5.1.1: - version "5.1.8" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" - -immediate@^3.2.3: - version "3.3.0" - resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.3.0.tgz#1aef225517836bcdf7f2a2de2600c79ff0269266" - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3, inherits@~2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - -inherits@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - -ini@^1.3.5: - version "1.3.5" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" - -interpret@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" - -invariant@^2.2.2: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - dependencies: - loose-envify "^1.0.0" - -invert-kv@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" - -ipaddr.js@1.9.1: - version "1.9.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" - -is-accessor-descriptor@^0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" - dependencies: - kind-of "^3.0.2" - -is-accessor-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" - dependencies: - kind-of "^6.0.0" - -is-arguments@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.0.4.tgz#3faf966c7cba0ff437fb31f6250082fcf0448cf3" - -is-binary-path@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" - dependencies: - binary-extensions "^1.0.0" - -is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" - dependencies: - binary-extensions "^2.0.0" - -is-buffer@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - -is-buffer@~2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.4.tgz#3e572f23c8411a5cfd9557c849e3665e0b290623" - -is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.1.5: - version "1.2.0" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.0.tgz#83336560b54a38e35e3a2df7afd0454d691468bb" - -is-data-descriptor@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" - dependencies: - kind-of "^3.0.2" - -is-data-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" - dependencies: - kind-of "^6.0.0" - -is-date-object@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" - -is-descriptor@^0.1.0: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" - dependencies: - is-accessor-descriptor "^0.1.6" - is-data-descriptor "^0.1.4" - kind-of "^5.0.0" - -is-descriptor@^1.0.0, is-descriptor@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" - dependencies: - is-accessor-descriptor "^1.0.0" - is-data-descriptor "^1.0.0" - kind-of "^6.0.2" - -is-dotfile@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" - -is-equal-shallow@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" - dependencies: - is-primitive "^2.0.0" - -is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - -is-extendable@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" - dependencies: - is-plain-object "^2.0.4" - -is-extglob@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - -is-finite@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3" - -is-fn@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fn/-/is-fn-1.0.0.tgz#9543d5de7bcf5b08a22ec8a20bae6e286d510d8c" - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - -is-function@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.2.tgz#4f097f30abf6efadac9833b17ca5dc03f8144e08" - -is-generator-function@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.7.tgz#d2132e529bb0000a7f80794d4bdf5cd5e5813522" - -is-glob@^2.0.0, is-glob@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" - dependencies: - is-extglob "^1.0.0" - -is-glob@^4.0.1, is-glob@~4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - dependencies: - is-extglob "^2.1.1" - -is-hex-prefixed@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" - -is-nan@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.0.tgz#85d1f5482f7051c2019f5673ccebdb06f3b0db03" - dependencies: - define-properties "^1.1.3" - -is-natural-number@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-natural-number/-/is-natural-number-4.0.1.tgz#ab9d76e1db4ced51e35de0c72ebecf09f734cde8" - -is-number@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" - dependencies: - kind-of "^3.0.2" - -is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - dependencies: - kind-of "^3.0.2" - -is-number@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - -is-object@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" - -is-plain-obj@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - -is-plain-object@^2.0.3, is-plain-object@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" - dependencies: - isobject "^3.0.1" - -is-posix-bracket@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" - -is-primitive@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" - -is-regex@^1.0.4, is-regex@^1.0.5: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.0.tgz#ece38e389e490df0dc21caea2bd596f987f767ff" - dependencies: - has-symbols "^1.0.1" - -is-regex@~1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae" - dependencies: - has "^1.0.3" - -is-retry-allowed@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" - -is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - -is-symbol@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" - dependencies: - has-symbols "^1.0.1" - -is-typed-array@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.3.tgz#a4ff5a5e672e1a55f99c7f54e59597af5c1df04d" - dependencies: - available-typed-arrays "^1.0.0" - es-abstract "^1.17.4" - foreach "^2.0.5" - has-symbols "^1.0.1" - -is-typedarray@^1.0.0, is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - -is-windows@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - -isarray@1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - -isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - dependencies: - isarray "1.0.0" - -isobject@^3.0.0, isobject@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - -isurl@^1.0.0-alpha5: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" - dependencies: - has-to-string-tag-x "^1.2.0" - is-object "^1.0.1" - -js-sha3@0.5.7, js-sha3@^0.5.7: - version "0.5.7" - resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" - -js-sha3@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" - -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - -js-tokens@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" - -js-yaml@3.13.1: - version "3.13.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -js-yaml@3.x: - version "3.14.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482" - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - -jsesc@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - -jsesc@~0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" - -json-buffer@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" - -json-rpc-engine@^3.4.0, json-rpc-engine@^3.6.0: - version "3.8.0" - resolved "https://registry.yarnpkg.com/json-rpc-engine/-/json-rpc-engine-3.8.0.tgz#9d4ff447241792e1d0a232f6ef927302bb0c62a9" - dependencies: - async "^2.0.1" - babel-preset-env "^1.7.0" - babelify "^7.3.0" - json-rpc-error "^2.0.0" - promise-to-callback "^1.0.0" - safe-event-emitter "^1.0.1" - -json-rpc-engine@^5.1.3: - version "5.1.8" - resolved "https://registry.yarnpkg.com/json-rpc-engine/-/json-rpc-engine-5.1.8.tgz#5ba0147ce571899bbaa7133ffbc05317c34a3c7f" - dependencies: - async "^2.0.1" - eth-json-rpc-errors "^2.0.1" - promise-to-callback "^1.0.0" - safe-event-emitter "^1.0.1" - -json-rpc-error@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/json-rpc-error/-/json-rpc-error-2.0.0.tgz#a7af9c202838b5e905c7250e547f1aff77258a02" - dependencies: - inherits "^2.0.1" - -json-rpc-random-id@^1.0.0, json-rpc-random-id@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-rpc-random-id/-/json-rpc-random-id-1.0.1.tgz#ba49d96aded1444dbb8da3d203748acbbcdec8c8" - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - -json-stable-stringify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" - dependencies: - jsonify "~0.0.0" - -json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - -json5@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" - -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - optionalDependencies: - graceful-fs "^4.1.6" - -jsonify@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" - -jsonschema@^1.2.4: - version "1.2.6" - resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.2.6.tgz#52b0a8e9dc06bbae7295249d03e4b9faee8a0c0b" - -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" - -keccak@^1.0.2: - version "1.4.0" - resolved "https://registry.yarnpkg.com/keccak/-/keccak-1.4.0.tgz#572f8a6dbee8e7b3aa421550f9e6408ca2186f80" - dependencies: - bindings "^1.2.1" - inherits "^2.0.3" - nan "^2.2.1" - safe-buffer "^5.1.0" - -keccak@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/keccak/-/keccak-2.1.0.tgz#734ea53f2edcfd0f42cdb8d5f4c358fef052752b" - dependencies: - bindings "^1.5.0" - inherits "^2.0.4" - nan "^2.14.0" - safe-buffer "^5.2.0" - -keccak@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.0.tgz#420d1de4a38a04f33ff8401f0535fb93756861d4" - dependencies: - node-addon-api "^2.0.0" - node-gyp-build "^4.2.0" - -keyv@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" - dependencies: - json-buffer "3.0.0" - -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - dependencies: - is-buffer "^1.1.5" - -kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - dependencies: - is-buffer "^1.1.5" - -kind-of@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" - -kind-of@^6.0.0, kind-of@^6.0.2: - version "6.0.3" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" - -lcid@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" - dependencies: - invert-kv "^2.0.0" - -level-codec@~7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/level-codec/-/level-codec-7.0.1.tgz#341f22f907ce0f16763f24bddd681e395a0fb8a7" - -level-errors@^1.0.3: - version "1.1.2" - resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-1.1.2.tgz#4399c2f3d3ab87d0625f7e3676e2d807deff404d" - dependencies: - errno "~0.1.1" - -level-errors@~1.0.3: - version "1.0.5" - resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-1.0.5.tgz#83dbfb12f0b8a2516bdc9a31c4876038e227b859" - dependencies: - errno "~0.1.1" - -level-iterator-stream@~1.3.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/level-iterator-stream/-/level-iterator-stream-1.3.1.tgz#e43b78b1a8143e6fa97a4f485eb8ea530352f2ed" - dependencies: - inherits "^2.0.1" - level-errors "^1.0.3" - readable-stream "^1.0.33" - xtend "^4.0.0" - -level-ws@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/level-ws/-/level-ws-0.0.0.tgz#372e512177924a00424b0b43aef2bb42496d228b" - dependencies: - readable-stream "~1.0.15" - xtend "~2.1.1" - -levelup@^1.2.1: - version "1.3.9" - resolved "https://registry.yarnpkg.com/levelup/-/levelup-1.3.9.tgz#2dbcae845b2bb2b6bea84df334c475533bbd82ab" - dependencies: - deferred-leveldown "~1.2.1" - level-codec "~7.0.0" - level-errors "~1.0.3" - level-iterator-stream "~1.3.0" - prr "~1.0.1" - semver "~5.4.1" - xtend "~4.0.0" - -levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - -locate-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" - dependencies: - p-locate "^3.0.0" - path-exists "^3.0.0" - -lodash.flatmap@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.flatmap/-/lodash.flatmap-4.5.0.tgz#ef8cbf408f6e48268663345305c6acc0b778702e" - -lodash.toarray@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.toarray/-/lodash.toarray-4.4.0.tgz#24c4bfcd6b2fba38bfd0594db1179d8e9b656561" - -lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4: - version "4.17.15" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" - -log-symbols@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4" - dependencies: - chalk "^2.4.2" - -loose-envify@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - -lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" - -lowercase-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" - -ltgt@~2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5" - -make-dir@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" - dependencies: - pify "^3.0.0" - -make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - -map-age-cleaner@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" - dependencies: - p-defer "^1.0.0" - -map-cache@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - -map-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - dependencies: - object-visit "^1.0.0" - -math-random@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.4.tgz#5dd6943c938548267016d4e34f057583080c514c" - -md5.js@^1.3.4: - version "1.3.5" - resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - -mem@^4.0.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" - dependencies: - map-age-cleaner "^0.1.1" - mimic-fn "^2.0.0" - p-is-promise "^2.0.0" - -memdown@^1.0.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/memdown/-/memdown-1.4.1.tgz#b4e4e192174664ffbae41361aa500f3119efe215" - dependencies: - abstract-leveldown "~2.7.1" - functional-red-black-tree "^1.0.1" - immediate "^3.2.3" - inherits "~2.0.1" - ltgt "~2.2.0" - safe-buffer "~5.1.1" - -merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - -merge2@^1.2.3, merge2@^1.3.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" - -merkle-patricia-tree@^2.1.2, merkle-patricia-tree@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/merkle-patricia-tree/-/merkle-patricia-tree-2.3.2.tgz#982ca1b5a0fde00eed2f6aeed1f9152860b8208a" - dependencies: - async "^1.4.2" - ethereumjs-util "^5.0.0" - level-ws "0.0.0" - levelup "^1.2.1" - memdown "^1.0.0" - readable-stream "^2.0.0" - rlp "^2.0.0" - semaphore ">=1.0.1" - -methods@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - -micromatch@^2.1.5: - version "2.3.11" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" - dependencies: - arr-diff "^2.0.0" - array-unique "^0.2.1" - braces "^1.8.2" - expand-brackets "^0.1.4" - extglob "^0.3.1" - filename-regex "^2.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.1" - kind-of "^3.0.2" - normalize-path "^2.0.1" - object.omit "^2.0.0" - parse-glob "^3.0.4" - regex-cache "^0.4.2" - -micromatch@^3.1.10: - version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - braces "^2.3.1" - define-property "^2.0.2" - extend-shallow "^3.0.2" - extglob "^2.0.4" - fragment-cache "^0.2.1" - kind-of "^6.0.2" - nanomatch "^1.2.9" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.2" - -micromatch@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" - dependencies: - braces "^3.0.1" - picomatch "^2.0.5" - -miller-rabin@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" - dependencies: - bn.js "^4.0.0" - brorand "^1.0.1" - -mime-db@1.44.0: - version "1.44.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" - -mime-types@^2.1.12, mime-types@^2.1.16, mime-types@~2.1.19, mime-types@~2.1.24: - version "2.1.27" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" - dependencies: - mime-db "1.44.0" - -mime@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - -mimic-fn@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - -mimic-response@^1.0.0, mimic-response@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" - -min-document@^2.19.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" - dependencies: - dom-walk "^0.1.0" - -minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" - -minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - -"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - dependencies: - brace-expansion "^1.1.7" - -minimist@^1.2.5, minimist@~1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - -minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" - dependencies: - safe-buffer "^5.1.2" - yallist "^3.0.0" - -minizlib@^1.2.1: - version "1.3.3" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" - dependencies: - minipass "^2.9.0" - -mixin-deep@^1.2.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" - dependencies: - for-in "^1.0.2" - is-extendable "^1.0.1" - -mkdirp-promise@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz#e9b8f68e552c68a9c1713b84883f7a1dd039b8a1" - dependencies: - mkdirp "*" - -mkdirp@*: - version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - -mkdirp@0.5.5, mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1: - version "0.5.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" - dependencies: - minimist "^1.2.5" - -mocha@^7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-7.2.0.tgz#01cc227b00d875ab1eed03a75106689cfed5a604" - dependencies: - ansi-colors "3.2.3" - browser-stdout "1.3.1" - chokidar "3.3.0" - debug "3.2.6" - diff "3.5.0" - escape-string-regexp "1.0.5" - find-up "3.0.0" - glob "7.1.3" - growl "1.10.5" - he "1.2.0" - js-yaml "3.13.1" - log-symbols "3.0.0" - minimatch "3.0.4" - mkdirp "0.5.5" - ms "2.1.1" - node-environment-flags "1.0.6" - object.assign "4.1.0" - strip-json-comments "2.0.1" - supports-color "6.0.0" - which "1.3.1" - wide-align "1.1.3" - yargs "13.3.2" - yargs-parser "13.1.2" - yargs-unparser "1.6.0" - -mock-fs@^4.1.0: - version "4.12.0" - resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.12.0.tgz#a5d50b12d2d75e5bec9dac3b67ffe3c41d31ade4" - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - -ms@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" - -ms@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - -multibase@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.7.0.tgz#1adfc1c50abe05eefeb5091ac0c2728d6b84581b" - dependencies: - base-x "^3.0.8" - buffer "^5.5.0" - -multibase@~0.6.0: - version "0.6.1" - resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.6.1.tgz#b76df6298536cc17b9f6a6db53ec88f85f8cc12b" - dependencies: - base-x "^3.0.8" - buffer "^5.5.0" - -multicodec@^0.5.5: - version "0.5.7" - resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-0.5.7.tgz#1fb3f9dd866a10a55d226e194abba2dcc1ee9ffd" - dependencies: - varint "^5.0.0" - -multicodec@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-1.0.1.tgz#4e2812d726b9f7c7d615d3ebc5787d36a08680f9" - dependencies: - buffer "^5.5.0" - varint "^5.0.0" - -multihashes@^0.4.15, multihashes@~0.4.15: - version "0.4.19" - resolved "https://registry.yarnpkg.com/multihashes/-/multihashes-0.4.19.tgz#d7493cf028e48747122f350908ea13d12d204813" - dependencies: - buffer "^5.5.0" - multibase "^0.7.0" - varint "^5.0.0" - -nan@^2.12.1, nan@^2.14.0, nan@^2.2.1: - version "2.14.1" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01" - -nano-json-stream-parser@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz#0cc8f6d0e2b622b479c40d499c46d64b755c6f5f" - -nanomatch@^1.2.9: - version "1.2.13" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - define-property "^2.0.2" - extend-shallow "^3.0.2" - fragment-cache "^0.2.1" - is-windows "^1.0.2" - kind-of "^6.0.2" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -negotiator@0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" - -neo-async@^2.6.0: - version "2.6.1" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" - -next-tick@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" - -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - -node-addon-api@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.1.tgz#4fd0931bf6d7e48b219ff3e6abc73cbb0252b7a3" - -node-emoji@^1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.10.0.tgz#8886abd25d9c7bb61802a658523d1f8d2a89b2da" - dependencies: - lodash.toarray "^4.4.0" - -node-environment-flags@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.6.tgz#a30ac13621f6f7d674260a54dede048c3982c088" - dependencies: - object.getownpropertydescriptors "^2.0.3" - semver "^5.7.0" - -node-fetch@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.1.2.tgz#ab884e8e7e57e38a944753cec706f788d1768bb5" - -node-fetch@~1.7.1: - version "1.7.3" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" - dependencies: - encoding "^0.1.11" - is-stream "^1.0.1" - -node-gyp-build@^4.2.0: - version "4.2.2" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.2.2.tgz#3f44b65adaafd42fb6c3d81afd630e45c847eb66" - -nopt@3.x: - version "3.0.6" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" - dependencies: - abbrev "1" - -normalize-path@^2.0.0, normalize-path@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - dependencies: - remove-trailing-separator "^1.0.1" - -normalize-path@^3.0.0, normalize-path@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - -normalize-url@^4.1.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129" - -npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - dependencies: - path-key "^2.0.0" - -number-to-bn@1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/number-to-bn/-/number-to-bn-1.7.0.tgz#bb3623592f7e5f9e0030b1977bd41a0c53fe1ea0" - dependencies: - bn.js "4.11.6" - strip-hex-prefix "1.0.0" - -oauth-sign@~0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" - -object-assign@^4, object-assign@^4.0.0, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - -object-copy@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - dependencies: - copy-descriptor "^0.1.0" - define-property "^0.2.5" - kind-of "^3.0.3" - -object-inspect@^1.7.0, object-inspect@~1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" - -object-is@^1.0.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.2.tgz#c5d2e87ff9e119f78b7a088441519e2eec1573b6" - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.5" - -object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - -object-keys@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336" - -object-visit@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - dependencies: - isobject "^3.0.0" - -object.assign@4.1.0, object.assign@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" - dependencies: - define-properties "^1.1.2" - function-bind "^1.1.1" - has-symbols "^1.0.0" - object-keys "^1.0.11" - -object.getownpropertydescriptors@^2.0.3: - version "2.1.0" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649" - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - -object.omit@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" - dependencies: - for-own "^0.1.4" - is-extendable "^0.1.1" - -object.pick@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - dependencies: - isobject "^3.0.1" - -oboe@2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/oboe/-/oboe-2.1.4.tgz#20c88cdb0c15371bb04119257d4fdd34b0aa49f6" - dependencies: - http-https "^1.0.0" - -on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - dependencies: - ee-first "1.1.1" - -once@1.x, once@^1.3.0, once@^1.3.1, once@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - dependencies: - wrappy "1" - -optionator@^0.8.1: - version "0.8.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" - dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.6" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - word-wrap "~1.2.3" - -os-homedir@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - -os-locale@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" - dependencies: - execa "^1.0.0" - lcid "^2.0.0" - mem "^4.0.0" - -os-tmpdir@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - -output-file-sync@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" - dependencies: - graceful-fs "^4.1.4" - mkdirp "^0.5.1" - object-assign "^4.1.0" - -p-cancelable@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa" - -p-cancelable@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" - -p-defer@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" - -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - -p-is-promise@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" - -p-limit@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - dependencies: - p-try "^2.0.0" - -p-locate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" - dependencies: - p-limit "^2.0.0" - -p-timeout@^1.1.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-1.2.1.tgz#5eb3b353b7fce99f101a1038880bb054ebbea386" - dependencies: - p-finally "^1.0.0" - -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - -parse-asn1@^5.0.0, parse-asn1@^5.1.5: - version "5.1.5" - resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.5.tgz#003271343da58dc94cace494faef3d2147ecea0e" - dependencies: - asn1.js "^4.0.0" - browserify-aes "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.0" - pbkdf2 "^3.0.3" - safe-buffer "^5.1.1" - -parse-code-context@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/parse-code-context/-/parse-code-context-1.0.0.tgz#718c295c593d0d19a37f898473268cc75e98de1e" - -parse-glob@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" - dependencies: - glob-base "^0.3.0" - is-dotfile "^1.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.0" - -parse-headers@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.3.tgz#5e8e7512383d140ba02f0c7aa9f49b4399c92515" - -parseurl@~1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" - -pascalcase@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - -path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - -path-key@^2.0.0, path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - -path-parse@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - -path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - -pathval@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" - -pbkdf2@^3.0.3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.0.tgz#8839d778223e922164803a411dc62fddb57d3b02" - dependencies: - create-hash "^1.1.2" - create-hmac "^1.1.4" - ripemd160 "^2.0.1" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -pbkdf2@^3.0.9: - version "3.1.1" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.1.tgz#cb8724b0fada984596856d1a6ebafd3584654b94" - dependencies: - create-hash "^1.1.2" - create-hmac "^1.1.4" - ripemd160 "^2.0.1" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -pend@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" - -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - -picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1: - version "2.2.2" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" - -pify@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - -pify@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" - -pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - dependencies: - pinkie "^2.0.0" - -pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - -posix-character-classes@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - -precond@0.2: - version "0.2.3" - resolved "https://registry.yarnpkg.com/precond/-/precond-0.2.3.tgz#aa9591bcaa24923f1e0f4849d240f47efc1075ac" - -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - -prepend-http@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" - -prepend-http@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" - -preserve@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" - -prettier-plugin-solidity@^1.0.0-alpha.52: - version "1.0.0-alpha.53" - resolved "https://registry.yarnpkg.com/prettier-plugin-solidity/-/prettier-plugin-solidity-1.0.0-alpha.53.tgz#42ef3435fb179bc41fe83f08d7b9327c88bf4a01" - dependencies: - "@solidity-parser/parser" "^0.6.1" - dir-to-object "^2.0.0" - emoji-regex "^9.0.0" - escape-string-regexp "^4.0.0" - extract-comments "^1.1.0" - prettier "^2.0.5" - semver "^7.3.2" - string-width "^4.2.0" - -prettier@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.0.5.tgz#d6d56282455243f2f92cc1716692c08aa31522d4" - -private@^0.1.6, private@^0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" - -process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" - -process@~0.5.1: - version "0.5.2" - resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" - -promise-to-callback@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/promise-to-callback/-/promise-to-callback-1.0.0.tgz#5d2a749010bfb67d963598fcd3960746a68feef7" - dependencies: - is-fn "^1.0.0" - set-immediate-shim "^1.0.1" - -proxy-addr@~2.0.5: - version "2.0.6" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" - dependencies: - forwarded "~0.1.2" - ipaddr.js "1.9.1" - -prr@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" - -psl@^1.1.28: - version "1.8.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" - -public-encrypt@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" - dependencies: - bn.js "^4.1.0" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - parse-asn1 "^5.0.0" - randombytes "^2.0.1" - safe-buffer "^5.1.2" - -pump@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -punycode@2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" - -punycode@^2.1.0, punycode@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - -qs@6.7.0: - version "6.7.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" - -qs@~6.5.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" - -query-string@^5.0.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" - dependencies: - decode-uri-component "^0.2.0" - object-assign "^4.1.0" - strict-uri-encode "^1.0.0" - -randomatic@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" - dependencies: - is-number "^4.0.0" - kind-of "^6.0.0" - math-random "^1.0.1" - -randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.0.6, randombytes@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" - dependencies: - safe-buffer "^5.1.0" - -randomfill@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" - dependencies: - randombytes "^2.0.5" - safe-buffer "^5.1.0" - -randomhex@0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/randomhex/-/randomhex-0.1.5.tgz#baceef982329091400f2a2912c6cd02f1094f585" - -range-parser@~1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" - -raw-body@2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" - dependencies: - bytes "3.1.0" - http-errors "1.7.2" - iconv-lite "0.4.24" - unpipe "1.0.0" - -readable-stream@^1.0.33: - version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.0, readable-stream@^2.3.5, readable-stream@~2.3.6: - version "2.3.7" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -readable-stream@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readable-stream@~1.0.15: - version "1.0.34" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readdirp@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" - dependencies: - graceful-fs "^4.1.11" - micromatch "^3.1.10" - readable-stream "^2.0.2" - -readdirp@~3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.2.0.tgz#c30c33352b12c96dfb4b895421a49fd5a9593839" - dependencies: - picomatch "^2.0.4" - -rechoir@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" - dependencies: - resolve "^1.1.6" - -recursive-readdir@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.2.tgz#9946fb3274e1628de6e36b2f6714953b4845094f" - dependencies: - minimatch "3.0.4" - -regenerate@^1.2.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.1.tgz#cad92ad8e6b591773485fbe05a485caf4f457e6f" - -regenerator-runtime@^0.10.5: - version "0.10.5" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" - -regenerator-runtime@^0.11.0: - version "0.11.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" - -regenerator-runtime@^0.13.4: - version "0.13.5" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697" - -regenerator-transform@^0.10.0: - version "0.10.1" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" - dependencies: - babel-runtime "^6.18.0" - babel-types "^6.19.0" - private "^0.1.6" - -regex-cache@^0.4.2: - version "0.4.4" - resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" - dependencies: - is-equal-shallow "^0.1.3" - -regex-not@^1.0.0, regex-not@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" - dependencies: - extend-shallow "^3.0.2" - safe-regex "^1.1.0" - -regexp.prototype.flags@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz#7aba89b3c13a64509dabcf3ca8d9fbb9bdf5cb75" - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - -regexpu-core@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" - dependencies: - regenerate "^1.2.1" - regjsgen "^0.2.0" - regjsparser "^0.1.4" - -regjsgen@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" - -regjsparser@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" - dependencies: - jsesc "~0.5.0" - -remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - -repeat-element@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" - -repeat-string@^1.5.2, repeat-string@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - -repeating@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" - dependencies: - is-finite "^1.0.0" - -request@^2.79.0, request@^2.85.0: - version "2.88.2" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.5.0" - tunnel-agent "^0.6.0" - uuid "^3.3.2" - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - -require-main-filename@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" - -resolve-url@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" - -resolve@1.1.x: - version "1.1.7" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" - -resolve@^1.1.6, resolve@^1.12.0, resolve@^1.8.1, resolve@~1.17.0: - version "1.17.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" - dependencies: - path-parse "^1.0.6" - -responselike@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" - dependencies: - lowercase-keys "^1.0.0" - -resumer@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/resumer/-/resumer-0.0.0.tgz#f1e8f461e4064ba39e82af3cdc2a8c893d076759" - dependencies: - through "~2.3.4" - -ret@~0.1.10: - version "0.1.15" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" - -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - -ripemd160@^2.0.0, ripemd160@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - -rlp@^2.0.0, rlp@^2.2.3, rlp@^2.2.4: - version "2.2.5" - resolved "https://registry.yarnpkg.com/rlp/-/rlp-2.2.5.tgz#b0577b763e909f21a9dea31b4b235b2393f15ef1" - dependencies: - bn.js "^4.11.1" - -run-parallel@^1.1.9: - version "1.1.9" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" - -rustbn.js@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/rustbn.js/-/rustbn.js-0.2.0.tgz#8082cb886e707155fd1cb6f23bd591ab8d55d0ca" - -safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - -safe-event-emitter@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/safe-event-emitter/-/safe-event-emitter-1.0.1.tgz#5b692ef22329ed8f69fdce607e50ca734f6f20af" - dependencies: - events "^3.0.0" - -safe-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - dependencies: - ret "~0.1.10" - -"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - -sc-istanbul@^0.4.5: - version "0.4.5" - resolved "https://registry.yarnpkg.com/sc-istanbul/-/sc-istanbul-0.4.5.tgz#1896066484d55336cf2cdbcc7884dc79da50dc76" - dependencies: - abbrev "1.0.x" - async "1.x" - escodegen "1.8.x" - esprima "2.7.x" - glob "^5.0.15" - handlebars "^4.0.1" - js-yaml "3.x" - mkdirp "0.5.x" - nopt "3.x" - once "1.x" - resolve "1.1.x" - supports-color "^3.1.0" - which "^1.1.1" - wordwrap "^1.0.0" - -scrypt-js@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-2.0.3.tgz#bb0040be03043da9a012a2cea9fc9f852cfc87d4" - -scrypt-js@2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-2.0.4.tgz#32f8c5149f0797672e551c07e230f834b6af5f16" - -"scrypt-shim@github:web3-js/scrypt-shim": - version "0.1.0" - resolved "https://codeload.github.com/web3-js/scrypt-shim/tar.gz/aafdadda13e660e25e1c525d1f5b2443f5eb1ebb" - dependencies: - scryptsy "^2.1.0" - semver "^6.3.0" - -scryptsy@2.1.0, scryptsy@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/scryptsy/-/scryptsy-2.1.0.tgz#8d1e8d0c025b58fdd25b6fa9a0dc905ee8faa790" - -scryptsy@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/scryptsy/-/scryptsy-1.2.1.tgz#a3225fa4b2524f802700761e2855bdf3b2d92163" - dependencies: - pbkdf2 "^3.0.3" - -secp256k1@^3.0.1: - version "3.8.0" - resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-3.8.0.tgz#28f59f4b01dbee9575f56a47034b7d2e3b3b352d" - dependencies: - bindings "^1.5.0" - bip66 "^1.1.5" - bn.js "^4.11.8" - create-hash "^1.2.0" - drbg.js "^1.0.1" - elliptic "^6.5.2" - nan "^2.14.0" - safe-buffer "^5.1.2" - -secp256k1@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-4.0.1.tgz#b9570ca26ace9e74c3171512bba253da9c0b6d60" - dependencies: - elliptic "^6.5.2" - node-addon-api "^2.0.0" - node-gyp-build "^4.2.0" - -seek-bzip@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-1.0.5.tgz#cfe917cb3d274bcffac792758af53173eb1fabdc" - dependencies: - commander "~2.8.1" - -semaphore@>=1.0.1, semaphore@^1.0.3: - version "1.1.0" - resolved "https://registry.yarnpkg.com/semaphore/-/semaphore-1.1.0.tgz#aaad8b86b20fe8e9b32b16dc2ee682a8cd26a8aa" - -semver@6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.2.0.tgz#4d813d9590aaf8a9192693d6c85b9344de5901db" - -semver@^5.3.0, semver@^5.5.0, semver@^5.5.1, semver@^5.7.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - -semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - -semver@^7.3.2: - version "7.3.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" - -semver@~5.4.1: - version "5.4.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" - -send@0.17.1: - version "0.17.1" - resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" - dependencies: - debug "2.6.9" - depd "~1.1.2" - destroy "~1.0.4" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "~1.7.2" - mime "1.6.0" - ms "2.1.1" - on-finished "~2.3.0" - range-parser "~1.2.1" - statuses "~1.5.0" - -serve-static@1.14.1: - version "1.14.1" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" - dependencies: - encodeurl "~1.0.2" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.17.1" - -servify@^0.1.12: - version "0.1.12" - resolved "https://registry.yarnpkg.com/servify/-/servify-0.1.12.tgz#142ab7bee1f1d033b66d0707086085b17c06db95" - dependencies: - body-parser "^1.16.0" - cors "^2.8.1" - express "^4.14.0" - request "^2.79.0" - xhr "^2.3.3" - -set-blocking@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - -set-immediate-shim@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" - -set-value@^2.0.0, set-value@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.3" - split-string "^3.0.1" - -setimmediate@1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.4.tgz#20e81de622d4a02588ce0c8da8973cbcf1d3138f" - -setimmediate@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - -setprototypeof@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" - -sha.js@^2.4.0, sha.js@^2.4.8: - version "2.4.11" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - dependencies: - shebang-regex "^1.0.0" - -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - -shelljs@^0.8.3: - version "0.8.4" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.4.tgz#de7684feeb767f8716b326078a8a00875890e3c2" - dependencies: - glob "^7.0.0" - interpret "^1.0.0" - rechoir "^0.6.2" - -signal-exit@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" - -simple-concat@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.0.tgz#7344cbb8b6e26fb27d66b2fc86f9f6d5997521c6" - -simple-get@^2.7.0: - version "2.8.1" - resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.8.1.tgz#0e22e91d4575d87620620bc91308d57a77f44b5d" - dependencies: - decompress-response "^3.3.0" - once "^1.3.1" - simple-concat "^1.0.0" - -slash@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" - -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - -snapdragon-node@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" - dependencies: - define-property "^1.0.0" - isobject "^3.0.0" - snapdragon-util "^3.0.1" - -snapdragon-util@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" - dependencies: - kind-of "^3.2.0" - -snapdragon@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" - dependencies: - base "^0.11.1" - debug "^2.2.0" - define-property "^0.2.5" - extend-shallow "^2.0.1" - map-cache "^0.2.2" - source-map "^0.5.6" - source-map-resolve "^0.5.0" - use "^3.1.0" - -solidity-coverage@^0.7.7: - version "0.7.7" - resolved "https://registry.yarnpkg.com/solidity-coverage/-/solidity-coverage-0.7.7.tgz#e6d98436d529707c64c1d6d3355590031a724777" - dependencies: - "@solidity-parser/parser" "^0.6.0" - "@truffle/provider" "^0.1.17" - chalk "^2.4.2" - death "^1.1.0" - detect-port "^1.3.0" - fs-extra "^8.1.0" - ganache-cli "6.9.0" - ghost-testrpc "^0.0.2" - global-modules "^2.0.0" - globby "^10.0.1" - jsonschema "^1.2.4" - lodash "^4.17.15" - node-emoji "^1.10.0" - pify "^4.0.1" - recursive-readdir "^2.2.2" - sc-istanbul "^0.4.5" - shelljs "^0.8.3" - web3 "1.2.6" - -source-map-resolve@^0.5.0: - version "0.5.3" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" - dependencies: - atob "^2.1.2" - decode-uri-component "^0.2.0" - resolve-url "^0.2.1" - source-map-url "^0.4.0" - urix "^0.1.0" - -source-map-support@0.5.12: - version "0.5.12" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599" - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map-support@^0.4.15: - version "0.4.18" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" - dependencies: - source-map "^0.5.6" - -source-map-support@^0.5.17, source-map-support@^0.5.19: - version "0.5.19" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map-url@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" - -source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - -source-map@^0.6.0, source-map@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - -source-map@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d" - dependencies: - amdefine ">=0.0.4" - -split-string@^3.0.1, split-string@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" - dependencies: - extend-shallow "^3.0.0" - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - -sshpk@^1.7.0: - version "1.16.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" - -static-extend@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - dependencies: - define-property "^0.2.5" - object-copy "^0.1.0" - -"statuses@>= 1.5.0 < 2", statuses@~1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - -strict-uri-encode@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" - -"string-width@^1.0.2 || 2": - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - -string-width@^3.0.0, string-width@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" - -string-width@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" - -string.prototype.trim@~1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.1.tgz#141233dff32c82bfad80684d7e5f0869ee0fb782" - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - function-bind "^1.1.1" - -string.prototype.trimend@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913" - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.5" - -string.prototype.trimleft@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz#4408aa2e5d6ddd0c9a80739b087fbc067c03b3cc" - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.5" - string.prototype.trimstart "^1.0.0" - -string.prototype.trimright@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz#c76f1cef30f21bbad8afeb8db1511496cfb0f2a3" - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.5" - string.prototype.trimend "^1.0.0" - -string.prototype.trimstart@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54" - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.5" - -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - dependencies: - safe-buffer "~5.2.0" - -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - dependencies: - safe-buffer "~5.1.0" - -strip-ansi@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - dependencies: - ansi-regex "^2.0.0" - -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - dependencies: - ansi-regex "^3.0.0" - -strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" - dependencies: - ansi-regex "^4.1.0" - -strip-ansi@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" - dependencies: - ansi-regex "^5.0.0" - -strip-dirs@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/strip-dirs/-/strip-dirs-2.1.0.tgz#4987736264fc344cf20f6c34aca9d13d1d4ed6c5" - dependencies: - is-natural-number "^4.0.1" - -strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - -strip-hex-prefix@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz#0c5f155fef1151373377de9dbb588da05500e36f" - dependencies: - is-hex-prefixed "1.0.0" - -strip-json-comments@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - -supports-color@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a" - dependencies: - has-flag "^3.0.0" - -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - -supports-color@^3.1.0: - version "3.2.3" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" - dependencies: - has-flag "^1.0.0" - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - dependencies: - has-flag "^3.0.0" - -swarm-js@0.1.39: - version "0.1.39" - resolved "https://registry.yarnpkg.com/swarm-js/-/swarm-js-0.1.39.tgz#79becb07f291d4b2a178c50fee7aa6e10342c0e8" - dependencies: - bluebird "^3.5.0" - buffer "^5.0.5" - decompress "^4.0.0" - eth-lib "^0.1.26" - fs-extra "^4.0.2" - got "^7.1.0" - mime-types "^2.1.16" - mkdirp-promise "^5.0.1" - mock-fs "^4.1.0" - setimmediate "^1.0.5" - tar "^4.0.2" - xhr-request-promise "^0.1.2" - -swarm-js@^0.1.40: - version "0.1.40" - resolved "https://registry.yarnpkg.com/swarm-js/-/swarm-js-0.1.40.tgz#b1bc7b6dcc76061f6c772203e004c11997e06b99" - dependencies: - bluebird "^3.5.0" - buffer "^5.0.5" - eth-lib "^0.1.26" - fs-extra "^4.0.2" - got "^7.1.0" - mime-types "^2.1.16" - mkdirp-promise "^5.0.1" - mock-fs "^4.1.0" - setimmediate "^1.0.5" - tar "^4.0.2" - xhr-request "^1.0.1" - -tape@^4.6.3: - version "4.13.3" - resolved "https://registry.yarnpkg.com/tape/-/tape-4.13.3.tgz#51b3d91c83668c7a45b1a594b607dee0a0b46278" - dependencies: - deep-equal "~1.1.1" - defined "~1.0.0" - dotignore "~0.1.2" - for-each "~0.3.3" - function-bind "~1.1.1" - glob "~7.1.6" - has "~1.0.3" - inherits "~2.0.4" - is-regex "~1.0.5" - minimist "~1.2.5" - object-inspect "~1.7.0" - resolve "~1.17.0" - resumer "~0.0.0" - string.prototype.trim "~1.2.1" - through "~2.3.8" - -tar-stream@^1.5.2: - version "1.6.2" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" - dependencies: - bl "^1.0.0" - buffer-alloc "^1.2.0" - end-of-stream "^1.0.0" - fs-constants "^1.0.0" - readable-stream "^2.3.0" - to-buffer "^1.1.1" - xtend "^4.0.0" - -tar@^4.0.2: - version "4.4.13" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" - dependencies: - chownr "^1.1.1" - fs-minipass "^1.2.5" - minipass "^2.8.6" - minizlib "^1.2.1" - mkdirp "^0.5.0" - safe-buffer "^5.1.2" - yallist "^3.0.3" - -through2@^2.0.3: - version "2.0.5" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" - dependencies: - readable-stream "~2.3.6" - xtend "~4.0.1" - -through@^2.3.8, through@~2.3.4, through@~2.3.8: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - -timed-out@^4.0.0, timed-out@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" - -to-buffer@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" - -to-fast-properties@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - -to-object-path@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - dependencies: - kind-of "^3.0.2" - -to-readable-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" - -to-regex-range@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - dependencies: - is-number "^3.0.0" - repeat-string "^1.6.1" - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - dependencies: - is-number "^7.0.0" - -to-regex@^3.0.1, to-regex@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" - dependencies: - define-property "^2.0.2" - extend-shallow "^3.0.2" - regex-not "^1.0.2" - safe-regex "^1.1.0" - -toidentifier@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" - -tough-cookie@~2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" - dependencies: - psl "^1.1.28" - punycode "^2.1.1" - -trim-right@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" - -truffle-hdwallet-provider@^1.0.17: - version "1.0.17" - resolved "https://registry.yarnpkg.com/truffle-hdwallet-provider/-/truffle-hdwallet-provider-1.0.17.tgz#fe8edd0d6974eeb31af9959e41525fb19abd74ca" - dependencies: - any-promise "^1.3.0" - bindings "^1.3.1" - web3 "1.2.1" - websocket "^1.0.28" - -ts-node@^8.10.2: - version "8.10.2" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.10.2.tgz#eee03764633b1234ddd37f8db9ec10b75ec7fb8d" - dependencies: - arg "^4.1.0" - diff "^4.0.1" - make-error "^1.1.1" - source-map-support "^0.5.17" - yn "3.1.1" - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - dependencies: - safe-buffer "^5.0.1" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - dependencies: - prelude-ls "~1.1.2" - -type-detect@^4.0.0, type-detect@^4.0.5: - version "4.0.8" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" - -type-is@~1.6.17, type-is@~1.6.18: - version "1.6.18" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" - dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" - -type@^1.0.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" - -type@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/type/-/type-2.0.0.tgz#5f16ff6ef2eb44f260494dae271033b29c09a9c3" - -typedarray-to-buffer@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" - dependencies: - is-typedarray "^1.0.0" - -typedarray@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - -typescript@^3.9.5: - version "3.9.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.5.tgz#586f0dba300cde8be52dd1ac4f7e1009c1b13f36" - -uglify-js@^3.1.4: - version "3.9.4" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.9.4.tgz#867402377e043c1fc7b102253a22b64e5862401b" - dependencies: - commander "~2.20.3" - -ultron@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" - -unbzip2-stream@^1.0.9: - version "1.4.3" - resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7" - dependencies: - buffer "^5.2.1" - through "^2.3.8" - -underscore@1.9.1: - version "1.9.1" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" - -union-value@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" - dependencies: - arr-union "^3.1.0" - get-value "^2.0.6" - is-extendable "^0.1.1" - set-value "^2.0.1" - -universalify@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - -unorm@^1.3.3: - version "1.6.0" - resolved "https://registry.yarnpkg.com/unorm/-/unorm-1.6.0.tgz#029b289661fba714f1a9af439eb51d9b16c205af" - -unpipe@1.0.0, unpipe@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - -unset-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - dependencies: - has-value "^0.3.1" - isobject "^3.0.0" - -uri-js@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" - dependencies: - punycode "^2.1.0" - -urix@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - -url-parse-lax@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" - dependencies: - prepend-http "^1.0.1" - -url-parse-lax@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" - dependencies: - prepend-http "^2.0.0" - -url-set-query@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/url-set-query/-/url-set-query-1.0.0.tgz#016e8cfd7c20ee05cafe7795e892bd0702faa339" - -url-to-options@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" - -use@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" - -user-home@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" - -utf8@3.0.0, utf8@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1" - -util-deprecate@^1.0.1, util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - -util@^0.12.0: - version "0.12.3" - resolved "https://registry.yarnpkg.com/util/-/util-0.12.3.tgz#971bb0292d2cc0c892dab7c6a5d37c2bec707888" - dependencies: - inherits "^2.0.3" - is-arguments "^1.0.4" - is-generator-function "^1.0.7" - is-typed-array "^1.1.3" - safe-buffer "^5.1.2" - which-typed-array "^1.1.2" - -utils-merge@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - -uuid@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.1.tgz#c2a30dedb3e535d72ccf82e343941a50ba8533ac" - -uuid@3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" - -uuid@^3.3.2: - version "3.4.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" - -v8flags@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.1.1.tgz#aab1a1fa30d45f88dd321148875ac02c0b55e5b4" - dependencies: - user-home "^1.1.1" - -varint@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/varint/-/varint-5.0.0.tgz#d826b89f7490732fabc0c0ed693ed475dcb29ebf" - -vary@^1, vary@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - -web3-bzz@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.2.1.tgz#c3bd1e8f0c02a13cd6d4e3c3e9e1713f144f6f0d" - dependencies: - got "9.6.0" - swarm-js "0.1.39" - underscore "1.9.1" - -web3-bzz@1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.2.2.tgz#a3b9f613c49fd3e120e0997088a73557d5adb724" - dependencies: - "@types/node" "^10.12.18" - got "9.6.0" - swarm-js "0.1.39" - underscore "1.9.1" - -web3-bzz@1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.2.6.tgz#0b88c0b96029eaf01b10cb47c4d5f79db4668883" - dependencies: - "@types/node" "^10.12.18" - got "9.6.0" - swarm-js "0.1.39" - underscore "1.9.1" - -web3-bzz@1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.2.8.tgz#7ff2c2de362f82ae3825e48c70ec63b3aca2b8ef" - dependencies: - "@types/node" "^10.12.18" - got "9.6.0" - swarm-js "^0.1.40" - underscore "1.9.1" - -web3-core-helpers@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.2.1.tgz#f5f32d71c60a4a3bd14786118e633ce7ca6d5d0d" - dependencies: - underscore "1.9.1" - web3-eth-iban "1.2.1" - web3-utils "1.2.1" - -web3-core-helpers@1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.2.2.tgz#484974f4bd4a487217b85b0d7cfe841af0907619" - dependencies: - underscore "1.9.1" - web3-eth-iban "1.2.2" - web3-utils "1.2.2" - -web3-core-helpers@1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.2.6.tgz#7aacd25bf8015adcdfc0f3243d0dcfdff0373f7d" - dependencies: - underscore "1.9.1" - web3-eth-iban "1.2.6" - web3-utils "1.2.6" - -web3-core-helpers@1.2.8, web3-core-helpers@^1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.2.8.tgz#86776d8f658b63bb630c84a314686661e599aa68" - dependencies: - underscore "1.9.1" - web3-eth-iban "1.2.8" - web3-utils "1.2.8" - -web3-core-method@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.2.1.tgz#9df1bafa2cd8be9d9937e01c6a47fc768d15d90a" - dependencies: - underscore "1.9.1" - web3-core-helpers "1.2.1" - web3-core-promievent "1.2.1" - web3-core-subscriptions "1.2.1" - web3-utils "1.2.1" - -web3-core-method@1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.2.2.tgz#d4fe2bb1945b7152e5f08e4ea568b171132a1e56" - dependencies: - underscore "1.9.1" - web3-core-helpers "1.2.2" - web3-core-promievent "1.2.2" - web3-core-subscriptions "1.2.2" - web3-utils "1.2.2" - -web3-core-method@1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.2.6.tgz#f5a3e4d304abaf382923c8ab88ec8eeef45c1b3b" - dependencies: - underscore "1.9.1" - web3-core-helpers "1.2.6" - web3-core-promievent "1.2.6" - web3-core-subscriptions "1.2.6" - web3-utils "1.2.6" - -web3-core-method@1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.2.8.tgz#f28a79935432aebfa019e4a50f9b6ae6c9ef4297" - dependencies: - underscore "1.9.1" - web3-core-helpers "1.2.8" - web3-core-promievent "1.2.8" - web3-core-subscriptions "1.2.8" - web3-utils "1.2.8" - -web3-core-promievent@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.2.1.tgz#003e8a3eb82fb27b6164a6d5b9cad04acf733838" - dependencies: - any-promise "1.3.0" - eventemitter3 "3.1.2" - -web3-core-promievent@1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.2.2.tgz#3b60e3f2a0c96db8a891c927899d29d39e66ab1c" - dependencies: - any-promise "1.3.0" - eventemitter3 "3.1.2" - -web3-core-promievent@1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.2.6.tgz#b1550a3a4163e48b8b704c1fe4b0084fc2dad8f5" - dependencies: - any-promise "1.3.0" - eventemitter3 "3.1.2" - -web3-core-promievent@1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.2.8.tgz#a93ca2a19cae8b60883412619e04e69e11804eb5" - dependencies: - eventemitter3 "3.1.2" - -web3-core-requestmanager@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.2.1.tgz#fa2e2206c3d738db38db7c8fe9c107006f5c6e3d" - dependencies: - underscore "1.9.1" - web3-core-helpers "1.2.1" - web3-providers-http "1.2.1" - web3-providers-ipc "1.2.1" - web3-providers-ws "1.2.1" - -web3-core-requestmanager@1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.2.2.tgz#667ba9ac724c9c76fa8965ae8a3c61f66e68d8d6" - dependencies: - underscore "1.9.1" - web3-core-helpers "1.2.2" - web3-providers-http "1.2.2" - web3-providers-ipc "1.2.2" - web3-providers-ws "1.2.2" - -web3-core-requestmanager@1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.2.6.tgz#5808c0edc0d6e2991a87b65508b3a1ab065b68ec" - dependencies: - underscore "1.9.1" - web3-core-helpers "1.2.6" - web3-providers-http "1.2.6" - web3-providers-ipc "1.2.6" - web3-providers-ws "1.2.6" - -web3-core-requestmanager@1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.2.8.tgz#da7259e72a433858d04c59b999c5116bfb797c09" - dependencies: - underscore "1.9.1" - web3-core-helpers "1.2.8" - web3-providers-http "1.2.8" - web3-providers-ipc "1.2.8" - web3-providers-ws "1.2.8" - -web3-core-subscriptions@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.2.1.tgz#8c2368a839d4eec1c01a4b5650bbeb82d0e4a099" - dependencies: - eventemitter3 "3.1.2" - underscore "1.9.1" - web3-core-helpers "1.2.1" - -web3-core-subscriptions@1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.2.2.tgz#bf4ba23a653a003bdc3551649958cc0b080b068e" - dependencies: - eventemitter3 "3.1.2" - underscore "1.9.1" - web3-core-helpers "1.2.2" - -web3-core-subscriptions@1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.2.6.tgz#9d44189e2321f8f1abc31f6c09103b5283461b57" - dependencies: - eventemitter3 "3.1.2" - underscore "1.9.1" - web3-core-helpers "1.2.6" - -web3-core-subscriptions@1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.2.8.tgz#50945498fb0bd655f842cbcc13873d96956aa93e" - dependencies: - eventemitter3 "3.1.2" - underscore "1.9.1" - web3-core-helpers "1.2.8" - -web3-core@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.2.1.tgz#7278b58fb6495065e73a77efbbce781a7fddf1a9" - dependencies: - web3-core-helpers "1.2.1" - web3-core-method "1.2.1" - web3-core-requestmanager "1.2.1" - web3-utils "1.2.1" - -web3-core@1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.2.2.tgz#334b99c8222ef9cfd0339e27352f0b58ea789a2f" - dependencies: - "@types/bn.js" "^4.11.4" - "@types/node" "^12.6.1" - web3-core-helpers "1.2.2" - web3-core-method "1.2.2" - web3-core-requestmanager "1.2.2" - web3-utils "1.2.2" - -web3-core@1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.2.6.tgz#bb42a1d7ae49a7258460f0d95ddb00906f59ef92" - dependencies: - "@types/bn.js" "^4.11.4" - "@types/node" "^12.6.1" - web3-core-helpers "1.2.6" - web3-core-method "1.2.6" - web3-core-requestmanager "1.2.6" - web3-utils "1.2.6" - -web3-core@1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.2.8.tgz#2a488bb11519b71e7738265329bddc00fc200dd3" - dependencies: - "@types/bn.js" "^4.11.4" - "@types/node" "^12.6.1" - bignumber.js "^9.0.0" - web3-core-helpers "1.2.8" - web3-core-method "1.2.8" - web3-core-requestmanager "1.2.8" - web3-utils "1.2.8" - -web3-eth-abi@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.2.1.tgz#9b915b1c9ebf82f70cca631147035d5419064689" - dependencies: - ethers "4.0.0-beta.3" - underscore "1.9.1" - web3-utils "1.2.1" - -web3-eth-abi@1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.2.2.tgz#d5616d88a90020f894763423a9769f2da11fe37a" - dependencies: - ethers "4.0.0-beta.3" - underscore "1.9.1" - web3-utils "1.2.2" - -web3-eth-abi@1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.2.6.tgz#b495383cc5c0d8e2857b26e7fe25606685983b25" - dependencies: - ethers "4.0.0-beta.3" - underscore "1.9.1" - web3-utils "1.2.6" - -web3-eth-abi@1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.2.8.tgz#7537138f3e5cd1ccf98233fa07f388aa8dc1fff1" - dependencies: - "@ethersproject/abi" "5.0.0-beta.153" - underscore "1.9.1" - web3-utils "1.2.8" - -web3-eth-accounts@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.2.1.tgz#2741a8ef337a7219d57959ac8bd118b9d68d63cf" - dependencies: - any-promise "1.3.0" - crypto-browserify "3.12.0" - eth-lib "0.2.7" - scryptsy "2.1.0" - semver "6.2.0" - underscore "1.9.1" - uuid "3.3.2" - web3-core "1.2.1" - web3-core-helpers "1.2.1" - web3-core-method "1.2.1" - web3-utils "1.2.1" - -web3-eth-accounts@1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.2.2.tgz#c187e14bff6baa698ac352220290222dbfd332e5" - dependencies: - any-promise "1.3.0" - crypto-browserify "3.12.0" - eth-lib "0.2.7" - ethereumjs-common "^1.3.2" - ethereumjs-tx "^2.1.1" - scrypt-shim "github:web3-js/scrypt-shim" - underscore "1.9.1" - uuid "3.3.2" - web3-core "1.2.2" - web3-core-helpers "1.2.2" - web3-core-method "1.2.2" - web3-utils "1.2.2" - -web3-eth-accounts@1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.2.6.tgz#a1ba4bf75fa8102a3ec6cddd0eccd72462262720" - dependencies: - "@web3-js/scrypt-shim" "^0.1.0" - any-promise "1.3.0" - crypto-browserify "3.12.0" - eth-lib "^0.2.8" - ethereumjs-common "^1.3.2" - ethereumjs-tx "^2.1.1" - underscore "1.9.1" - uuid "3.3.2" - web3-core "1.2.6" - web3-core-helpers "1.2.6" - web3-core-method "1.2.6" - web3-utils "1.2.6" - -web3-eth-accounts@1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.2.8.tgz#e63afc6d4902f2beb0cf60e6b755c86fa5b5ccd7" - dependencies: - "@web3-js/scrypt-shim" "^0.1.0" - crypto-browserify "3.12.0" - eth-lib "^0.2.8" - ethereumjs-common "^1.3.2" - ethereumjs-tx "^2.1.1" - underscore "1.9.1" - uuid "3.3.2" - web3-core "1.2.8" - web3-core-helpers "1.2.8" - web3-core-method "1.2.8" - web3-utils "1.2.8" - -web3-eth-contract@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.2.1.tgz#3542424f3d341386fd9ff65e78060b85ac0ea8c4" - dependencies: - underscore "1.9.1" - web3-core "1.2.1" - web3-core-helpers "1.2.1" - web3-core-method "1.2.1" - web3-core-promievent "1.2.1" - web3-core-subscriptions "1.2.1" - web3-eth-abi "1.2.1" - web3-utils "1.2.1" - -web3-eth-contract@1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.2.2.tgz#84e92714918a29e1028ee7718f0712536e14e9a1" - dependencies: - "@types/bn.js" "^4.11.4" - underscore "1.9.1" - web3-core "1.2.2" - web3-core-helpers "1.2.2" - web3-core-method "1.2.2" - web3-core-promievent "1.2.2" - web3-core-subscriptions "1.2.2" - web3-eth-abi "1.2.2" - web3-utils "1.2.2" - -web3-eth-contract@1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.2.6.tgz#39111543960035ed94c597a239cf5aa1da796741" - dependencies: - "@types/bn.js" "^4.11.4" - underscore "1.9.1" - web3-core "1.2.6" - web3-core-helpers "1.2.6" - web3-core-method "1.2.6" - web3-core-promievent "1.2.6" - web3-core-subscriptions "1.2.6" - web3-eth-abi "1.2.6" - web3-utils "1.2.6" - -web3-eth-contract@1.2.8, web3-eth-contract@^1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.2.8.tgz#ff75920ac698a70781edcebbf75287a6d0f14499" - dependencies: - "@types/bn.js" "^4.11.4" - underscore "1.9.1" - web3-core "1.2.8" - web3-core-helpers "1.2.8" - web3-core-method "1.2.8" - web3-core-promievent "1.2.8" - web3-core-subscriptions "1.2.8" - web3-eth-abi "1.2.8" - web3-utils "1.2.8" - -web3-eth-ens@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.2.1.tgz#a0e52eee68c42a8b9865ceb04e5fb022c2d971d5" - dependencies: - eth-ens-namehash "2.0.8" - underscore "1.9.1" - web3-core "1.2.1" - web3-core-helpers "1.2.1" - web3-core-promievent "1.2.1" - web3-eth-abi "1.2.1" - web3-eth-contract "1.2.1" - web3-utils "1.2.1" - -web3-eth-ens@1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.2.2.tgz#0a4abed1d4cbdacbf5e1ab06e502d806d1192bc6" - dependencies: - eth-ens-namehash "2.0.8" - underscore "1.9.1" - web3-core "1.2.2" - web3-core-helpers "1.2.2" - web3-core-promievent "1.2.2" - web3-eth-abi "1.2.2" - web3-eth-contract "1.2.2" - web3-utils "1.2.2" - -web3-eth-ens@1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.2.6.tgz#bf86a624c4c72bc59913c2345180d3ea947e110d" - dependencies: - eth-ens-namehash "2.0.8" - underscore "1.9.1" - web3-core "1.2.6" - web3-core-helpers "1.2.6" - web3-core-promievent "1.2.6" - web3-eth-abi "1.2.6" - web3-eth-contract "1.2.6" - web3-utils "1.2.6" - -web3-eth-ens@1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.2.8.tgz#247daddfdbf7533adb0f45cd2f75c75e52f7e678" - dependencies: - content-hash "^2.5.2" - eth-ens-namehash "2.0.8" - underscore "1.9.1" - web3-core "1.2.8" - web3-core-helpers "1.2.8" - web3-core-promievent "1.2.8" - web3-eth-abi "1.2.8" - web3-eth-contract "1.2.8" - web3-utils "1.2.8" - -web3-eth-iban@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.2.1.tgz#2c3801718946bea24e9296993a975c80b5acf880" - dependencies: - bn.js "4.11.8" - web3-utils "1.2.1" - -web3-eth-iban@1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.2.2.tgz#76bec73bad214df7c4192388979a59fc98b96c5a" - dependencies: - bn.js "4.11.8" - web3-utils "1.2.2" - -web3-eth-iban@1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.2.6.tgz#0b22191fd1aa6e27f7ef0820df75820bfb4ed46b" - dependencies: - bn.js "4.11.8" - web3-utils "1.2.6" - -web3-eth-iban@1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.2.8.tgz#414e80a7fb2d1ea16490bc2c8fc29a996aec5612" - dependencies: - bn.js "4.11.8" - web3-utils "1.2.8" - -web3-eth-personal@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.2.1.tgz#244e9911b7b482dc17c02f23a061a627c6e47faf" - dependencies: - web3-core "1.2.1" - web3-core-helpers "1.2.1" - web3-core-method "1.2.1" - web3-net "1.2.1" - web3-utils "1.2.1" - -web3-eth-personal@1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.2.2.tgz#eee1c86a8132fa16b5e34c6d421ca92e684f0be6" - dependencies: - "@types/node" "^12.6.1" - web3-core "1.2.2" - web3-core-helpers "1.2.2" - web3-core-method "1.2.2" - web3-net "1.2.2" - web3-utils "1.2.2" - -web3-eth-personal@1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.2.6.tgz#47a0a0657ec04dd77f95451a6869d4751d324b6b" - dependencies: - "@types/node" "^12.6.1" - web3-core "1.2.6" - web3-core-helpers "1.2.6" - web3-core-method "1.2.6" - web3-net "1.2.6" - web3-utils "1.2.6" - -web3-eth-personal@1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.2.8.tgz#8ebb27210b4c9c9555a30c5bb2ce8db12f84cd24" - dependencies: - "@types/node" "^12.6.1" - web3-core "1.2.8" - web3-core-helpers "1.2.8" - web3-core-method "1.2.8" - web3-net "1.2.8" - web3-utils "1.2.8" - -web3-eth@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.2.1.tgz#b9989e2557c73a9e8ffdc107c6dafbe72c79c1b0" - dependencies: - underscore "1.9.1" - web3-core "1.2.1" - web3-core-helpers "1.2.1" - web3-core-method "1.2.1" - web3-core-subscriptions "1.2.1" - web3-eth-abi "1.2.1" - web3-eth-accounts "1.2.1" - web3-eth-contract "1.2.1" - web3-eth-ens "1.2.1" - web3-eth-iban "1.2.1" - web3-eth-personal "1.2.1" - web3-net "1.2.1" - web3-utils "1.2.1" - -web3-eth@1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.2.2.tgz#65a1564634a23b990efd1655bf94ad513904286c" - dependencies: - underscore "1.9.1" - web3-core "1.2.2" - web3-core-helpers "1.2.2" - web3-core-method "1.2.2" - web3-core-subscriptions "1.2.2" - web3-eth-abi "1.2.2" - web3-eth-accounts "1.2.2" - web3-eth-contract "1.2.2" - web3-eth-ens "1.2.2" - web3-eth-iban "1.2.2" - web3-eth-personal "1.2.2" - web3-net "1.2.2" - web3-utils "1.2.2" - -web3-eth@1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.2.6.tgz#15a8c65fdde0727872848cae506758d302d8d046" - dependencies: - underscore "1.9.1" - web3-core "1.2.6" - web3-core-helpers "1.2.6" - web3-core-method "1.2.6" - web3-core-subscriptions "1.2.6" - web3-eth-abi "1.2.6" - web3-eth-accounts "1.2.6" - web3-eth-contract "1.2.6" - web3-eth-ens "1.2.6" - web3-eth-iban "1.2.6" - web3-eth-personal "1.2.6" - web3-net "1.2.6" - web3-utils "1.2.6" - -web3-eth@1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.2.8.tgz#cf6a16fae4d7c12b90cfb6ef570cb1a2acc34c1b" - dependencies: - underscore "1.9.1" - web3-core "1.2.8" - web3-core-helpers "1.2.8" - web3-core-method "1.2.8" - web3-core-subscriptions "1.2.8" - web3-eth-abi "1.2.8" - web3-eth-accounts "1.2.8" - web3-eth-contract "1.2.8" - web3-eth-ens "1.2.8" - web3-eth-iban "1.2.8" - web3-eth-personal "1.2.8" - web3-net "1.2.8" - web3-utils "1.2.8" - -web3-net@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.2.1.tgz#edd249503315dd5ab4fa00220f6509d95bb7ab10" - dependencies: - web3-core "1.2.1" - web3-core-method "1.2.1" - web3-utils "1.2.1" - -web3-net@1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.2.2.tgz#5c3226ca72df7c591422440ce6f1203fd42ddad9" - dependencies: - web3-core "1.2.2" - web3-core-method "1.2.2" - web3-utils "1.2.2" - -web3-net@1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.2.6.tgz#035ca0fbe55282fda848ca17ebb4c8966147e5ea" - dependencies: - web3-core "1.2.6" - web3-core-method "1.2.6" - web3-utils "1.2.6" - -web3-net@1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.2.8.tgz#582fc2d4ba32c2e5c7761624e4be7c5434142d66" - dependencies: - web3-core "1.2.8" - web3-core-method "1.2.8" - web3-utils "1.2.8" - -web3-providers-http@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.2.1.tgz#c93ea003a42e7b894556f7e19dd3540f947f5013" - dependencies: - web3-core-helpers "1.2.1" - xhr2-cookies "1.1.0" - -web3-providers-http@1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.2.2.tgz#155e55c1d69f4c5cc0b411ede40dea3d06720956" - dependencies: - web3-core-helpers "1.2.2" - xhr2-cookies "1.1.0" - -web3-providers-http@1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.2.6.tgz#3c7b1252751fb37e53b873fce9dbb6340f5e31d9" - dependencies: - web3-core-helpers "1.2.6" - xhr2-cookies "1.1.0" - -web3-providers-http@1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.2.8.tgz#cd7fc4d49df6980b5dd0fb1b5a808bc4b6a0069d" - dependencies: - web3-core-helpers "1.2.8" - xhr2-cookies "1.1.0" - -web3-providers-ipc@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.2.1.tgz#017bfc687a8fc5398df2241eb98f135e3edd672c" - dependencies: - oboe "2.1.4" - underscore "1.9.1" - web3-core-helpers "1.2.1" - -web3-providers-ipc@1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.2.2.tgz#c6d165a12bc68674b4cdd543ea18aec79cafc2e8" - dependencies: - oboe "2.1.4" - underscore "1.9.1" - web3-core-helpers "1.2.2" - -web3-providers-ipc@1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.2.6.tgz#adabab5ac66b3ff8a26c7dc97af3f1a6a7609701" - dependencies: - oboe "2.1.4" - underscore "1.9.1" - web3-core-helpers "1.2.6" - -web3-providers-ipc@1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.2.8.tgz#47be918ddd077999aa14703169b76c807f45d894" - dependencies: - oboe "2.1.4" - underscore "1.9.1" - web3-core-helpers "1.2.8" - -web3-providers-ws@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.2.1.tgz#2d941eaf3d5a8caa3214eff8dc16d96252b842cb" - dependencies: - underscore "1.9.1" - web3-core-helpers "1.2.1" - websocket "github:web3-js/WebSocket-Node#polyfill/globalThis" - -web3-providers-ws@1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.2.2.tgz#d2c05c68598cea5ad3fa6ef076c3bcb3ca300d29" - dependencies: - underscore "1.9.1" - web3-core-helpers "1.2.2" - websocket "github:web3-js/WebSocket-Node#polyfill/globalThis" - -web3-providers-ws@1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.2.6.tgz#3cecc49f7c99f07a75076d3c54247050bc4f7e11" - dependencies: - "@web3-js/websocket" "^1.0.29" - underscore "1.9.1" - web3-core-helpers "1.2.6" - -web3-providers-ws@1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.2.8.tgz#9e6454edc82d753d398c8d1e044632c234434a46" - dependencies: - "@web3-js/websocket" "^1.0.29" - eventemitter3 "^4.0.0" - underscore "1.9.1" - web3-core-helpers "1.2.8" - -web3-shh@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.2.1.tgz#4460e3c1e07faf73ddec24ccd00da46f89152b0c" - dependencies: - web3-core "1.2.1" - web3-core-method "1.2.1" - web3-core-subscriptions "1.2.1" - web3-net "1.2.1" - -web3-shh@1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.2.2.tgz#44ed998f2a6ba0ec5cb9d455184a0f647826a49c" - dependencies: - web3-core "1.2.2" - web3-core-method "1.2.2" - web3-core-subscriptions "1.2.2" - web3-net "1.2.2" - -web3-shh@1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.2.6.tgz#2492616da4cac32d4c7534b890f43bac63190c14" - dependencies: - web3-core "1.2.6" - web3-core-method "1.2.6" - web3-core-subscriptions "1.2.6" - web3-net "1.2.6" - -web3-shh@1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.2.8.tgz#5162d9d13bc6838d390df1cd39e5f87235c1c2ae" - dependencies: - web3-core "1.2.8" - web3-core-method "1.2.8" - web3-core-subscriptions "1.2.8" - web3-net "1.2.8" - -web3-utils@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.2.1.tgz#21466e38291551de0ab34558de21512ac4274534" - dependencies: - bn.js "4.11.8" - eth-lib "0.2.7" - ethjs-unit "0.1.6" - number-to-bn "1.7.0" - randomhex "0.1.5" - underscore "1.9.1" - utf8 "3.0.0" - -web3-utils@1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.2.2.tgz#b53a08c40d2c3f31d3c4a28e7d749405df99c8c0" - dependencies: - bn.js "4.11.8" - eth-lib "0.2.7" - ethereum-bloom-filters "^1.0.6" - ethjs-unit "0.1.6" - number-to-bn "1.7.0" - randombytes "^2.1.0" - underscore "1.9.1" - utf8 "3.0.0" - -web3-utils@1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.2.6.tgz#b9a25432da00976457fcc1094c4af8ac6d486db9" - dependencies: - bn.js "4.11.8" - eth-lib "0.2.7" - ethereum-bloom-filters "^1.0.6" - ethjs-unit "0.1.6" - number-to-bn "1.7.0" - randombytes "^2.1.0" - underscore "1.9.1" - utf8 "3.0.0" - -web3-utils@1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.2.8.tgz#5321d91715cd4c0869005705a33c4c042a532b18" - dependencies: - bn.js "4.11.8" - eth-lib "0.2.7" - ethereum-bloom-filters "^1.0.6" - ethjs-unit "0.1.6" - number-to-bn "1.7.0" - randombytes "^2.1.0" - underscore "1.9.1" - utf8 "3.0.0" - -web3@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/web3/-/web3-1.2.1.tgz#5d8158bcca47838ab8c2b784a2dee4c3ceb4179b" - dependencies: - web3-bzz "1.2.1" - web3-core "1.2.1" - web3-eth "1.2.1" - web3-eth-personal "1.2.1" - web3-net "1.2.1" - web3-shh "1.2.1" - web3-utils "1.2.1" - -web3@1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/web3/-/web3-1.2.2.tgz#b1b8b69aafdf94cbaeadbb68a8aa1df2ef266aec" - dependencies: - "@types/node" "^12.6.1" - web3-bzz "1.2.2" - web3-core "1.2.2" - web3-eth "1.2.2" - web3-eth-personal "1.2.2" - web3-net "1.2.2" - web3-shh "1.2.2" - web3-utils "1.2.2" - -web3@1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/web3/-/web3-1.2.6.tgz#c497dcb14cdd8d6d9fb6b445b3b68ff83f8ccf68" - dependencies: - "@types/node" "^12.6.1" - web3-bzz "1.2.6" - web3-core "1.2.6" - web3-eth "1.2.6" - web3-eth-personal "1.2.6" - web3-net "1.2.6" - web3-shh "1.2.6" - web3-utils "1.2.6" - -web3@^1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/web3/-/web3-1.2.8.tgz#20b24baa769e0224a708ef5bf196a5b83d19540b" - dependencies: - web3-bzz "1.2.8" - web3-core "1.2.8" - web3-eth "1.2.8" - web3-eth-personal "1.2.8" - web3-net "1.2.8" - web3-shh "1.2.8" - web3-utils "1.2.8" - -websocket@^1.0.28: - version "1.0.31" - resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.31.tgz#e5d0f16c3340ed87670e489ecae6144c79358730" - dependencies: - debug "^2.2.0" - es5-ext "^0.10.50" - nan "^2.14.0" - typedarray-to-buffer "^3.1.5" - yaeti "^0.0.6" - -"websocket@github:web3-js/WebSocket-Node#polyfill/globalThis": - version "1.0.29" - resolved "https://codeload.github.com/web3-js/WebSocket-Node/tar.gz/ef5ea2f41daf4a2113b80c9223df884b4d56c400" - dependencies: - debug "^2.2.0" - es5-ext "^0.10.50" - nan "^2.14.0" - typedarray-to-buffer "^3.1.5" - yaeti "^0.0.6" - -whatwg-fetch@2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f" - -which-module@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - -which-typed-array@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.2.tgz#e5f98e56bda93e3dac196b01d47c1156679c00b2" - dependencies: - available-typed-arrays "^1.0.2" - es-abstract "^1.17.5" - foreach "^2.0.5" - function-bind "^1.1.1" - has-symbols "^1.0.1" - is-typed-array "^1.1.3" - -which@1.3.1, which@^1.1.1, which@^1.2.9, which@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - dependencies: - isexe "^2.0.0" - -wide-align@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" - dependencies: - string-width "^1.0.2 || 2" - -word-wrap@~1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - -wordwrap@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - -wrap-ansi@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" - dependencies: - ansi-styles "^3.2.0" - string-width "^3.0.0" - strip-ansi "^5.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - -ws@^3.0.0: - version "3.3.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" - dependencies: - async-limiter "~1.0.0" - safe-buffer "~5.1.0" - ultron "~1.1.0" - -ws@^5.1.1: - version "5.2.2" - resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f" - dependencies: - async-limiter "~1.0.0" - -xhr-request-promise@^0.1.2: - version "0.1.3" - resolved "https://registry.yarnpkg.com/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz#2d5f4b16d8c6c893be97f1a62b0ed4cf3ca5f96c" - dependencies: - xhr-request "^1.1.0" - -xhr-request@^1.0.1, xhr-request@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/xhr-request/-/xhr-request-1.1.0.tgz#f4a7c1868b9f198723444d82dcae317643f2e2ed" - dependencies: - buffer-to-arraybuffer "^0.0.5" - object-assign "^4.1.1" - query-string "^5.0.1" - simple-get "^2.7.0" - timed-out "^4.0.1" - url-set-query "^1.0.0" - xhr "^2.0.4" - -xhr2-cookies@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz#7d77449d0999197f155cb73b23df72505ed89d48" - dependencies: - cookiejar "^2.1.1" - -xhr@^2.0.4, xhr@^2.2.0, xhr@^2.3.3: - version "2.5.0" - resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.5.0.tgz#bed8d1676d5ca36108667692b74b316c496e49dd" - dependencies: - global "~4.3.0" - is-function "^1.0.1" - parse-headers "^2.0.0" - xtend "^4.0.0" - -xmlhttprequest@1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc" - -xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.0, xtend@~4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - -xtend@~2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.1.2.tgz#6efecc2a4dad8e6962c4901b337ce7ba87b5d28b" - dependencies: - object-keys "~0.4.0" - -y18n@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" - -yaeti@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577" - -yallist@^3.0.0, yallist@^3.0.3: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - -yargs-parser@13.1.2, yargs-parser@^13.1.0, yargs-parser@^13.1.2: - version "13.1.2" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - -yargs-unparser@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f" - dependencies: - flat "^4.1.0" - lodash "^4.17.15" - yargs "^13.3.0" - -yargs@13.2.4: - version "13.2.4" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.4.tgz#0b562b794016eb9651b98bd37acf364aa5d6dc83" - dependencies: - cliui "^5.0.0" - find-up "^3.0.0" - get-caller-file "^2.0.1" - os-locale "^3.1.0" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^3.0.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^13.1.0" - -yargs@13.3.2, yargs@^13.3.0: - version "13.3.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" - dependencies: - cliui "^5.0.0" - find-up "^3.0.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^3.0.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^13.1.2" - -yauzl@^2.4.2: - version "2.10.0" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" - dependencies: - buffer-crc32 "~0.2.3" - fd-slicer "~1.1.0" - -yn@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" From aadf5eb8446710011048df5638b159b2feddaf3d Mon Sep 17 00:00:00 2001 From: owen05 Date: Tue, 10 Nov 2020 18:37:51 +0800 Subject: [PATCH 107/118] route testing --- contracts/SmartRoute/SmartApprove.sol | 7 +- contracts/SmartRoute/SmartSwap.sol | 49 ++- package-lock.json | 33 +- package.json | 2 +- route-test.sh | 2 + test/Route/Route.test.ts | 362 +++++++++++------ .../utils-v1/{Context.ts => Context-route.ts} | 177 ++++++--- test/utils-v1/Converter.ts | 6 + test/utils-v1/dodoHelper.ts | 366 ++++++++++++++++++ 9 files changed, 802 insertions(+), 202 deletions(-) create mode 100644 route-test.sh rename test/utils-v1/{Context.ts => Context-route.ts} (51%) create mode 100644 test/utils-v1/dodoHelper.ts diff --git a/contracts/SmartRoute/SmartApprove.sol b/contracts/SmartRoute/SmartApprove.sol index 3b6ccd3..0fcc38b 100644 --- a/contracts/SmartRoute/SmartApprove.sol +++ b/contracts/SmartRoute/SmartApprove.sol @@ -11,7 +11,6 @@ import {IERC20} from "../intf/IERC20.sol"; import {SafeERC20} from "../lib/SafeERC20.sol"; import {Ownable} from "../lib/Ownable.sol"; - contract SmartApprove is Ownable { using SafeERC20 for IERC20; address public smartSwap; @@ -20,9 +19,6 @@ contract SmartApprove is Ownable { smartSwap = _smartSwap; } - - event Test1(uint256 amount); - function claimTokens( IERC20 token, address who, @@ -30,7 +26,6 @@ contract SmartApprove is Ownable { uint256 amount ) external { require(msg.sender == smartSwap, "Not SmartSwap Address, Access restricted"); - emit Test1(amount); - // token.safeTransferFrom(who, dest, amount); + token.safeTransferFrom(who, dest, amount); } } diff --git a/contracts/SmartRoute/SmartSwap.sol b/contracts/SmartRoute/SmartSwap.sol index 0856450..aba2dde 100644 --- a/contracts/SmartRoute/SmartSwap.sol +++ b/contracts/SmartRoute/SmartSwap.sol @@ -30,7 +30,7 @@ contract SmartSwap is Ownable { IERC20 indexed toToken, address indexed sender, uint256 fromAmount, - uint256 toAmount + uint256 returnAmount ); event ExternalRecord(address indexed to, address indexed sender); @@ -39,7 +39,6 @@ contract SmartSwap is Ownable { smartApprove = ISmartApprove(_smartApprove); } - function dodoSwap( IERC20 fromToken, IERC20 toToken, @@ -50,37 +49,35 @@ contract SmartSwap is Ownable { uint256[] memory starts, uint256[] memory gasLimitsAndValues ) public payable returns (uint256 returnAmount) { - require(minReturnAmount > 0, "haha hihi Min return should be bigger then 0."); + require(minReturnAmount > 0, "Min return should be bigger then 0."); require(callPairs.length > 0, "pairs should exists."); - // if (fromToken != ETH_ADDRESS) { - // // smartApprove.claimTokens(fromToken, msg.sender, address(this), fromTokenAmount); - // } + if (fromToken != ETH_ADDRESS) { + smartApprove.claimTokens(fromToken, msg.sender, address(this), fromTokenAmount); + } - // for (uint256 i = 0; i < callPairs.length; i++) { - // require(callPairs[i] != address(smartApprove), "Access denied"); - // require( - // callPairs[i].externalCall( - // gasLimitsAndValues[i] & ((1 << 128) - 1), - // callDataConcat, - // starts[i], - // starts[i + 1] - starts[i], - // gasLimitsAndValues[i] >> 128 - // ) - // ); - // } + for (uint256 i = 0; i < callPairs.length; i++) { + require(callPairs[i] != address(smartApprove), "Access denied"); + require( + callPairs[i].externalCall( + gasLimitsAndValues[i] & ((1 << 128) - 1), + callDataConcat, + starts[i], + starts[i + 1] - starts[i], + gasLimitsAndValues[i] >> 128 + ),"Swap Transaction Error!" + ); + } - // // Return back all unswapped - // fromToken.universalTransfer(msg.sender, fromToken.universalBalanceOf(address(this))); + fromToken.universalTransfer(msg.sender, fromToken.universalBalanceOf(address(this))); + returnAmount = toToken.universalBalanceOf(address(this)); - // returnAmount = toToken.universalBalanceOf(address(this)); - - // require(returnAmount >= minReturnAmount, "Return amount is not enough"); - // toToken.universalTransfer(msg.sender, returnAmount); - emit Swapped(fromToken, toToken, msg.sender, fromTokenAmount, fromTokenAmount); - // emit Swapped(fromToken, toToken, msg.sender, fromTokenAmount, returnAmount); + require(returnAmount >= minReturnAmount, "Return amount is not enough"); + toToken.universalTransfer(msg.sender, returnAmount); + emit Swapped(fromToken, toToken, msg.sender, fromTokenAmount, returnAmount); } + //TODO:change function externalSwap( IERC20 fromToken, IERC20 toToken, diff --git a/package-lock.json b/package-lock.json index e1bfe80..af6f651 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1526,7 +1526,8 @@ "assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==" + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true }, "assign-symbols": { "version": "1.0.0", @@ -2255,6 +2256,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "dev": true, "requires": { "assertion-error": "^1.1.0", "check-error": "^1.0.2", @@ -2284,7 +2286,8 @@ "check-error": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=" + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true }, "checkpoint-store": { "version": "1.1.0", @@ -2787,6 +2790,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, "requires": { "type-detect": "^4.0.0" } @@ -4998,7 +5002,8 @@ "get-func-name": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=" + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true }, "get-intrinsic": { "version": "1.0.1", @@ -6116,6 +6121,12 @@ "integrity": "sha1-74y/QI9uSCaGYzRTBcaswLd4cC4=", "dev": true }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=", + "dev": true + }, "lodash.toarray": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", @@ -7156,7 +7167,8 @@ "pathval": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", - "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=" + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "dev": true }, "pbkdf2": { "version": "3.1.1", @@ -8904,6 +8916,16 @@ "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" }, + "truffle-assertions": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/truffle-assertions/-/truffle-assertions-0.9.2.tgz", + "integrity": "sha512-9g2RhaxU2F8DeWhqoGQvL/bV8QVoSnQ6PY+ZPvYRP5eF7+/8LExb4mjLx/FeliLTjc3Tv1SABG05Gu5qQ/ErmA==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "lodash.isequal": "^4.5.0" + } + }, "truffle-hdwallet-provider": { "version": "1.0.17", "resolved": "https://registry.npmjs.org/truffle-hdwallet-provider/-/truffle-hdwallet-provider-1.0.17.tgz", @@ -8994,7 +9016,8 @@ "type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true }, "type-is": { "version": "1.6.18", diff --git a/package.json b/package.json index 4c759df..de2e88b 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,6 @@ "babel-cli": "^6.26.0", "babel-eslint": "^10.1.0", "bignumber.js": "^9.0.0", - "chai": "^4.2.0", "chai-bignumber": "^3.0.0", "debug": "^4.1.1", "dotenv-flow": "^3.1.0", @@ -50,6 +49,7 @@ }, "devDependencies": { "@truffle/hdwallet-provider": "^1.0.36", + "chai": "^4.2.0", "ganache-cli": "^6.9.1", "prettier": "^2.0.5", "prettier-plugin-solidity": "^1.0.0-alpha.52", diff --git a/route-test.sh b/route-test.sh new file mode 100644 index 0000000..89655ff --- /dev/null +++ b/route-test.sh @@ -0,0 +1,2 @@ +truffle compile --all +truffle test ./test/Route/Route.test.ts \ No newline at end of file diff --git a/test/Route/Route.test.ts b/test/Route/Route.test.ts index 79f8a23..e4d6e99 100644 --- a/test/Route/Route.test.ts +++ b/test/Route/Route.test.ts @@ -5,86 +5,145 @@ */ -// import * as assert from 'assert'; - +import * as assert from 'assert'; import BigNumber from 'bignumber.js'; -import { DODOContext, getDODOContext } from '../utils-v1/Context'; -import { decimalStr,MAX_UINT256 } from '../utils-v1/Converter'; +import { DODOContext, getDODOContext } from '../utils-v1/Context-route'; +import { decimalStr,MAX_UINT256,fromWei,mweiStr} from '../utils-v1/Converter'; import { logGas } from '../utils-v1/Log'; +import { DODOHelper } from '../utils-v1/dodoHelper'; let lp: string; let trader: string; -async function init(ctx: DODOContext): Promise { - await ctx.setOraclePrice(decimalStr("100")); - +async function initDODO_USDT(ctx: DODOContext): Promise { + await ctx.setOraclePrice(ctx.DODO_USDT_ORACLE,mweiStr("0.1")); lp = ctx.spareAccounts[0]; trader = ctx.spareAccounts[1]; - await ctx.approveDODO(lp); - await ctx.approveDODO(trader); + + let DODO = ctx.DODO; + let USDT = ctx.USDT; + let DODO_USDT = ctx.DODO_USDT; + await ctx.approvePair(DODO,USDT,DODO_USDT.options.address,lp); + await ctx.approvePair(DODO,USDT,DODO_USDT.options.address,trader); - await ctx.mintTestToken(lp, decimalStr("10"), decimalStr("1000")); - await ctx.mintTestToken(trader, decimalStr("10"), decimalStr("1000")); + await ctx.mintToken(DODO,USDT, lp, decimalStr("10000"), mweiStr("1000")); + await ctx.mintToken(DODO,USDT,trader, decimalStr("100"), mweiStr("0")); - await ctx.DODO.methods - .depositBaseTo(lp, decimalStr("10")) + await DODO_USDT.methods + .depositBaseTo(lp, decimalStr("10000")) .send(ctx.sendParam(lp)); - await ctx.DODO.methods - .depositQuoteTo(lp, decimalStr("1000")) + await DODO_USDT.methods + .depositQuoteTo(lp, mweiStr("1000")) .send(ctx.sendParam(lp)); - } - -async function calcRoute(ctx: DODOContext) { - let fromTokenAmount = decimalStr("1"); - //路径 - let routes = [ - { - address: ctx.BASE.options.address, - decimals: 18 - }, - { - address: ctx.QUOTE.options.address, - decimals: 18 - } - ] +async function initUSDT_USDC(ctx: DODOContext): Promise { + await ctx.setOraclePrice(ctx.USDT_USDC_ORACLE,decimalStr("1")); + lp = ctx.spareAccounts[0]; + trader = ctx.spareAccounts[1]; - //路径上交易对 - let pairs = [ - { - pair: ctx.DODO.options.address, - base: ctx.BASE.options.address - } - ] + let USDT = ctx.USDT; + let USDC = ctx.USDC; + let USDT_USDC = ctx.USDT_USDC; + + await ctx.approvePair(USDT,USDC,USDT_USDC.options.address,lp); + await ctx.mintToken(USDT,USDC,lp, mweiStr("1000"), mweiStr("1000")); + + await USDT_USDC.methods + .depositBaseTo(lp, mweiStr("1000")) + .send(ctx.sendParam(lp)); + await USDT_USDC.methods + .depositQuoteTo(lp, mweiStr("1000")) + .send(ctx.sendParam(lp)); +} + +async function initWETH_USDC(ctx: DODOContext): Promise { + await ctx.setOraclePrice(ctx.WETH_USDC_ORACLE,mweiStr("450")); + lp = ctx.spareAccounts[0]; + trader = ctx.spareAccounts[1]; + + let WETH = ctx.WETH; + let USDC = ctx.USDC; + let WETH_USDC = ctx.WETH_USDC; + + await ctx.approvePair(WETH,USDC,WETH_USDC.options.address,lp); + await ctx.mintToken(WETH,USDC,lp, decimalStr("1000"), mweiStr("450000")); + + await WETH_USDC.methods + .depositBaseTo(lp, decimalStr("1000")) + .send(ctx.sendParam(lp)); + await WETH_USDC.methods + .depositQuoteTo(lp, mweiStr("450000")) + .send(ctx.sendParam(lp)); +} + +//mock sdk logic +async function calcRoute(ctx: DODOContext,fromTokenAmount:string,slippage:number,routes:any[],pairs:any[]) { + let swapAmount = fromTokenAmount + let callPairs: string[] = [] let datas: string = "" let starts: number[] = [] let gAndV: number[] = [] - let swapAmount = fromTokenAmount for (let i = 0; i < pairs.length; i++) { - let curPair = pairs[i] - callPairs.push(curPair.pair) - //TODO: hardcode - let curContact =ctx.DODO; - let curData = '' - if (curPair.base === routes[i].address) { - curData = await curContact.methods.sellBaseToken(swapAmount, 0, []).encodeABI() - swapAmount = await curContact.methods.querySellBaseToken(swapAmount).call(); - } else { - curData = await curContact.methods.buyBaseToken(swapAmount, 0, []).encodABI() - swapAmount = await curContact.methods.queryBuyBaseToken(swapAmount).call(); + if(i == 0){ + starts.push(0); } - starts.push(datas.length) - gAndV.push(0) + let curPair = pairs[i] + let curContact =pairs[i].pairContract; + let curData = ''; + let curApproveData = ''; + + if (curPair.base === routes[i].address) { + curApproveData = await pairs[i].baseContract.methods.approve(curPair.pair,swapAmount).encodeABI() + curApproveData = curApproveData.substring(2,curApproveData.length) + datas += curApproveData + starts.push(datas.length/2) + gAndV.push(0) + callPairs.push(pairs[i].baseContract.options.address); + curData = await curContact.methods.sellBaseToken(swapAmount, 0, "0x").encodeABI() + console.log(i + ":b-for-swapAmount:",swapAmount); + swapAmount = await curContact.methods.querySellBaseToken(swapAmount).call(); + console.log(i + ":a-for-swapAmount:",swapAmount); + } else { + //TODO: approve的逻辑? + curApproveData = await pairs[i].quoteContract.methods.approve(curPair.pair,swapAmount).encodeABI() + curApproveData = curApproveData.substring(2,curApproveData.length) + datas += curApproveData + starts.push(datas.length/2) + gAndV.push(0) + callPairs.push(pairs[i].quoteContract.options.address); + console.log(i + ":b-for-swapAmount:",swapAmount); + let baseDecimal = await pairs[i].baseContract.methods.decimals().call(); + let quoteDecimal = await pairs[i].quoteContract.methods.decimals().call(); + let curPairDetail = { + B: new BigNumber(await curContact.methods._BASE_BALANCE_().call() / 10 ** baseDecimal), + Q: new BigNumber(await curContact.methods._QUOTE_BALANCE_().call() / 10 ** quoteDecimal), + B0: new BigNumber(await curContact.methods._TARGET_BASE_TOKEN_AMOUNT_().call() / 10 ** baseDecimal), + Q0: new BigNumber(await curContact.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call() / 10 ** quoteDecimal), + RStatus: await curContact.methods._R_STATUS_().call(), + OraclePrice: new BigNumber(await curContact.methods.getOraclePrice().call() / 10 ** (18-baseDecimal + quoteDecimal)), + k: new BigNumber(parseInt(ctx.k) / 1e18), + mtFeeRate: new BigNumber(parseInt(ctx.mtFeeRate) / 1e18), + lpFeeRate: new BigNumber(parseInt(ctx.lpFeeRate) / 1e18) + } + let dodoHelper = new DODOHelper(curPairDetail) + let tmpamount = dodoHelper.queryBuyQuote(new BigNumber(fromWei(swapAmount,'mwei'))).toString(); + swapAmount = decimalStr(tmpamount); + curData = await curContact.methods.buyBaseToken(swapAmount, 0, "0x").encodeABI() + console.log(i + ":a-for-swapAmount:",swapAmount); + } + curData = curData.substring(2,curData.length) datas += curData + starts.push(datas.length/2) + gAndV.push(0) + callPairs.push(curPair.pair) } - - let toAmount = new BigNumber(swapAmount).multipliedBy(0.99).toFixed(0, BigNumber.ROUND_DOWN) - + datas = "0x" + datas; + let toAmount = new BigNumber(swapAmount).multipliedBy(1-slippage).toFixed(0, BigNumber.ROUND_DOWN) return ctx.SmartSwap.methods.dodoSwap( - ctx.BASE.options.address, - ctx.QUOTE.options.address, + routes[0].address, + routes[routes.length-1].address, fromTokenAmount, toAmount, callPairs, @@ -100,7 +159,9 @@ describe("Trader", () => { before(async () => { ctx = await getDODOContext(); - await init(ctx); + await initDODO_USDT(ctx); + await initUSDT_USDC(ctx); + await initWETH_USDC(ctx); }); beforeEach(async () => { @@ -111,61 +172,138 @@ describe("Trader", () => { await ctx.EVM.reset(snapshotId); }); - describe("hit currently pair", () => { - it("base to quote", async () => { - var beforeBalance = await ctx.BASE.methods.balanceOf(trader).call() - // await ctx.BASE.methods.approve(ctx.SmartApprove.options.address,MAX_UINT256).send(ctx.sendParam(trader)) - console.log("beforeBalance",beforeBalance) - await logGas(await calcRoute(ctx), ctx.sendParam(trader), "buy token") - var afterBalance = await ctx.BASE.methods.balanceOf(trader).call() - console.log("afterBalance",afterBalance) - // // trader balances - // assert.equal( - // await ctx.BASE.methods.balanceOf(trader).call(), - // decimalStr("11") - // ); - // assert.equal( - // await ctx.QUOTE.methods.balanceOf(trader).call(), - // "898581839502056240973" - // ); + describe("route calc test", () => { + it("DODO to USDT directly swap", async () => { + var b_DODO = await ctx.DODO.methods.balanceOf(trader).call() + var b_USDT = await ctx.USDT.methods.balanceOf(trader).call() + console.log("Before DODO:" + fromWei(b_DODO,'ether') + "; USDT:" + fromWei(b_USDT,'mwei')); + //approve DODO entry + await ctx.DODO.methods.approve(ctx.SmartApprove.options.address,MAX_UINT256).send(ctx.sendParam(trader)) + //set route path + var routes = [{ + address: ctx.DODO.options.address, + decimals: 18 + }, + { + address: ctx.USDT.options.address, + decimals: 6 + }]; + + var pairs = [{ + pair: ctx.DODO_USDT.options.address, + base: ctx.DODO.options.address, + /*only for test*/ + pairContract: ctx.DODO_USDT, + baseContract: ctx.DODO, + quoteContract: ctx.USDT + /**************/ + }]; + + var tx = await logGas(await calcRoute(ctx,decimalStr('10'),0.1,routes,pairs), ctx.sendParam(trader), "route swap") + // console.log(tx.events['Swapped']); + var a_DODO = await ctx.DODO.methods.balanceOf(trader).call() + var a_USDT = await ctx.USDT.methods.balanceOf(trader).call() + console.log("After DODO:" + fromWei(a_DODO,'ether') + "; USDT:" + fromWei(a_USDT,'mwei')); + }); + + + it("DODO to USDC two hops swap", async () => { + var b_DODO = await ctx.DODO.methods.balanceOf(trader).call() + var b_USDC = await ctx.USDC.methods.balanceOf(trader).call() + console.log("Before DODO:" + fromWei(b_DODO,'ether') + "; USDC:" + fromWei(b_USDC,'mwei')); + //approve DODO entry + await ctx.DODO.methods.approve(ctx.SmartApprove.options.address,MAX_UINT256).send(ctx.sendParam(trader)) + //set route path + var routes = [{ + address: ctx.DODO.options.address, + decimals: 18 + },{ + address: ctx.USDT.options.address, + decimals: 6 + },{ + address: ctx.USDC.options.address, + decimals: 6 + }]; + + var pairs = [{ + pair: ctx.DODO_USDT.options.address, + base: ctx.DODO.options.address, + /*only for test*/ + pairContract: ctx.DODO_USDT, + baseContract: ctx.DODO, + quoteContract: ctx.USDT + /**************/ + },{ + pair: ctx.USDT_USDC.options.address, + base: ctx.USDT.options.address, + /*only for test*/ + pairContract: ctx.USDT_USDC, + baseContract: ctx.USDT, + quoteContract: ctx.USDC + /**************/ + }]; + + var tx = await logGas(await calcRoute(ctx,decimalStr('10'),0.1,routes,pairs), ctx.sendParam(trader), "route swap") + // console.log(tx.events['Swapped']); + var a_DODO = await ctx.DODO.methods.balanceOf(trader).call() + var a_USDC = await ctx.USDC.methods.balanceOf(trader).call() + console.log("After DODO:" + fromWei(a_DODO,'ether') + "; USDC:" + fromWei(a_USDC,'mwei')); + }); + + + + it("DODO to WETH three hops swap", async () => { + var b_DODO = await ctx.DODO.methods.balanceOf(trader).call() + var b_WETH = await ctx.WETH.methods.balanceOf(trader).call() + console.log("Before DODO:" + fromWei(b_DODO,'ether') + "; WETH:" + fromWei(b_WETH,'ether')); + //approve DODO entry + await ctx.DODO.methods.approve(ctx.SmartApprove.options.address,MAX_UINT256).send(ctx.sendParam(trader)) + //set route path + var routes = [{ + address: ctx.DODO.options.address, + decimals: 18 + },{ + address: ctx.USDT.options.address, + decimals: 6 + },{ + address: ctx.USDC.options.address, + decimals: 6 + },{ + address: ctx.WETH.options.address, + decimals: 18 + }]; + + var pairs = [{ + pair: ctx.DODO_USDT.options.address, + base: ctx.DODO.options.address, + /*only for test*/ + pairContract: ctx.DODO_USDT, + baseContract: ctx.DODO, + quoteContract: ctx.USDT + /**************/ + },{ + pair: ctx.USDT_USDC.options.address, + base: ctx.USDT.options.address, + /*only for test*/ + pairContract: ctx.USDT_USDC, + baseContract: ctx.USDT, + quoteContract: ctx.USDC + /**************/ + },{ + pair: ctx.WETH_USDC.options.address, + base: ctx.WETH.options.address, + /*only for test*/ + pairContract: ctx.WETH_USDC, + baseContract: ctx.WETH, + quoteContract: ctx.USDC + /**************/ + }]; + + var tx = await logGas(await calcRoute(ctx,decimalStr('10'),0.1,routes,pairs), ctx.sendParam(trader), "route swap") + // console.log(tx.events['Swapped']); + var a_DODO = await ctx.DODO.methods.balanceOf(trader).call() + var a_WETH = await ctx.WETH.methods.balanceOf(trader).call() + console.log("After DODO:" + fromWei(a_DODO,'ether') + "; WETH:" + fromWei(a_WETH,'ether')); }); }); - - - // describe("Revert cases", () => { - // it("price limit", async () => { - // await assert.rejects( - // ctx.DODO.methods - // .buyBaseToken(decimalStr("1"), decimalStr("100"), "0x") - // .send(ctx.sendParam(trader)), - // /BUY_BASE_COST_TOO_MUCH/ - // ); - // await assert.rejects( - // ctx.DODO.methods - // .sellBaseToken(decimalStr("1"), decimalStr("100"), "0x") - // .send(ctx.sendParam(trader)), - // /SELL_BASE_RECEIVE_NOT_ENOUGH/ - // ); - // }); - - // it("base balance limit", async () => { - // await assert.rejects( - // ctx.DODO.methods - // .buyBaseToken(decimalStr("11"), decimalStr("10000"), "0x") - // .send(ctx.sendParam(trader)), - // /DODO_BASE_BALANCE_NOT_ENOUGH/ - // ); - - // await ctx.DODO.methods - // .buyBaseToken(decimalStr("1"), decimalStr("200"), "0x") - // .send(ctx.sendParam(trader)); - - // await assert.rejects( - // ctx.DODO.methods - // .buyBaseToken(decimalStr("11"), decimalStr("10000"), "0x") - // .send(ctx.sendParam(trader)), - // /DODO_BASE_BALANCE_NOT_ENOUGH/ - // ); - // }); - // }); }); diff --git a/test/utils-v1/Context.ts b/test/utils-v1/Context-route.ts similarity index 51% rename from test/utils-v1/Context.ts rename to test/utils-v1/Context-route.ts index f00ba44..68a6a02 100644 --- a/test/utils-v1/Context.ts +++ b/test/utils-v1/Context-route.ts @@ -49,47 +49,48 @@ export let DefaultDODOContextInitConfig = { export class DODOContext { EVM: EVM; Web3: Web3; - DODO: Contract; DODOZoo: Contract; - BASE: Contract; - BaseCapital: Contract; - QUOTE: Contract; - QuoteCapital: Contract; - ORACLE: Contract; - SmartSwap: Contract; - SmartApprove: Contract; Deployer: string; Supervisor: string; Maintainer: string; spareAccounts: string[]; + lpFeeRate: string; + mtFeeRate: string; + k: string; + + //token + DODO:Contract; + USDT:Contract; + USDC:Contract; + WETH:Contract; + //pair + DODO_USDT: Contract; + USDT_USDC: Contract; + WETH_USDC: Contract; + DODO_USDT_ORACLE: Contract; + USDT_USDC_ORACLE: Contract; + WETH_USDC_ORACLE: Contract; + //SmartRoute + SmartSwap: Contract; + SmartApprove: Contract; constructor() {} async init(config: DODOContextInitConfig) { + this.k = config.k; + this.mtFeeRate = config.mtFeeRate; + this.lpFeeRate = config.lpFeeRate; + this.EVM = new EVM(); this.Web3 = getDefaultWeb3(); var cloneFactory = await contracts.newContract( contracts.CLONE_FACTORY_CONTRACT_NAME ); - - this.BASE = await contracts.newContract( - contracts.TEST_ERC20_CONTRACT_NAME, - ["TestBase", 18] - ); - this.QUOTE = await contracts.newContract( - contracts.TEST_ERC20_CONTRACT_NAME, - ["TestQuote", 18] - ); - this.ORACLE = await contracts.newContract( - contracts.NAIVE_ORACLE_CONTRACT_NAME - ); - const allAccounts = await this.Web3.eth.getAccounts(); this.Deployer = allAccounts[0]; this.Supervisor = allAccounts[1]; this.Maintainer = allAccounts[2]; this.spareAccounts = allAccounts.slice(3, 10); - var DODOTemplate = await contracts.newContract( contracts.DODO_CONTRACT_NAME ); @@ -101,13 +102,66 @@ export class DODOContext { this.Supervisor, ] ); - + //发币 + this.DODO = await contracts.newContract( + contracts.TEST_ERC20_CONTRACT_NAME, + ["DODO", 18] + ); + this.USDT = await contracts.newContract( + contracts.TEST_ERC20_CONTRACT_NAME, + ["USDT", 6] + ); + this.USDC = await contracts.newContract( + contracts.TEST_ERC20_CONTRACT_NAME, + ["USDC", 6] + ); + this.WETH = await contracts.newContract( + contracts.TEST_ERC20_CONTRACT_NAME, + ["WETH", 18] + ); + //创建交易对 + //DODO-USDT + this.DODO_USDT_ORACLE = await contracts.newContract( + contracts.NAIVE_ORACLE_CONTRACT_NAME + ); await this.DODOZoo.methods .breedDODO( this.Maintainer, - this.BASE.options.address, - this.QUOTE.options.address, - this.ORACLE.options.address, + this.DODO.options.address, + this.USDT.options.address, + this.DODO_USDT_ORACLE.options.address, + config.lpFeeRate, + config.mtFeeRate, + config.k, + config.gasPriceLimit + ) + .send(this.sendParam(this.Deployer)); + //USDT-USDC + this.USDT_USDC_ORACLE = await contracts.newContract( + contracts.NAIVE_ORACLE_CONTRACT_NAME + ); + await this.DODOZoo.methods + .breedDODO( + this.Maintainer, + this.USDT.options.address, + this.USDC.options.address, + this.USDT_USDC_ORACLE.options.address, + config.lpFeeRate, + config.mtFeeRate, + config.k, + config.gasPriceLimit + ) + .send(this.sendParam(this.Deployer)); + //WETH-USDC + this.WETH_USDC_ORACLE = await contracts.newContract( + contracts.NAIVE_ORACLE_CONTRACT_NAME + ); + await this.DODOZoo.methods + .breedDODO( + this.Maintainer, + this.WETH.options.address, + this.USDC.options.address, + this.WETH_USDC_ORACLE.options.address, config.lpFeeRate, config.mtFeeRate, config.k, @@ -115,30 +169,50 @@ export class DODOContext { ) .send(this.sendParam(this.Deployer)); - this.DODO = contracts.getContractWithAddress( + this.DODO_USDT = contracts.getContractWithAddress( contracts.DODO_CONTRACT_NAME, await this.DODOZoo.methods - .getDODO(this.BASE.options.address, this.QUOTE.options.address) + .getDODO(this.DODO.options.address, this.USDT.options.address) .call() ); - await this.DODO.methods + + this.USDT_USDC = contracts.getContractWithAddress( + contracts.DODO_CONTRACT_NAME, + await this.DODOZoo.methods + .getDODO(this.USDT.options.address, this.USDC.options.address) + .call() + ); + this.WETH_USDC = contracts.getContractWithAddress( + contracts.DODO_CONTRACT_NAME, + await this.DODOZoo.methods + .getDODO(this.WETH.options.address, this.USDC.options.address) + .call() + ); + + await this.DODO_USDT.methods .enableBaseDeposit() .send(this.sendParam(this.Deployer)); - await this.DODO.methods + await this.DODO_USDT.methods .enableQuoteDeposit() .send(this.sendParam(this.Deployer)); - await this.DODO.methods.enableTrading().send(this.sendParam(this.Deployer)); + await this.DODO_USDT.methods.enableTrading().send(this.sendParam(this.Deployer)); - this.BaseCapital = contracts.getContractWithAddress( - contracts.DODO_LP_TOKEN_CONTRACT_NAME, - await this.DODO.methods._BASE_CAPITAL_TOKEN_().call() - ); - this.QuoteCapital = contracts.getContractWithAddress( - contracts.DODO_LP_TOKEN_CONTRACT_NAME, - await this.DODO.methods._QUOTE_CAPITAL_TOKEN_().call() - ); + await this.USDT_USDC.methods + .enableBaseDeposit() + .send(this.sendParam(this.Deployer)); + await this.USDT_USDC.methods + .enableQuoteDeposit() + .send(this.sendParam(this.Deployer)); + await this.USDT_USDC.methods.enableTrading().send(this.sendParam(this.Deployer)); + + await this.WETH_USDC.methods + .enableBaseDeposit() + .send(this.sendParam(this.Deployer)); + await this.WETH_USDC.methods + .enableQuoteDeposit() + .send(this.sendParam(this.Deployer)); + await this.WETH_USDC.methods.enableTrading().send(this.sendParam(this.Deployer)); - /*v1.5*/ this.SmartApprove = await contracts.newContract( contracts.SMART_APPROVE ); @@ -149,7 +223,6 @@ export class DODOContext { ); await this.SmartApprove.methods.setSmartSwap(this.SmartSwap.options.address).send(this.sendParam(this.Deployer)); - /*****/ console.log(log.blueText("[Init dodo context]")); } @@ -163,25 +236,25 @@ export class DODOContext { }; } - async setOraclePrice(price: string) { - await this.ORACLE.methods + async setOraclePrice(oracle:Contract,price: string) { + await oracle.methods .setPrice(price) .send(this.sendParam(this.Deployer)); } - async mintTestToken(to: string, base: string, quote: string) { - await this.BASE.methods.mint(to, base).send(this.sendParam(this.Deployer)); - await this.QUOTE.methods - .mint(to, quote) + async mintToken(tokenBase:Contract,tokenQuote:Contract,to: string, base: string, quote: string) { + await tokenBase.methods.mint(to, base).send(this.sendParam(this.Deployer)); + await tokenQuote.methods + .mint(to,  quote) .send(this.sendParam(this.Deployer)); } - async approveDODO(account: string) { - await this.BASE.methods - .approve(this.DODO.options.address, MAX_UINT256) + async approvePair(tokenBase:Contract,tokenQuote:Contract, approveTarget:string,account: string) { + await tokenBase.methods + .approve(approveTarget, MAX_UINT256) .send(this.sendParam(account)); - await this.QUOTE.methods - .approve(this.DODO.options.address, MAX_UINT256) + await tokenQuote.methods + .approve(approveTarget, MAX_UINT256) .send(this.sendParam(account)); } } diff --git a/test/utils-v1/Converter.ts b/test/utils-v1/Converter.ts index c7108b9..f4af089 100644 --- a/test/utils-v1/Converter.ts +++ b/test/utils-v1/Converter.ts @@ -1,4 +1,5 @@ import BigNumber from "bignumber.js"; +import { getDefaultWeb3 } from './EVM'; export const MAX_UINT256 = "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" @@ -12,4 +13,9 @@ export function mweiStr(value: string): string { export function gweiStr(gwei: string): string { return new BigNumber(gwei).multipliedBy(10 ** 9).toFixed(0, BigNumber.ROUND_DOWN) +} + +export function fromWei(value:string,unit:any): string { + var web3 = getDefaultWeb3(); + return web3.utils.fromWei(value,unit); } \ No newline at end of file diff --git a/test/utils-v1/dodoHelper.ts b/test/utils-v1/dodoHelper.ts new file mode 100644 index 0000000..ca83e23 --- /dev/null +++ b/test/utils-v1/dodoHelper.ts @@ -0,0 +1,366 @@ +import { BigNumber } from 'bignumber.js'; + +export const RStatusOne = 0; +export const RStatusAboveOne = 1; +export const RStatusBelowOne = 2; + +export class DODOHelper { + // unstable + public B!: BigNumber; // DODO._BASE_BALANCE_() / 10^baseDecimals + public Q!: BigNumber; // DODO._QUOTE_BALANCE_() / 10^quoteDecimals + public B0!: BigNumber; // DODO._TARGET_BASE_TOKEN_AMOUNT_() / 10^baseDecimals + public Q0!: BigNumber; // DODO._TARGET_QUOTE_TOKEN_AMOUNT_() / 10^quoteDecimals + public RStatus!: number; // DODO._R_STATUS_() + public OraclePrice!: BigNumber; // DODO.getOraclePrice() / 10^(18-baseDecimals+quoteDecimals) + + // stable + public k!: BigNumber; // DODO._K_()/10^18 + public mtFeeRate!: BigNumber; // DODO._MT_FEE_RATE_()/10^18 + public lpFeeRate!: BigNumber; // DODO._LP_FEE_RATE_()/10^18 + + constructor(pairDetail:any) { + this.B = pairDetail.B + this.Q = pairDetail.Q + this.B0 = pairDetail.B0 + this.Q0 = pairDetail.Q0 + this.RStatus = pairDetail.RStatus + this.OraclePrice = pairDetail.OraclePrice + this.k = pairDetail.k + this.mtFeeRate = pairDetail.mtFeeRate + this.lpFeeRate = pairDetail.lpFeeRate + } + + // return mid price + public getMidPrice(): BigNumber { + if (this.RStatus === RStatusOne) { + return this.OraclePrice; + } + if (this.RStatus === RStatusAboveOne) { + let R = this.B0.div(this.B); + R = R.multipliedBy(R) + .multipliedBy(this.k) + .minus(this.k) + .plus(new BigNumber(1)); + return this.OraclePrice.multipliedBy(R); + } + if (this.RStatus === RStatusBelowOne) { + let R = this.Q0.div(this.Q); + R = R.multipliedBy(R) + .multipliedBy(this.k) + .minus(this.k) + .plus(new BigNumber(1)); + return this.OraclePrice.div(R); + } + return this.OraclePrice; + } + + // return the targetBase and targetQuote assuming system balanced + public getExpectedTarget(): { base: BigNumber; quote: BigNumber } { + let baseTarget: BigNumber; + let quoteTarget: BigNumber; + baseTarget = this.B0; + quoteTarget = this.Q0; + if (this.RStatus === RStatusOne) { + baseTarget = this.B0; + quoteTarget = this.Q0; + } + if (this.RStatus === RStatusAboveOne) { + quoteTarget = this.Q0; + baseTarget = solveQuadraticFunctionForTarget(this.B, this.k, this.Q.minus(this.Q0).div(this.OraclePrice)); + } + if (this.RStatus === RStatusBelowOne) { + baseTarget = this.B0; + quoteTarget = solveQuadraticFunctionForTarget( + this.Q, + this.k, + this.B.minus(this.B0).multipliedBy(this.OraclePrice) + ); + } + return { + base: baseTarget, + quote: quoteTarget + }; + } + + // return paid quote amount (fee deducted) + public queryBuyBase(amount: BigNumber) { + let mtFee = amount.multipliedBy(this.mtFeeRate); + let lpFee = amount.multipliedBy(this.lpFeeRate); + amount = amount.plus(mtFee).plus(lpFee); + let target = this.getExpectedTarget(); + let quote = new BigNumber(0); + if (this.RStatus === RStatusOne) { + quote = this.ROneBuyBase(amount, target.base); + } else if (this.RStatus === RStatusAboveOne) { + quote = this.RAboveBuyBase(amount, target.base); + } else { + let backOneBase = this.B.minus(target.base); + let backOneQuote = target.quote.minus(this.Q); + if (amount.isLessThanOrEqualTo(backOneBase)) { + quote = this.RBelowBuyBase(amount, target.quote); + } else { + quote = backOneQuote.plus(this.ROneBuyBase(amount.minus(backOneBase), target.base)); + } + } + + return quote + } + + // return received quote amount (fee deducted) + public querySellBase(amount: BigNumber) { + let result: BigNumber; + let target = this.getExpectedTarget(); + if (this.RStatus === RStatusOne) { + result = this.ROneSellBase(amount, target.quote); + } else if (this.RStatus === RStatusBelowOne) { + result = this.RBelowSellBase(amount, target.quote); + } else { + let backOneBase = target.base.minus(this.B); + let backOneQuote = this.Q.minus(target.quote); + if (amount.isLessThanOrEqualTo(backOneBase)) { + result = this.RAboveSellBase(amount, target.base); + } else { + result = backOneQuote.plus(this.ROneSellBase(amount.minus(backOneBase), target.quote)); + } + } + let mtFee = result.multipliedBy(this.mtFeeRate); + let lpFee = result.multipliedBy(this.lpFeeRate); + + const quote = result.minus(mtFee).minus(lpFee); + + return quote + } + + // return paid base amount (fee deducted) + public queryBuyQuote(amount: BigNumber): BigNumber { + let mtFee = amount.multipliedBy(this.mtFeeRate); + let lpFee = amount.multipliedBy(this.lpFeeRate); + amount = amount.plus(mtFee).plus(lpFee); + let target = this.getExpectedTarget(); + if (this.RStatus === RStatusOne) { + return this.ROneBuyQuote(amount, target.quote); + } else if (this.RStatus === RStatusBelowOne) { + return this.RBelowBuyQuote(amount, target.quote); + } else { + let backOneBase = target.base.minus(this.B); + let backOneQuote = this.Q.minus(target.quote); + if (amount.isLessThanOrEqualTo(backOneQuote)) { + return this.RAboveBuyQuote(amount, target.base); + } else { + return backOneBase.plus(this.ROneBuyQuote(amount.minus(backOneQuote), target.quote)); + } + } + } + + // return received base amount (fee deducted) + public querySellQuote(amount: BigNumber): BigNumber { + let result: BigNumber; + let target = this.getExpectedTarget(); + if (this.RStatus === RStatusOne) { + result = this.ROneSellQuote(amount, target.base); + } else if (this.RStatus === RStatusAboveOne) { + result = this.RAboveSellQuote(amount, target.base); + } else { + let backOneBase = this.B.minus(target.base); + let backOneQuote = target.quote.minus(this.Q); + if (amount.isLessThanOrEqualTo(backOneQuote)) { + result = this.RBelowSellQuote(amount, target.quote); + } else { + result = backOneBase.plus(this.ROneSellQuote(amount.minus(backOneQuote), target.base)); + } + } + let mtFee = result.multipliedBy(this.mtFeeRate); + let lpFee = result.multipliedBy(this.lpFeeRate); + return result.minus(mtFee).minus(lpFee); + } + + public getWithdrawBasePenalty(amount: BigNumber): BigNumber { + if (this.RStatus === RStatusAboveOne) { + let baseTarget = solveQuadraticFunctionForTarget(this.B, this.k, this.Q.minus(this.Q0).div(this.OraclePrice)); + let baseTargetWithdraw = solveQuadraticFunctionForTarget( + this.B.minus(amount), + this.k, + this.Q.minus(this.Q0).div(this.OraclePrice) + ); + let penalty = baseTarget.minus(baseTargetWithdraw).minus(amount); + return penalty; + } else { + return new BigNumber(0); + } + } + + public getWithdrawQuotePenalty(amount: BigNumber): BigNumber { + if (this.RStatus === RStatusBelowOne) { + let quoteTarget = solveQuadraticFunctionForTarget( + this.Q, + this.k, + this.B.minus(this.B0).multipliedBy(this.OraclePrice) + ); + let quoteTargetWithdraw = solveQuadraticFunctionForTarget( + this.Q.minus(amount), + this.k, + this.B.minus(this.B0).multipliedBy(this.OraclePrice) + ); + let penalty = quoteTarget.minus(quoteTargetWithdraw).minus(amount); + return penalty; + } else { + return new BigNumber(0); + } + } + + // =========== helper ROne =========== + + public ROneBuyBase(amount: BigNumber, targetBase: BigNumber): BigNumber { + if (amount.isGreaterThanOrEqualTo(targetBase)) { + throw new Error('ROne Buy Base Amount Exceed Limitation'); + } + return integrate(targetBase, targetBase, targetBase.minus(amount), this.OraclePrice, this.k); + } + + public ROneBuyQuote(amount: BigNumber, targetQuote: BigNumber): BigNumber { + if (amount.isGreaterThanOrEqualTo(targetQuote)) { + throw new Error('ROne Buy Quote Amount Exceed Limitation'); + } + return integrate( + targetQuote, + targetQuote, + targetQuote.minus(amount), + new BigNumber(1).div(this.OraclePrice), + this.k + ); + } + + public ROneSellBase(amount: BigNumber, targetQuote: BigNumber): BigNumber { + let newQ = solveQuadraticFunctionForTrade(targetQuote, targetQuote, this.OraclePrice, amount.negated(), this.k); + return targetQuote.minus(newQ); + } + + public ROneSellQuote(amount: BigNumber, targetBase: BigNumber): BigNumber { + let newB = solveQuadraticFunctionForTrade( + targetBase, + targetBase, + new BigNumber(1).div(this.OraclePrice), + amount.negated(), + this.k + ); + return targetBase.minus(newB); + } + + // =========== helper RAbove =========== + + public RAboveBuyBase(amount: BigNumber, targetBase: BigNumber): BigNumber { + if (amount.isGreaterThanOrEqualTo(this.B)) { + throw new Error('RAbove Buy Base Amount Exceed Limitation'); + } + return integrate(targetBase, this.B, this.B.minus(amount), this.OraclePrice, this.k); + } + + public RAboveSellBase(amount: BigNumber, targetBase: BigNumber): BigNumber { + if (amount.plus(this.B).isGreaterThan(targetBase)) { + throw new Error('RAbove Sell Base Amount Exceed Limitation'); + } + return integrate(targetBase, this.B.plus(amount), this.B, this.OraclePrice, this.k); + } + + public RAboveBuyQuote(amount: BigNumber, targetBase: BigNumber): BigNumber { + let newB = solveQuadraticFunctionForTrade( + targetBase, + this.B, + new BigNumber(1).div(this.OraclePrice), + amount, + this.k + ); + return newB.minus(this.B); + } + + public RAboveSellQuote(amount: BigNumber, targetBase: BigNumber): BigNumber { + let newB = solveQuadraticFunctionForTrade( + targetBase, + this.B, + new BigNumber(1).div(this.OraclePrice), + amount.negated(), + this.k + ); + return this.B.minus(newB); + } + + // =========== helper RBelow =========== + + public RBelowBuyQuote(amount: BigNumber, targetQuote: BigNumber): BigNumber { + if (amount.isGreaterThanOrEqualTo(this.Q)) { + throw new Error('RBelow Buy Quote Amount Exceed Limitation'); + } + return integrate(targetQuote, this.Q, this.Q.minus(amount), new BigNumber(1).div(this.OraclePrice), this.k); + } + + public RBelowSellQuote(amount: BigNumber, targetQuote: BigNumber): BigNumber { + if (amount.plus(this.Q).isGreaterThan(targetQuote)) { + throw new Error('RBelow Sell Quote Amount Exceed Limitation'); + } + return integrate(targetQuote, this.Q.plus(amount), this.Q, new BigNumber(1).div(this.OraclePrice), this.k); + } + + public RBelowBuyBase(amount: BigNumber, targetQuote: BigNumber): BigNumber { + let newQ = solveQuadraticFunctionForTrade(targetQuote, this.Q, this.OraclePrice, amount, this.k); + return newQ.minus(this.Q); + } + + public RBelowSellBase(amount: BigNumber, targetQuote: BigNumber): BigNumber { + let newQ = solveQuadraticFunctionForTrade(targetQuote, this.Q, this.OraclePrice, amount.negated(), this.k); + return this.Q.minus(newQ); + } +} + +export const integrate = (V0: BigNumber, V1: BigNumber, V2: BigNumber, i: BigNumber, k: BigNumber): BigNumber => { + let fairAmount = i.multipliedBy(V1.minus(V2)); + let penalty = V0.multipliedBy(V0) + .div(V1) + .div(V2) + .multipliedBy(k); + return fairAmount.multipliedBy(new BigNumber(1).minus(k).plus(penalty)); +}; + +export const solveQuadraticFunctionForTrade = ( + V0: BigNumber, + V1: BigNumber, + i: BigNumber, + delta: BigNumber, + k: BigNumber +): BigNumber => { + // -b = (1-k)V1-kV0^2/V1+i*delta + let minusB = new BigNumber(1).minus(k).multipliedBy(V1); + minusB = minusB.minus( + k + .multipliedBy(V0) + .multipliedBy(V0) + .div(V1) + ); + minusB = minusB.plus(i.multipliedBy(delta)); + + // sqrt(b*b+4(1-k)kQ0*Q0) + let squareRoot = new BigNumber(4) + .multipliedBy(new BigNumber(1).minus(k)) + .multipliedBy(k) + .multipliedBy(V0) + .multipliedBy(V0); + squareRoot = minusB + .multipliedBy(minusB) + .plus(squareRoot) + .sqrt(); + + // 2(1-k) + let denominator = new BigNumber(2).multipliedBy(new BigNumber(1).minus(k)); + + return minusB.plus(squareRoot).div(denominator); +}; + +export const solveQuadraticFunctionForTarget = (V1: BigNumber, k: BigNumber, fairAmount: BigNumber): BigNumber => { + // V0 = V1+V1*(sqrt-1)/2k + let sqrt = new BigNumber(4) + .multipliedBy(k) + .multipliedBy(fairAmount) + .div(V1); + sqrt = new BigNumber(1).plus(sqrt).sqrt(); + let premium = sqrt.minus(new BigNumber(1)).div(k.multipliedBy(new BigNumber(2))); + return V1.multipliedBy(new BigNumber(1).plus(premium)); +}; From 897b2a4759a0a637c8ee01f67343e4ef108aec2d Mon Sep 17 00:00:00 2001 From: owen05 Date: Tue, 10 Nov 2020 23:14:02 +0800 Subject: [PATCH 108/118] fix quote => base swap test --- .../DODOVendorMachine/impl/DVMFunding.sol | 2 +- test/Route/Route.test.ts | 27 ++++++++++++++----- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/contracts/DODOVendorMachine/impl/DVMFunding.sol b/contracts/DODOVendorMachine/impl/DVMFunding.sol index 9e715c2..a169ae0 100644 --- a/contracts/DODOVendorMachine/impl/DVMFunding.sol +++ b/contracts/DODOVendorMachine/impl/DVMFunding.sol @@ -61,7 +61,7 @@ contract DVMFunding is DVMStorage { _VAULT_.transferBaseOut(to, baseAmount); _VAULT_.transferQuoteOut(to, quoteAmount); _VAULT_.sync(); - if (data.length > 0) IDODOCallee(to, shareAmount, baseAmount, quoteAmount, data); + if (data.length > 0) IDODOCallee(msg.sender).DVMSellShareCall(to, shareAmount, baseAmount, quoteAmount, data); } function retrieve(address to) external preventReentrant { diff --git a/test/Route/Route.test.ts b/test/Route/Route.test.ts index e4d6e99..011be8d 100644 --- a/test/Route/Route.test.ts +++ b/test/Route/Route.test.ts @@ -48,6 +48,7 @@ async function initUSDT_USDC(ctx: DODOContext): Promise { await ctx.approvePair(USDT,USDC,USDT_USDC.options.address,lp); await ctx.mintToken(USDT,USDC,lp, mweiStr("1000"), mweiStr("1000")); + await ctx.mintToken(USDT,USDC,trader, mweiStr("0"), mweiStr("0")); await USDT_USDC.methods .depositBaseTo(lp, mweiStr("1000")) @@ -106,7 +107,6 @@ async function calcRoute(ctx: DODOContext,fromTokenAmount:string,slippage:number swapAmount = await curContact.methods.querySellBaseToken(swapAmount).call(); console.log(i + ":a-for-swapAmount:",swapAmount); } else { - //TODO: approve的逻辑? curApproveData = await pairs[i].quoteContract.methods.approve(curPair.pair,swapAmount).encodeABI() curApproveData = curApproveData.substring(2,curApproveData.length) datas += curApproveData @@ -128,9 +128,11 @@ async function calcRoute(ctx: DODOContext,fromTokenAmount:string,slippage:number lpFeeRate: new BigNumber(parseInt(ctx.lpFeeRate) / 1e18) } let dodoHelper = new DODOHelper(curPairDetail) - let tmpamount = dodoHelper.queryBuyQuote(new BigNumber(fromWei(swapAmount,'mwei'))).toString(); - swapAmount = decimalStr(tmpamount); - curData = await curContact.methods.buyBaseToken(swapAmount, 0, "0x").encodeABI() + //TODO:2倍? + let tmpQuoteAmount = new BigNumber(swapAmount).multipliedBy(1-0.006).toFixed(0, BigNumber.ROUND_DOWN) + let tmpBaseAmount = dodoHelper.queryBuyQuote(new BigNumber(fromWei(tmpQuoteAmount,'mwei'))).toString(); + curData = await curContact.methods.buyBaseToken(decimalStr(tmpBaseAmount), swapAmount, "0x").encodeABI() + swapAmount = decimalStr(tmpBaseAmount); console.log(i + ":a-for-swapAmount:",swapAmount); } curData = curData.substring(2,curData.length) @@ -204,6 +206,10 @@ describe("Trader", () => { var a_DODO = await ctx.DODO.methods.balanceOf(trader).call() var a_USDT = await ctx.USDT.methods.balanceOf(trader).call() console.log("After DODO:" + fromWei(a_DODO,'ether') + "; USDT:" + fromWei(a_USDT,'mwei')); + console.log("===============================================") + var c_DODO = await ctx.DODO.methods.balanceOf(ctx.SmartSwap.options.address).call() + var c_USDT = await ctx.USDT.methods.balanceOf(ctx.SmartSwap.options.address).call() + console.log("Contract DODO:" + fromWei(c_DODO,'ether') + "; USDT:" + fromWei(c_USDT,'mwei')); }); @@ -248,10 +254,13 @@ describe("Trader", () => { var a_DODO = await ctx.DODO.methods.balanceOf(trader).call() var a_USDC = await ctx.USDC.methods.balanceOf(trader).call() console.log("After DODO:" + fromWei(a_DODO,'ether') + "; USDC:" + fromWei(a_USDC,'mwei')); + console.log("===============================================") + var c_DODO = await ctx.DODO.methods.balanceOf(ctx.SmartSwap.options.address).call() + var c_USDT = await ctx.USDT.methods.balanceOf(ctx.SmartSwap.options.address).call() + var c_USDC = await ctx.USDC.methods.balanceOf(ctx.SmartSwap.options.address).call() + console.log("Contract DODO:" + fromWei(c_DODO,'ether') + "; USDT:" + fromWei(c_USDT,'mwei') + "; USDC:" + fromWei(c_USDC,'mwei')); }); - - it("DODO to WETH three hops swap", async () => { var b_DODO = await ctx.DODO.methods.balanceOf(trader).call() var b_WETH = await ctx.WETH.methods.balanceOf(trader).call() @@ -304,6 +313,12 @@ describe("Trader", () => { var a_DODO = await ctx.DODO.methods.balanceOf(trader).call() var a_WETH = await ctx.WETH.methods.balanceOf(trader).call() console.log("After DODO:" + fromWei(a_DODO,'ether') + "; WETH:" + fromWei(a_WETH,'ether')); + console.log("===============================================") + var c_DODO = await ctx.DODO.methods.balanceOf(ctx.SmartSwap.options.address).call() + var c_USDT = await ctx.USDT.methods.balanceOf(ctx.SmartSwap.options.address).call() + var c_USDC = await ctx.USDC.methods.balanceOf(ctx.SmartSwap.options.address).call() + var c_WETH = await ctx.WETH.methods.balanceOf(ctx.SmartSwap.options.address).call() + console.log("Contract DODO:" + fromWei(c_DODO,'ether') + "; USDT:" + fromWei(c_USDT,'mwei') + "; USDC:" + fromWei(c_USDC,'mwei') + "; WETH:" + fromWei(c_WETH,'ether')); }); }); }); From 5fd411c50c4957b51a6329729231b2b57edafe82 Mon Sep 17 00:00:00 2001 From: mingda Date: Wed, 11 Nov 2020 16:42:00 +0800 Subject: [PATCH 109/118] set gas price to external contract --- contracts/DODOVendorMachine/impl/DVM.sol | 4 ++- .../DODOVendorMachine/impl/DVMStorage.sol | 12 ++++++-- .../DODOVendorMachine/impl/DVMTrader.sol | 2 ++ contracts/DODOVendorMachine/intf/IDVM.sol | 1 + contracts/Factory/DVMFactory.sol | 7 ++++- contracts/lib/GasPriceSource.sol | 29 +++++++++++++++++++ test/DVM/funding.test.ts | 6 ++-- test/utils/Contracts.ts | 1 + test/utils/DVMContext.ts | 6 +++- 9 files changed, 59 insertions(+), 9 deletions(-) create mode 100644 contracts/lib/GasPriceSource.sol diff --git a/contracts/DODOVendorMachine/impl/DVM.sol b/contracts/DODOVendorMachine/impl/DVM.sol index 70ea6d2..4b437ad 100644 --- a/contracts/DODOVendorMachine/impl/DVM.sol +++ b/contracts/DODOVendorMachine/impl/DVM.sol @@ -10,6 +10,7 @@ pragma experimental ABIEncoderV2; import {IFeeRateModel} from "../../intf/IFeeRateModel.sol"; import {IPermissionManager} from "../../lib/PermissionManager.sol"; +import {IGasPriceSource} from "../../lib/GasPriceSource.sol"; import {DVMTrader} from "./DVMTrader.sol"; import {DVMFunding} from "./DVMFunding.sol"; import {DVMVault} from "./DVMVault.sol"; @@ -22,6 +23,7 @@ contract DVM is DVMTrader, DVMFunding { address lpFeeRateModel, address mtFeeRateModel, address tradePermissionManager, + address gasPriceSource, uint256 i, uint256 k ) external { @@ -32,10 +34,10 @@ contract DVM is DVMTrader, DVMFunding { _LP_FEE_RATE_MODEL_ = IFeeRateModel(lpFeeRateModel); _MT_FEE_RATE_MODEL_ = IFeeRateModel(mtFeeRateModel); _TRADE_PERMISSION_ = IPermissionManager(tradePermissionManager); + _GAS_PRICE_LIMIT_ = IGasPriceSource(gasPriceSource); _MAINTAINER_ = maintainer; _I_ = i; _K_ = k; - _GAS_PRICE_LIMIT_ = uint256(-1); } // ============ Version Control ============ diff --git a/contracts/DODOVendorMachine/impl/DVMStorage.sol b/contracts/DODOVendorMachine/impl/DVMStorage.sol index e2712f3..dd5e988 100644 --- a/contracts/DODOVendorMachine/impl/DVMStorage.sol +++ b/contracts/DODOVendorMachine/impl/DVMStorage.sol @@ -14,6 +14,7 @@ import {SafeMath} from "../../lib/SafeMath.sol"; import {DODOMath} from "../../lib/DODOMath.sol"; import {DecimalMath} from "../../lib/DecimalMath.sol"; import {IPermissionManager} from "../../lib/PermissionManager.sol"; +import {IGasPriceSource} from "../../lib/GasPriceSource.sol"; import {IFeeRateModel} from "../../intf/IFeeRateModel.sol"; import {DVMVault} from "./DVMVault.sol"; @@ -22,7 +23,7 @@ contract DVMStorage is InitializableOwnable, ReentrancyGuard { // ============ Variables for Control ============ - uint256 public _GAS_PRICE_LIMIT_; + IGasPriceSource public _GAS_PRICE_LIMIT_; // ============ Advanced Controls ============ @@ -62,6 +63,11 @@ contract DVMStorage is InitializableOwnable, ReentrancyGuard { _; } + modifier limitGasPrice() { + require(tx.gasprice <= _GAS_PRICE_LIMIT_.getGasPrice(), "GAS_PRICE_EXCEED"); + _; + } + // ============ Helper Functions ============ function calculateBase0(uint256 baseAmount, uint256 quoteAmount) public view returns (uint256) { @@ -93,8 +99,8 @@ contract DVMStorage is InitializableOwnable, ReentrancyGuard { _MAINTAINER_ = newMaintainer; } - function setGasPriceLimit(uint256 newGasPriceLimit) external onlyOwner { - _GAS_PRICE_LIMIT_ = newGasPriceLimit; + function setGasPriceSource(address newGasPriceLimitSource) external onlyOwner { + _GAS_PRICE_LIMIT_ = IGasPriceSource(newGasPriceLimitSource); } function setBuy(bool open) external onlyOwner { diff --git a/contracts/DODOVendorMachine/impl/DVMTrader.sol b/contracts/DODOVendorMachine/impl/DVMTrader.sol index 6981e1e..cd79126 100644 --- a/contracts/DODOVendorMachine/impl/DVMTrader.sol +++ b/contracts/DODOVendorMachine/impl/DVMTrader.sol @@ -20,6 +20,7 @@ contract DVMTrader is DVMStorage { function sellBase(address to) external preventReentrant + limitGasPrice isSellAllow(to) returns (uint256 receiveQuoteAmount) { @@ -37,6 +38,7 @@ contract DVMTrader is DVMStorage { function sellQuote(address to) external preventReentrant + limitGasPrice isBuyAllow(to) returns (uint256 receiveBaseAmount) { diff --git a/contracts/DODOVendorMachine/intf/IDVM.sol b/contracts/DODOVendorMachine/intf/IDVM.sol index 854a6dd..cfca4e0 100644 --- a/contracts/DODOVendorMachine/intf/IDVM.sol +++ b/contracts/DODOVendorMachine/intf/IDVM.sol @@ -16,6 +16,7 @@ interface IDVM { address lpFeeRateModel, address mtFeeRateModel, address tradePermissionManager, + address gasPriceSource, uint256 i, uint256 k ) external; diff --git a/contracts/Factory/DVMFactory.sol b/contracts/Factory/DVMFactory.sol index 1dd6414..a8d4312 100644 --- a/contracts/Factory/DVMFactory.sol +++ b/contracts/Factory/DVMFactory.sol @@ -22,6 +22,8 @@ contract DVMFactory is Ownable { address public _FEE_RATE_MODEL_TEMPLATE_; address public _PERMISSION_MANAGER_TEMPLATE_; + address public _DEFAULT_GAS_PRICE_SOURCE_; + // base -> quote -> DVM address list mapping(address => mapping(address => address[])) _REGISTRY_; @@ -30,13 +32,15 @@ contract DVMFactory is Ownable { address vaultTemplate, address dvmTemplate, address feeRateModelTemplate, - address permissionManagerTemplate + address permissionManagerTemplate, + address defaultGasPriceSource ) public { _CLONE_FACTORY_ = cloneFactory; _VAULT_TEMPLATE_ = vaultTemplate; _DVM_TEMPLATE_ = dvmTemplate; _FEE_RATE_MODEL_TEMPLATE_ = feeRateModelTemplate; _PERMISSION_MANAGER_TEMPLATE_ = permissionManagerTemplate; + _DEFAULT_GAS_PRICE_SOURCE_ = defaultGasPriceSource; } function createStandardDODOVendorMachine( @@ -59,6 +63,7 @@ contract DVMFactory is Ownable { createConstFeeRateModel(msg.sender, lpFeeRate), createConstFeeRateModel(msg.sender, mtFeeRate), createPermissionManager(msg.sender), + _DEFAULT_GAS_PRICE_SOURCE_, i, k ); diff --git a/contracts/lib/GasPriceSource.sol b/contracts/lib/GasPriceSource.sol new file mode 100644 index 0000000..d1a71a5 --- /dev/null +++ b/contracts/lib/GasPriceSource.sol @@ -0,0 +1,29 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {Ownable} from "./Ownable.sol"; + +interface IGasPriceSource { + function setGasPrice(uint256) external; + + function getGasPrice() external view returns (uint256); +} + +contract GasPriceSource is IGasPriceSource, Ownable { + uint256 public _GAS_PRICE_; + + function setGasPrice(uint256 gasPrice) external override { + _GAS_PRICE_ = gasPrice; + } + + function getGasPrice() external override view returns (uint256) { + return _GAS_PRICE_; + } +} diff --git a/test/DVM/funding.test.ts b/test/DVM/funding.test.ts index 93b7625..3fa01fc 100644 --- a/test/DVM/funding.test.ts +++ b/test/DVM/funding.test.ts @@ -143,13 +143,13 @@ describe("Funding", () => { }); describe("sell shares", () => { - it("sell shares", async () => { + it.only("sell shares", async () => { await ctx.Route.methods .depositToDVM(ctx.DVM.options.address, lp, decimalStr("10"), decimalStr("100")) .send(ctx.sendParam(lp)); var vaultShares = await ctx.Vault.methods.balanceOf(lp).call() - var bob = ctx.SpareAccounts[0] - await ctx.DVM.methods.sellShares(bob, vaultShares).send(ctx.sendParam(lp)) + var bob = ctx.SpareAccounts[5] + await ctx.DVM.methods.sellShares(bob, vaultShares, "0x").send(ctx.sendParam(lp)) assert.equal(await ctx.BASE.methods.balanceOf(bob).call(), decimalStr("10")) assert.equal(await ctx.QUOTE.methods.balanceOf(bob).call(), decimalStr("100")) }) diff --git a/test/utils/Contracts.ts b/test/utils/Contracts.ts index f781f46..7964523 100644 --- a/test/utils/Contracts.ts +++ b/test/utils/Contracts.ts @@ -34,6 +34,7 @@ export const DVM_FACTORY_NAME = "DVMFactory" export const SMART_ROUTE_NAME = "SmartRoute" export const CONST_FEE_RATE_MODEL_NAME = "ConstFeeRateModel" export const PERMISSION_MANAGER_NAME = "PermissionManager" +export const GAS_PRICE_SOURCE_NAME = "GasPriceSource" interface ContractJson { abi: any; diff --git a/test/utils/DVMContext.ts b/test/utils/DVMContext.ts index 2f35a1e..02d721b 100644 --- a/test/utils/DVMContext.ts +++ b/test/utils/DVMContext.ts @@ -73,13 +73,16 @@ export class DVMContext { var dvmTemplate = await contracts.newContract(contracts.DVM_NAME) var feeRateModelTemplate = await contracts.newContract(contracts.CONST_FEE_RATE_MODEL_NAME) var permissionManagerTemplate = await contracts.newContract(contracts.PERMISSION_MANAGER_NAME) + var gasPriceSource = await contracts.newContract(contracts.GAS_PRICE_SOURCE_NAME) this.DVMFactory = await contracts.newContract(contracts.DVM_FACTORY_NAME, [cloneFactory.options.address, vaultTemplate.options.address, dvmTemplate.options.address, feeRateModelTemplate.options.address, - permissionManagerTemplate.options.address]) + permissionManagerTemplate.options.address, + gasPriceSource.options.address, + ]) this.BASE = await contracts.newContract( contracts.MINTABLE_ERC20_CONTRACT_NAME, @@ -109,6 +112,7 @@ export class DVMContext { this.Vault = contracts.getContractWithAddress(contracts.DVM_VAULT_NAME, await this.DVM.methods._VAULT_().call()) await this.DVM.methods.setMaintainer(this.Maintainer).send(this.sendParam(this.Deployer)) + await gasPriceSource.methods.setGasPrice(MAX_UINT256).send(this.sendParam(this.Deployer)) console.log(log.blueText("[Init DVM context]")); } From e7923043587110a953dbcbc4ea6622324cc8c6f6 Mon Sep 17 00:00:00 2001 From: owen05 Date: Wed, 11 Nov 2020 17:13:46 +0800 Subject: [PATCH 110/118] dodo route logic fix --- contracts/SmartRoute/SmartSwap.sol | 57 ++++--- contracts/helper/DODOSellHelper.sol | 226 ++++++++++++++++++++++++++++ contracts/intf/IDODO.sol | 81 ++++++++++ contracts/intf/IDODOSellHelper.sol | 14 ++ test/Route/Route.test.ts | 111 ++++---------- test/utils-v1/Context-route.ts | 8 +- test/utils-v1/Contracts.ts | 3 + 7 files changed, 388 insertions(+), 112 deletions(-) create mode 100644 contracts/helper/DODOSellHelper.sol create mode 100644 contracts/intf/IDODO.sol create mode 100644 contracts/intf/IDODOSellHelper.sol diff --git a/contracts/SmartRoute/SmartSwap.sol b/contracts/SmartRoute/SmartSwap.sol index aba2dde..a501ea2 100644 --- a/contracts/SmartRoute/SmartSwap.sol +++ b/contracts/SmartRoute/SmartSwap.sol @@ -12,8 +12,9 @@ import {ExternalCall} from "../lib/ExternalCall.sol"; import {IERC20} from "../intf/IERC20.sol"; import {UniversalERC20} from "../lib/UniversalERC20.sol"; import {SafeMath} from "../lib/SafeMath.sol"; -import {DecimalMath} from "../lib/DecimalMath.sol"; +import {IDODOSellHelper} from "../intf/IDODOSellHelper.sol"; import {ISmartApprove} from "../intf/ISmartApprove.sol"; +import {IDODO} from "../intf/IDODO.sol"; contract SmartSwap is Ownable { @@ -21,11 +22,11 @@ contract SmartSwap is Ownable { using UniversalERC20 for IERC20; using ExternalCall for address; - ISmartApprove public smartApprove; - IERC20 constant ETH_ADDRESS = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); + ISmartApprove public smartApprove; + IDODOSellHelper public dodoSellHelper; - event Swapped( + event OrderHistory( IERC20 indexed fromToken, IERC20 indexed toToken, address indexed sender, @@ -35,8 +36,9 @@ contract SmartSwap is Ownable { event ExternalRecord(address indexed to, address indexed sender); - constructor(address _smartApprove) public { + constructor(address _smartApprove,address _dodoSellHelper) public { smartApprove = ISmartApprove(_smartApprove); + dodoSellHelper = IDODOSellHelper(_dodoSellHelper); } function dodoSwap( @@ -44,40 +46,41 @@ contract SmartSwap is Ownable { IERC20 toToken, uint256 fromTokenAmount, uint256 minReturnAmount, - address[] memory callPairs, - bytes memory callDataConcat, - uint256[] memory starts, - uint256[] memory gasLimitsAndValues + address[] memory dodoPairs, + uint256[] memory directions ) public payable returns (uint256 returnAmount) { require(minReturnAmount > 0, "Min return should be bigger then 0."); - require(callPairs.length > 0, "pairs should exists."); + require(dodoPairs.length > 0, "pairs should exists."); if (fromToken != ETH_ADDRESS) { smartApprove.claimTokens(fromToken, msg.sender, address(this), fromTokenAmount); } - for (uint256 i = 0; i < callPairs.length; i++) { - require(callPairs[i] != address(smartApprove), "Access denied"); - require( - callPairs[i].externalCall( - gasLimitsAndValues[i] & ((1 << 128) - 1), - callDataConcat, - starts[i], - starts[i + 1] - starts[i], - gasLimitsAndValues[i] >> 128 - ),"Swap Transaction Error!" - ); + for (uint256 i = 0; i < dodoPairs.length; i++) { + uint256 curDirection = directions[i]; + address curDodoPair = dodoPairs[i]; + if(curDirection == 0){ + address curDodoBase = IDODO(curDodoPair)._BASE_TOKEN_(); + uint256 curAmountIn = IERC20(curDodoBase).balanceOf(address(this)); + IERC20(curDodoBase).approve(curDodoPair,curAmountIn); + IDODO(curDodoPair).sellBaseToken(curAmountIn, 0, ""); + }else { + address curDodoQuote = IDODO(curDodoPair)._QUOTE_TOKEN_(); + uint256 curAmountIn = IERC20(curDodoQuote).balanceOf(address(this)); + IERC20(curDodoQuote).approve(curDodoPair,curAmountIn); + uint256 canBuyBaseAmount = dodoSellHelper.querySellQuoteToken(curDodoPair,curAmountIn); + IDODO(curDodoPair).buyBaseToken(canBuyBaseAmount, curAmountIn, ""); + } } - fromToken.universalTransfer(msg.sender, fromToken.universalBalanceOf(address(this))); returnAmount = toToken.universalBalanceOf(address(this)); require(returnAmount >= minReturnAmount, "Return amount is not enough"); toToken.universalTransfer(msg.sender, returnAmount); - emit Swapped(fromToken, toToken, msg.sender, fromTokenAmount, returnAmount); + emit OrderHistory(fromToken, toToken, msg.sender, fromTokenAmount, returnAmount); } - //TODO:change + function externalSwap( IERC20 fromToken, IERC20 toToken, @@ -100,16 +103,12 @@ contract SmartSwap is Ownable { require(success, "Contract Swap execution Failed"); - // Return back all unswapped fromToken.universalTransfer(msg.sender, fromToken.universalBalanceOf(address(this))); - returnAmount = toToken.universalBalanceOf(address(this)); require(returnAmount >= minReturnAmount, "Return amount is not enough"); toToken.universalTransfer(msg.sender, returnAmount); - - emit Swapped(fromToken, toToken, msg.sender, fromTokenAmount, returnAmount); - + emit OrderHistory(fromToken, toToken, msg.sender, fromTokenAmount, returnAmount); emit ExternalRecord(to, msg.sender); } } diff --git a/contracts/helper/DODOSellHelper.sol b/contracts/helper/DODOSellHelper.sol new file mode 100644 index 0000000..2a41e92 --- /dev/null +++ b/contracts/helper/DODOSellHelper.sol @@ -0,0 +1,226 @@ +/** + *Submitted for verification at Etherscan.io on 2020-10-10 +*/ + +// File: contracts/intf/IDODO.sol + +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {IDODO} from "../intf/IDODO.sol"; +import {SafeMath} from "../lib/SafeMath.sol"; +import {DecimalMath} from "../lib/DecimalMath.sol"; +// import {DODOMath} from "../lib/DODOMath.sol"; + + +library DODOMath { + using SafeMath for uint256; + + /* + Integrate dodo curve fron V1 to V2 + require V0>=V1>=V2>0 + res = (1-k)i(V1-V2)+ikV0*V0(1/V2-1/V1) + let V1-V2=delta + res = i*delta*(1-k+k(V0^2/V1/V2)) + */ + function _GeneralIntegrate( + uint256 V0, + uint256 V1, + uint256 V2, + uint256 i, + uint256 k + ) internal pure returns (uint256) { + uint256 fairAmount = DecimalMath.mul(i, V1.sub(V2)); // i*delta + uint256 V0V0V1V2 = DecimalMath.divCeil(V0.mul(V0).div(V1), V2); + uint256 penalty = DecimalMath.mul(k, V0V0V1V2); // k(V0^2/V1/V2) + return DecimalMath.mul(fairAmount, DecimalMath.ONE.sub(k).add(penalty)); + } + + /* + The same with integration expression above, we have: + i*deltaB = (Q2-Q1)*(1-k+kQ0^2/Q1/Q2) + Given Q1 and deltaB, solve Q2 + This is a quadratic function and the standard version is + aQ2^2 + bQ2 + c = 0, where + a=1-k + -b=(1-k)Q1-kQ0^2/Q1+i*deltaB + c=-kQ0^2 + and Q2=(-b+sqrt(b^2+4(1-k)kQ0^2))/2(1-k) + note: another root is negative, abondan + if deltaBSig=true, then Q2>Q1 + if deltaBSig=false, then Q2= kQ02Q1) { + b = b.sub(kQ02Q1); + minusbSig = true; + } else { + b = kQ02Q1.sub(b); + minusbSig = false; + } + + // calculate sqrt + uint256 squareRoot = DecimalMath.mul( + DecimalMath.ONE.sub(k).mul(4), + DecimalMath.mul(k, Q0).mul(Q0) + ); // 4(1-k)kQ0^2 + squareRoot = b.mul(b).add(squareRoot).sqrt(); // sqrt(b*b+4(1-k)kQ0*Q0) + + // final res + uint256 denominator = DecimalMath.ONE.sub(k).mul(2); // 2(1-k) + uint256 numerator; + if (minusbSig) { + numerator = b.add(squareRoot); + } else { + numerator = squareRoot.sub(b); + } + + if (deltaBSig) { + return DecimalMath.divFloor(numerator, denominator); + } else { + return DecimalMath.divCeil(numerator, denominator); + } + } + + /* + Start from the integration function + i*deltaB = (Q2-Q1)*(1-k+kQ0^2/Q1/Q2) + Assume Q2=Q0, Given Q1 and deltaB, solve Q0 + let fairAmount = i*deltaB + */ + function _SolveQuadraticFunctionForTarget( + uint256 V1, + uint256 k, + uint256 fairAmount + ) internal pure returns (uint256 V0) { + // V0 = V1+V1*(sqrt-1)/2k + uint256 sqrt = DecimalMath.divCeil(DecimalMath.mul(k, fairAmount).mul(4), V1); + sqrt = sqrt.add(DecimalMath.ONE).mul(DecimalMath.ONE).sqrt(); + uint256 premium = DecimalMath.divCeil(sqrt.sub(DecimalMath.ONE), k.mul(2)); + // V0 is greater than or equal to V1 according to the solution + return DecimalMath.mul(V1, DecimalMath.ONE.add(premium)); + } +} + + +contract DODOSellHelper { + using SafeMath for uint256; + + enum RStatus {ONE, ABOVE_ONE, BELOW_ONE} + + uint256 constant ONE = 10**18; + + struct DODOState { + uint256 oraclePrice; + uint256 K; + uint256 B; + uint256 Q; + uint256 baseTarget; + uint256 quoteTarget; + RStatus rStatus; + } + + function querySellBaseToken(address dodo, uint256 amount) public view returns (uint256) { + return IDODO(dodo).querySellBaseToken(amount); + } + + function querySellQuoteToken(address dodo, uint256 amount) public view returns (uint256) { + DODOState memory state; + (state.baseTarget, state.quoteTarget) = IDODO(dodo).getExpectedTarget(); + state.rStatus = RStatus(IDODO(dodo)._R_STATUS_()); + state.oraclePrice = IDODO(dodo).getOraclePrice(); + state.Q = IDODO(dodo)._QUOTE_BALANCE_(); + state.B = IDODO(dodo)._BASE_BALANCE_(); + state.K = IDODO(dodo)._K_(); + + uint256 boughtAmount; + // Determine the status (RStatus) and calculate the amount + // based on the state + if (state.rStatus == RStatus.ONE) { + boughtAmount = _ROneSellQuoteToken(amount, state); + } else if (state.rStatus == RStatus.ABOVE_ONE) { + boughtAmount = _RAboveSellQuoteToken(amount, state); + } else { + uint256 backOneBase = state.B.sub(state.baseTarget); + uint256 backOneQuote = state.quoteTarget.sub(state.Q); + if (amount <= backOneQuote) { + boughtAmount = _RBelowSellQuoteToken(amount, state); + } else { + boughtAmount = backOneBase.add( + _ROneSellQuoteToken(amount.sub(backOneQuote), state) + ); + } + } + // Calculate fees + return + DecimalMath.divFloor( + boughtAmount, + DecimalMath.ONE.add(IDODO(dodo)._MT_FEE_RATE_()).add(IDODO(dodo)._LP_FEE_RATE_()) + ); + } + + function _ROneSellQuoteToken(uint256 amount, DODOState memory state) + internal + pure + returns (uint256 receiveBaseToken) + { + uint256 i = DecimalMath.divFloor(ONE, state.oraclePrice); + uint256 B2 = DODOMath._SolveQuadraticFunctionForTrade( + state.baseTarget, + state.baseTarget, + DecimalMath.mul(i, amount), + false, + state.K + ); + return state.baseTarget.sub(B2); + } + + function _RAboveSellQuoteToken(uint256 amount, DODOState memory state) + internal + pure + returns (uint256 receieBaseToken) + { + uint256 i = DecimalMath.divFloor(ONE, state.oraclePrice); + uint256 B2 = DODOMath._SolveQuadraticFunctionForTrade( + state.baseTarget, + state.B, + DecimalMath.mul(i, amount), + false, + state.K + ); + return state.B.sub(B2); + } + + function _RBelowSellQuoteToken(uint256 amount, DODOState memory state) + internal + pure + returns (uint256 receiveBaseToken) + { + uint256 Q1 = state.Q.add(amount); + uint256 i = DecimalMath.divFloor(ONE, state.oraclePrice); + return DODOMath._GeneralIntegrate(state.quoteTarget, Q1, state.Q, i, state.K); + } +} \ No newline at end of file diff --git a/contracts/intf/IDODO.sol b/contracts/intf/IDODO.sol new file mode 100644 index 0000000..69d3d66 --- /dev/null +++ b/contracts/intf/IDODO.sol @@ -0,0 +1,81 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + + +interface IDODO { + function init( + address owner, + address supervisor, + address maintainer, + address baseToken, + address quoteToken, + address oracle, + uint256 lpFeeRate, + uint256 mtFeeRate, + uint256 k, + uint256 gasPriceLimit + ) external; + + function transferOwnership(address newOwner) external; + + function claimOwnership() external; + + function sellBaseToken( + uint256 amount, + uint256 minReceiveQuote, + bytes calldata data + ) external returns (uint256); + + function buyBaseToken( + uint256 amount, + uint256 maxPayQuote, + bytes calldata data + ) external returns (uint256); + + function querySellBaseToken(uint256 amount) external view returns (uint256 receiveQuote); + + function queryBuyBaseToken(uint256 amount) external view returns (uint256 payQuote); + + function depositBaseTo(address to, uint256 amount) external returns (uint256); + + function withdrawBase(uint256 amount) external returns (uint256); + + function withdrawAllBase() external returns (uint256); + + function depositQuoteTo(address to, uint256 amount) external returns (uint256); + + function withdrawQuote(uint256 amount) external returns (uint256); + + function withdrawAllQuote() external returns (uint256); + + function _BASE_CAPITAL_TOKEN_() external returns (address); + + function _QUOTE_CAPITAL_TOKEN_() external returns (address); + + function _BASE_TOKEN_() external returns (address); + + function _QUOTE_TOKEN_() external returns (address); + + function _R_STATUS_() external view returns (uint8); + + function _QUOTE_BALANCE_() external view returns (uint256); + + function _BASE_BALANCE_() external view returns (uint256); + + function _K_() external view returns (uint256); + + function _MT_FEE_RATE_() external view returns (uint256); + + function _LP_FEE_RATE_() external view returns (uint256); + + function getExpectedTarget() external view returns (uint256 baseTarget, uint256 quoteTarget); + + function getOraclePrice() external view returns (uint256); +} \ No newline at end of file diff --git a/contracts/intf/IDODOSellHelper.sol b/contracts/intf/IDODOSellHelper.sol new file mode 100644 index 0000000..69fa9b4 --- /dev/null +++ b/contracts/intf/IDODOSellHelper.sol @@ -0,0 +1,14 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +interface IDODOSellHelper { + function querySellQuoteToken(address dodo, uint256 amount) external view returns (uint256); + function querySellBaseToken(address dodo, uint256 amount) external view returns (uint256); +} diff --git a/test/Route/Route.test.ts b/test/Route/Route.test.ts index 011be8d..08823c8 100644 --- a/test/Route/Route.test.ts +++ b/test/Route/Route.test.ts @@ -48,7 +48,6 @@ async function initUSDT_USDC(ctx: DODOContext): Promise { await ctx.approvePair(USDT,USDC,USDT_USDC.options.address,lp); await ctx.mintToken(USDT,USDC,lp, mweiStr("1000"), mweiStr("1000")); - await ctx.mintToken(USDT,USDC,trader, mweiStr("0"), mweiStr("0")); await USDT_USDC.methods .depositBaseTo(lp, mweiStr("1000")) @@ -58,6 +57,7 @@ async function initUSDT_USDC(ctx: DODOContext): Promise { .send(ctx.sendParam(lp)); } + async function initWETH_USDC(ctx: DODOContext): Promise { await ctx.setOraclePrice(ctx.WETH_USDC_ORACLE,mweiStr("450")); lp = ctx.spareAccounts[0]; @@ -81,77 +81,38 @@ async function initWETH_USDC(ctx: DODOContext): Promise { //mock sdk logic async function calcRoute(ctx: DODOContext,fromTokenAmount:string,slippage:number,routes:any[],pairs:any[]) { let swapAmount = fromTokenAmount + let directions:number[] = [] + let dodoPairs:string[] = [] + - let callPairs: string[] = [] - let datas: string = "" - let starts: number[] = [] - let gAndV: number[] = [] for (let i = 0; i < pairs.length; i++) { - if(i == 0){ - starts.push(0); - } let curPair = pairs[i] - let curContact =pairs[i].pairContract; - let curData = ''; - let curApproveData = ''; - + dodoPairs.push(curPair.pair) + let curContact = pairs[i].pairContract if (curPair.base === routes[i].address) { - curApproveData = await pairs[i].baseContract.methods.approve(curPair.pair,swapAmount).encodeABI() - curApproveData = curApproveData.substring(2,curApproveData.length) - datas += curApproveData - starts.push(datas.length/2) - gAndV.push(0) - callPairs.push(pairs[i].baseContract.options.address); - curData = await curContact.methods.sellBaseToken(swapAmount, 0, "0x").encodeABI() - console.log(i + ":b-for-swapAmount:",swapAmount); + directions[i] = 0; swapAmount = await curContact.methods.querySellBaseToken(swapAmount).call(); - console.log(i + ":a-for-swapAmount:",swapAmount); + console.log(i + "-swapAmount:",swapAmount); } else { - curApproveData = await pairs[i].quoteContract.methods.approve(curPair.pair,swapAmount).encodeABI() - curApproveData = curApproveData.substring(2,curApproveData.length) - datas += curApproveData - starts.push(datas.length/2) - gAndV.push(0) - callPairs.push(pairs[i].quoteContract.options.address); - console.log(i + ":b-for-swapAmount:",swapAmount); - let baseDecimal = await pairs[i].baseContract.methods.decimals().call(); - let quoteDecimal = await pairs[i].quoteContract.methods.decimals().call(); - let curPairDetail = { - B: new BigNumber(await curContact.methods._BASE_BALANCE_().call() / 10 ** baseDecimal), - Q: new BigNumber(await curContact.methods._QUOTE_BALANCE_().call() / 10 ** quoteDecimal), - B0: new BigNumber(await curContact.methods._TARGET_BASE_TOKEN_AMOUNT_().call() / 10 ** baseDecimal), - Q0: new BigNumber(await curContact.methods._TARGET_QUOTE_TOKEN_AMOUNT_().call() / 10 ** quoteDecimal), - RStatus: await curContact.methods._R_STATUS_().call(), - OraclePrice: new BigNumber(await curContact.methods.getOraclePrice().call() / 10 ** (18-baseDecimal + quoteDecimal)), - k: new BigNumber(parseInt(ctx.k) / 1e18), - mtFeeRate: new BigNumber(parseInt(ctx.mtFeeRate) / 1e18), - lpFeeRate: new BigNumber(parseInt(ctx.lpFeeRate) / 1e18) - } - let dodoHelper = new DODOHelper(curPairDetail) - //TODO:2倍? - let tmpQuoteAmount = new BigNumber(swapAmount).multipliedBy(1-0.006).toFixed(0, BigNumber.ROUND_DOWN) - let tmpBaseAmount = dodoHelper.queryBuyQuote(new BigNumber(fromWei(tmpQuoteAmount,'mwei'))).toString(); - curData = await curContact.methods.buyBaseToken(decimalStr(tmpBaseAmount), swapAmount, "0x").encodeABI() - swapAmount = decimalStr(tmpBaseAmount); - console.log(i + ":a-for-swapAmount:",swapAmount); + directions[i] = 1; + swapAmount = await ctx.DODOSellHelper.methods.querySellQuoteToken(curPair.pair,swapAmount).call(); + console.log(i + "-swapAmount:",swapAmount); } - curData = curData.substring(2,curData.length) - datas += curData - starts.push(datas.length/2) - gAndV.push(0) - callPairs.push(curPair.pair) } - datas = "0x" + datas; + let toAmount = new BigNumber(swapAmount).multipliedBy(1-slippage).toFixed(0, BigNumber.ROUND_DOWN) + + console.log("minAmount:",toAmount); + // console.log("dodoPairs",dodoPairs); + // console.log("directions",directions); + return ctx.SmartSwap.methods.dodoSwap( routes[0].address, routes[routes.length-1].address, fromTokenAmount, toAmount, - callPairs, - datas, - starts, - gAndV + dodoPairs, + directions ) } @@ -195,14 +156,12 @@ describe("Trader", () => { pair: ctx.DODO_USDT.options.address, base: ctx.DODO.options.address, /*only for test*/ - pairContract: ctx.DODO_USDT, - baseContract: ctx.DODO, - quoteContract: ctx.USDT + pairContract: ctx.DODO_USDT /**************/ }]; - var tx = await logGas(await calcRoute(ctx,decimalStr('10'),0.1,routes,pairs), ctx.sendParam(trader), "route swap") - // console.log(tx.events['Swapped']); + var tx = await logGas(await calcRoute(ctx,decimalStr('10'),0.1,routes,pairs), ctx.sendParam(trader), "directly swap") + // console.log(tx.events['OrderHistory']); var a_DODO = await ctx.DODO.methods.balanceOf(trader).call() var a_USDT = await ctx.USDT.methods.balanceOf(trader).call() console.log("After DODO:" + fromWei(a_DODO,'ether') + "; USDT:" + fromWei(a_USDT,'mwei')); @@ -235,21 +194,17 @@ describe("Trader", () => { pair: ctx.DODO_USDT.options.address, base: ctx.DODO.options.address, /*only for test*/ - pairContract: ctx.DODO_USDT, - baseContract: ctx.DODO, - quoteContract: ctx.USDT + pairContract: ctx.DODO_USDT /**************/ },{ pair: ctx.USDT_USDC.options.address, base: ctx.USDT.options.address, /*only for test*/ - pairContract: ctx.USDT_USDC, - baseContract: ctx.USDT, - quoteContract: ctx.USDC + pairContract: ctx.USDT_USDC /**************/ }]; - var tx = await logGas(await calcRoute(ctx,decimalStr('10'),0.1,routes,pairs), ctx.sendParam(trader), "route swap") + var tx = await logGas(await calcRoute(ctx,decimalStr('10'),0.1,routes,pairs), ctx.sendParam(trader), "tow hops swap") // console.log(tx.events['Swapped']); var a_DODO = await ctx.DODO.methods.balanceOf(trader).call() var a_USDC = await ctx.USDC.methods.balanceOf(trader).call() @@ -286,30 +241,24 @@ describe("Trader", () => { pair: ctx.DODO_USDT.options.address, base: ctx.DODO.options.address, /*only for test*/ - pairContract: ctx.DODO_USDT, - baseContract: ctx.DODO, - quoteContract: ctx.USDT + pairContract: ctx.DODO_USDT /**************/ },{ pair: ctx.USDT_USDC.options.address, base: ctx.USDT.options.address, /*only for test*/ - pairContract: ctx.USDT_USDC, - baseContract: ctx.USDT, - quoteContract: ctx.USDC + pairContract: ctx.USDT_USDC /**************/ },{ pair: ctx.WETH_USDC.options.address, base: ctx.WETH.options.address, /*only for test*/ - pairContract: ctx.WETH_USDC, - baseContract: ctx.WETH, - quoteContract: ctx.USDC + pairContract: ctx.WETH_USDC /**************/ }]; - var tx = await logGas(await calcRoute(ctx,decimalStr('10'),0.1,routes,pairs), ctx.sendParam(trader), "route swap") - // console.log(tx.events['Swapped']); + var tx = await logGas(await calcRoute(ctx,decimalStr('10'),0.1,routes,pairs), ctx.sendParam(trader), "three hops swap") + console.log(tx.events['TestAmount']); var a_DODO = await ctx.DODO.methods.balanceOf(trader).call() var a_WETH = await ctx.WETH.methods.balanceOf(trader).call() console.log("After DODO:" + fromWei(a_DODO,'ether') + "; WETH:" + fromWei(a_WETH,'ether')); diff --git a/test/utils-v1/Context-route.ts b/test/utils-v1/Context-route.ts index 68a6a02..43761ac 100644 --- a/test/utils-v1/Context-route.ts +++ b/test/utils-v1/Context-route.ts @@ -57,7 +57,6 @@ export class DODOContext { lpFeeRate: string; mtFeeRate: string; k: string; - //token DODO:Contract; USDT:Contract; @@ -73,6 +72,7 @@ export class DODOContext { //SmartRoute SmartSwap: Contract; SmartApprove: Contract; + DODOSellHelper: Contract; constructor() {} @@ -213,13 +213,17 @@ export class DODOContext { .send(this.sendParam(this.Deployer)); await this.WETH_USDC.methods.enableTrading().send(this.sendParam(this.Deployer)); + this.DODOSellHelper = await contracts.newContract( + contracts.DODO_SELL_HELPER + ); + this.SmartApprove = await contracts.newContract( contracts.SMART_APPROVE ); this.SmartSwap = await contracts.newContract( contracts.SMART_SWAP, - [this.SmartApprove.options.address] + [this.SmartApprove.options.address,this.DODOSellHelper.options.address] ); await this.SmartApprove.methods.setSmartSwap(this.SmartSwap.options.address).send(this.sendParam(this.Deployer)); diff --git a/test/utils-v1/Contracts.ts b/test/utils-v1/Contracts.ts index a17f6b2..306f274 100644 --- a/test/utils-v1/Contracts.ts +++ b/test/utils-v1/Contracts.ts @@ -30,6 +30,7 @@ const LockedTokenVault = require(`${jsonPath}LockedTokenVault.json`) /*v1.5*/ const SmartSwap = require(`${jsonPath2}SmartSwap.json`) const SmartApprove = require(`${jsonPath2}SmartApprove.json`) +const DODOSellHelper = require(`${jsonPath2}DODOSellHelper.json`) /******/ import { getDefaultWeb3 } from './EVM'; @@ -53,6 +54,7 @@ export const DODO_MINE_READER_NAME = "DODOMineReader" /*v1.5*/ export const SMART_SWAP = "SmartSwap" export const SMART_APPROVE = "SmartApprove" +export const DODO_SELL_HELPER = "DODOSellHelper" /******/ var contractMap: { [name: string]: any } = {} @@ -73,6 +75,7 @@ contractMap[DODO_MINE_READER_NAME] = DODOMineReader /*v1.5*/ contractMap[SMART_SWAP] = SmartSwap contractMap[SMART_APPROVE] = SmartApprove +contractMap[DODO_SELL_HELPER] = DODOSellHelper /******/ interface ContractJson { From e4d6f42ef66486c03f8519e647a87fe616149103 Mon Sep 17 00:00:00 2001 From: mingda Date: Wed, 11 Nov 2020 23:48:29 +0800 Subject: [PATCH 111/118] use IDVM Vault --- .../DODOVendorMachine/impl/DVMStorage.sol | 4 +- .../DODOVendorMachine/intf/IDVMVault.sol | 54 +++++++++++++++++++ test/DVM/trader.test.ts | 34 ++++++++++-- 3 files changed, 87 insertions(+), 5 deletions(-) diff --git a/contracts/DODOVendorMachine/impl/DVMStorage.sol b/contracts/DODOVendorMachine/impl/DVMStorage.sol index dd5e988..ea67c83 100644 --- a/contracts/DODOVendorMachine/impl/DVMStorage.sol +++ b/contracts/DODOVendorMachine/impl/DVMStorage.sol @@ -16,7 +16,7 @@ import {DecimalMath} from "../../lib/DecimalMath.sol"; import {IPermissionManager} from "../../lib/PermissionManager.sol"; import {IGasPriceSource} from "../../lib/GasPriceSource.sol"; import {IFeeRateModel} from "../../intf/IFeeRateModel.sol"; -import {DVMVault} from "./DVMVault.sol"; +import {IDVMVault} from "../intf/IDVMVault.sol"; contract DVMStorage is InitializableOwnable, ReentrancyGuard { using SafeMath for uint256; @@ -46,7 +46,7 @@ contract DVMStorage is InitializableOwnable, ReentrancyGuard { uint256 public _K_; uint256 public _I_; - DVMVault public _VAULT_; + IDVMVault public _VAULT_; // ============ Modifiers ============ diff --git a/contracts/DODOVendorMachine/intf/IDVMVault.sol b/contracts/DODOVendorMachine/intf/IDVMVault.sol index eba49e2..de8a251 100644 --- a/contracts/DODOVendorMachine/intf/IDVMVault.sol +++ b/contracts/DODOVendorMachine/intf/IDVMVault.sol @@ -14,4 +14,58 @@ interface IDVMVault { address _baseToken, address _quoteToken ) external; + + function _BASE_TOKEN_() external returns (address); + + function _QUOTE_TOKEN_() external returns (address); + + function _BASE_RESERVE_() external returns (address); + + function _QUOTE_RESERVE_() external returns (address); + + function symbol() external returns (string memory); + + function decimals() external returns (uint256); + + function name() external returns (string memory); + + function totalSupply() external returns (uint256); + + function getVaultBalance() external view returns (uint256 baseBalance, uint256 quoteBalance); + + function getVaultReserve() external view returns (uint256 baseReserve, uint256 quoteReserve); + + function getBaseBalance() external view returns (uint256 baseBalance); + + function getQuoteBalance() external view returns (uint256 quoteBalance); + + function getBaseInput() external view returns (uint256 input); + + function getQuoteInput() external view returns (uint256 input); + + function sync() external; + + function transferBaseOut(address to, uint256 amount) external; + + function transferQuoteOut(address to, uint256 amount) external; + + function transfer(address to, uint256 amount) external returns (bool); + + function balanceOf(address owner) external view returns (uint256 balance); + + function shareRatioOf(address owner) external view returns (uint256 shareRatio); + + function transferFrom( + address from, + address to, + uint256 amount + ) external returns (bool); + + function approve(address spender, uint256 amount) external returns (bool); + + function allowance(address owner, address spender) external view returns (uint256); + + function mint(address user, uint256 value) external; + + function burn(address user, uint256 value) external; } diff --git a/test/DVM/trader.test.ts b/test/DVM/trader.test.ts index 1b1b5f3..25bfecc 100644 --- a/test/DVM/trader.test.ts +++ b/test/DVM/trader.test.ts @@ -51,9 +51,6 @@ describe("Trader", () => { }); describe("trade", () => { - // it.only("gas cost", async () => { - // await logGas(ctx.DVM.methods.calculateBase0(decimalStr("200"), decimalStr("1")), ctx.sendParam(trader), "calculate base0") - // }) it("buy & sell", async () => { console.log("BASE0 before buy", await ctx.DVM.methods.getBase0().call()) @@ -119,6 +116,37 @@ describe("Trader", () => { await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), "103733009669408099" ); + + // buy when quoet is not 0 + await logGas(ctx.Route.methods.sellQuoteOnDVM(ctx.DVM.options.address, trader, decimalStr("200"), decimalStr("1")), ctx.sendParam(trader), "buy base token") + console.log("BASE0 after second buy", await ctx.DVM.methods.getBase0().call()) + // trader balances + console.log( + await ctx.BASE.methods.balanceOf(trader).call(), + "12837528824326616018" + ); + console.log( + await ctx.QUOTE.methods.balanceOf(trader).call(), + "703421810640399874603" + ); + // vault balances + console.log( + await ctx.BASE.methods.balanceOf(ctx.Vault.options.address).call(), + "7158622099620899913" + ); + console.log( + await ctx.QUOTE.methods.balanceOf(ctx.Vault.options.address).call(), + "296474456349930717298" + ); + // maintainer balances + console.log( + await ctx.BASE.methods.balanceOf(ctx.Maintainer).call(), + "3849076052484069" + ); + console.log( + await ctx.QUOTE.methods.balanceOf(ctx.Maintainer).call(), + "103733009669408099" + ); }); }); }); From cbc6786ca59904c1492d8bb2a5cdc144333d9626 Mon Sep 17 00:00:00 2001 From: owen05 Date: Thu, 12 Nov 2020 09:43:38 +0800 Subject: [PATCH 112/118] migrations script --- deploy-detail.txt | 8 ++++++++ migrations/2_deploy.js | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 deploy-detail.txt diff --git a/deploy-detail.txt b/deploy-detail.txt new file mode 100644 index 0000000..c728994 --- /dev/null +++ b/deploy-detail.txt @@ -0,0 +1,8 @@ +==================================================== +network type: kovan +Deploy time: 2020/11/12 上午9:38:54 +Deploy type: Smart Route +SmartApprove Address: 0x8D2625d0f1ed3C7E1E506Bf86b4660c1781Fd7C0 +DODOSellHelper Address: 0xbdEae617F2616b45DCB69B287D52940a76035Fe3 +SmartSwap Address: 0xC1632dD29D5c4ac1Cd7b9B7d1e23E91bB092acAC +SmartApprovce setSmartSwap tx: 0x2e641cd363b3c42579308502dbca07e45377032fb52ae5f1acbd0d865d0ce7e3 diff --git a/migrations/2_deploy.js b/migrations/2_deploy.js index 63ed46d..c5949eb 100644 --- a/migrations/2_deploy.js +++ b/migrations/2_deploy.js @@ -1 +1,33 @@ -module.exports = async (deployer, network) => {}; +const fs = require('fs'); +const file = fs.createWriteStream('../deploy-detail.txt'); +let logger = new console.Console(file, file); + +const SmartApprove = artifacts.require("SmartApprove"); +const SmartSwap = artifacts.require("SmartSwap"); +const DODOSellHelper = artifacts.require("DODOSellHelper"); + +const DEPLOY_ROUTE = true; + +module.exports = async (deployer, network) => { + logger.log("===================================================="); + logger.log("network type: " + network); + logger.log("Deploy time: " + new Date().toLocaleString()); + + if (DEPLOY_ROUTE) { + logger.log("Deploy type: Smart Route"); + await deployer.deploy(SmartApprove); + await deployer.deploy(DODOSellHelper); + logger.log("SmartApprove Address: ",SmartApprove.address); + logger.log("DODOSellHelper Address: ",DODOSellHelper.address); + + await deployer.deploy(SmartSwap,SmartApprove.address,DODOSellHelper.address); + logger.log("SmartSwap Address: ",SmartSwap.address); + + const SmartApproveInstance = await SmartApprove.deployed(); + var tx = await SmartApproveInstance.setSmartSwap(SmartSwap.address); + logger.log("SmartApprovce setSmartSwap tx: ",tx.tx); + } +}; + + + From a2ce55f3367e3295f30a12c67cdac11fa84976c9 Mon Sep 17 00:00:00 2001 From: owen05 Date: Thu, 12 Nov 2020 11:38:36 +0800 Subject: [PATCH 113/118] fix --- .gitignore | 1 + migrations/2_deploy.js | 16 +++++++++++++--- test/Route/Route.test.ts | 12 ------------ 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/.gitignore b/.gitignore index 7f476ea..658570c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ .idea build/ +build-v1/ dist/ node_modules/ coverage/ diff --git a/migrations/2_deploy.js b/migrations/2_deploy.js index c5949eb..b32ec7d 100644 --- a/migrations/2_deploy.js +++ b/migrations/2_deploy.js @@ -9,6 +9,13 @@ const DODOSellHelper = artifacts.require("DODOSellHelper"); const DEPLOY_ROUTE = true; module.exports = async (deployer, network) => { + let DODOSellHelperAddress = "" + if(network == 'kovan'){ + DODOSellHelperAddress = "0xbdEae617F2616b45DCB69B287D52940a76035Fe3"; + }else { + DODOSellHelperAddress = ""; + } + logger.log("===================================================="); logger.log("network type: " + network); logger.log("Deploy time: " + new Date().toLocaleString()); @@ -16,11 +23,14 @@ module.exports = async (deployer, network) => { if (DEPLOY_ROUTE) { logger.log("Deploy type: Smart Route"); await deployer.deploy(SmartApprove); - await deployer.deploy(DODOSellHelper); + if(DODOSellHelperAddress == "") { + await deployer.deploy(DODOSellHelper); + DODOSellHelperAddress = DODOSellHelper.address; + } logger.log("SmartApprove Address: ",SmartApprove.address); - logger.log("DODOSellHelper Address: ",DODOSellHelper.address); + logger.log("DODOSellHelper Address: ",DODOSellHelperAddress); - await deployer.deploy(SmartSwap,SmartApprove.address,DODOSellHelper.address); + await deployer.deploy(SmartSwap,SmartApprove.address,DODOSellHelperAddress); logger.log("SmartSwap Address: ",SmartSwap.address); const SmartApproveInstance = await SmartApprove.deployed(); diff --git a/test/Route/Route.test.ts b/test/Route/Route.test.ts index 08823c8..31f0e2b 100644 --- a/test/Route/Route.test.ts +++ b/test/Route/Route.test.ts @@ -155,9 +155,7 @@ describe("Trader", () => { var pairs = [{ pair: ctx.DODO_USDT.options.address, base: ctx.DODO.options.address, - /*only for test*/ pairContract: ctx.DODO_USDT - /**************/ }]; var tx = await logGas(await calcRoute(ctx,decimalStr('10'),0.1,routes,pairs), ctx.sendParam(trader), "directly swap") @@ -193,15 +191,11 @@ describe("Trader", () => { var pairs = [{ pair: ctx.DODO_USDT.options.address, base: ctx.DODO.options.address, - /*only for test*/ pairContract: ctx.DODO_USDT - /**************/ },{ pair: ctx.USDT_USDC.options.address, base: ctx.USDT.options.address, - /*only for test*/ pairContract: ctx.USDT_USDC - /**************/ }]; var tx = await logGas(await calcRoute(ctx,decimalStr('10'),0.1,routes,pairs), ctx.sendParam(trader), "tow hops swap") @@ -240,21 +234,15 @@ describe("Trader", () => { var pairs = [{ pair: ctx.DODO_USDT.options.address, base: ctx.DODO.options.address, - /*only for test*/ pairContract: ctx.DODO_USDT - /**************/ },{ pair: ctx.USDT_USDC.options.address, base: ctx.USDT.options.address, - /*only for test*/ pairContract: ctx.USDT_USDC - /**************/ },{ pair: ctx.WETH_USDC.options.address, base: ctx.WETH.options.address, - /*only for test*/ pairContract: ctx.WETH_USDC - /**************/ }]; var tx = await logGas(await calcRoute(ctx,decimalStr('10'),0.1,routes,pairs), ctx.sendParam(trader), "three hops swap") From 69658fc9fa8d98e4352e51338ab7e60ba8900c48 Mon Sep 17 00:00:00 2001 From: owen05 Date: Thu, 12 Nov 2020 11:43:31 +0800 Subject: [PATCH 114/118] rm build folder --- truffle-config.js | 94 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 truffle-config.js diff --git a/truffle-config.js b/truffle-config.js new file mode 100644 index 0000000..cce2b0e --- /dev/null +++ b/truffle-config.js @@ -0,0 +1,94 @@ +/** + * Use this file to configure your truffle project. It's seeded with some + * common settings for different networks and features like migrations, + * compilation and testing. Uncomment the ones you need or modify + * them to suit your project as necessary. + * + * More information about configuration can be found at: + * + * truffleframework.com/docs/advanced/configuration + * + * To deploy via Infura you'll need a wallet provider (like @truffle/hdwallet-provider) + * to sign your transactions before they're sent to a remote public node. Infura accounts + * are available for free at: infura.io/register. + * + * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate + * public/private key pairs. If you're publishing your code to GitHub make sure you load this + * phrase from a file you've .gitignored so it doesn't accidentally become public. + * + */ + +// const HDWalletProvider = require('@truffle/hdwallet-provider'); +// const infuraKey = "fj4jll3k....."; +// +// const fs = require('fs'); +// const mnemonic = fs.readFileSync(".secret").toString().trim(); +require("ts-node/register"); // eslint-disable-line +require("dotenv-flow").config(); // eslint-disable-line + +var HDWalletProvider = require("truffle-hdwallet-provider"); +var privKey = process.env.privKey; +var infuraId = process.env.infuraId; + +module.exports = { + /** + * Networks define how you connect to your ethereum client and let you set the + * defaults web3 uses to send transactions. If you don't specify one truffle + * will spin up a development blockchain for you on port 9545 when you + * run `develop` or `test`. You can ask a truffle command to use a specific + * network from the command line, e.g + * + * $ truffle test --network + */ + + networks: { + // Useful for testing. The `development` name is special - truffle uses it by default + // if it's defined here and no other network is specified at the command line. + // You should run a client (like ganache-cli, geth or parity) in a separate terminal + // tab if you use this network and you must also set the `host`, `port` and `network_id` + // options below to some value. + // + development: { + host: "127.0.0.1", + port: 8545, + network_id: 5777, + gas: 0xfffffffffff, + gasPrice: 1, + }, + kovan: { + provider: function() { + return new HDWalletProvider(privKey, "https://kovan.infura.io/v3/" + infuraId); + }, + gas: 8000000, + gasPrice: 1000000000, + network_id: 42, + skipDryRun: true + }, + coverage: { + host: "127.0.0.1", + port: 6545, + network_id: 1002, + gas: 0xfffffffffff, + gasPrice: 1, + }, + }, + + // Set default mocha options here, use special reporters etc. + mocha: { + timeout: false, + }, + plugins: ["solidity-coverage"], + // Configure your compilers + compilers: { + solc: { + version: "0.6.9", // Fetch exact version from solc-bin (default: truffle's version) + settings: { + // See the solidity docs for advice about optimization and evmVersion + optimizer: { + enabled: true, + runs: 200, + }, + }, + }, + }, +}; \ No newline at end of file From abd2b8aea29e294372e08c9d651dbdf7046aa536 Mon Sep 17 00:00:00 2001 From: owen05 Date: Fri, 13 Nov 2020 15:48:55 +0800 Subject: [PATCH 115/118] route and wrap and unwrap eth && test --- contracts/DODOVendorMachine/impl/DVM.sol | 4 +- .../DODOVendorMachine/intf/IDVMVault.sol | 4 +- contracts/DODOZoo.sol | 134 ++++++++++++++ contracts/SmartRoute/SmartSwap.sol | 19 +- contracts/helper/CloneFactory.sol | 33 ++++ contracts/helper/NativeOracle.sol | 25 +++ contracts/helper/TestERC20.sol | 74 ++++++++ contracts/helper/TestWETH.sol | 77 ++++++++ deploy-detail.txt | 9 +- migrations/2_deploy.js | 113 +++++++++++- test/Route/Route.test.ts | 167 ++++++++++++++++-- test/utils-v1/Context-route.ts | 16 +- test/utils-v1/Contracts.ts | 2 +- 13 files changed, 643 insertions(+), 34 deletions(-) create mode 100644 contracts/DODOZoo.sol create mode 100644 contracts/helper/CloneFactory.sol create mode 100644 contracts/helper/NativeOracle.sol create mode 100644 contracts/helper/TestERC20.sol create mode 100644 contracts/helper/TestWETH.sol diff --git a/contracts/DODOVendorMachine/impl/DVM.sol b/contracts/DODOVendorMachine/impl/DVM.sol index 4b437ad..e1d598b 100644 --- a/contracts/DODOVendorMachine/impl/DVM.sol +++ b/contracts/DODOVendorMachine/impl/DVM.sol @@ -13,7 +13,7 @@ import {IPermissionManager} from "../../lib/PermissionManager.sol"; import {IGasPriceSource} from "../../lib/GasPriceSource.sol"; import {DVMTrader} from "./DVMTrader.sol"; import {DVMFunding} from "./DVMFunding.sol"; -import {DVMVault} from "./DVMVault.sol"; +import {IDVMVault} from "../intf/IDVMVault.sol"; contract DVM is DVMTrader, DVMFunding { function init( @@ -28,7 +28,7 @@ contract DVM is DVMTrader, DVMFunding { uint256 k ) external { initOwner(owner); - _VAULT_ = DVMVault(vault); + _VAULT_ = IDVMVault(vault); _BASE_TOKEN_ = _VAULT_._BASE_TOKEN_(); _QUOTE_TOKEN_ = _VAULT_._QUOTE_TOKEN_(); _LP_FEE_RATE_MODEL_ = IFeeRateModel(lpFeeRateModel); diff --git a/contracts/DODOVendorMachine/intf/IDVMVault.sol b/contracts/DODOVendorMachine/intf/IDVMVault.sol index de8a251..a310e47 100644 --- a/contracts/DODOVendorMachine/intf/IDVMVault.sol +++ b/contracts/DODOVendorMachine/intf/IDVMVault.sol @@ -19,9 +19,9 @@ interface IDVMVault { function _QUOTE_TOKEN_() external returns (address); - function _BASE_RESERVE_() external returns (address); + function _BASE_RESERVE_() external returns (uint256); - function _QUOTE_RESERVE_() external returns (address); + function _QUOTE_RESERVE_() external returns (uint256); function symbol() external returns (string memory); diff --git a/contracts/DODOZoo.sol b/contracts/DODOZoo.sol new file mode 100644 index 0000000..c47cc10 --- /dev/null +++ b/contracts/DODOZoo.sol @@ -0,0 +1,134 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {Ownable} from "./lib/Ownable.sol"; +import {IDODO} from "./intf/IDODO.sol"; +import {ICloneFactory} from "./helper/CloneFactory.sol"; + + +/** + * @title DODOZoo + * @author DODO Breeder + * + * @notice Register of All DODO + */ +contract DODOZoo is Ownable { + address public _DODO_LOGIC_; + address public _CLONE_FACTORY_; + + address public _DEFAULT_SUPERVISOR_; + + mapping(address => mapping(address => address)) internal _DODO_REGISTER_; + address[] public _DODOs; + + // ============ Events ============ + + event DODOBirth(address newBorn, address baseToken, address quoteToken); + + // ============ Constructor Function ============ + + constructor( + address _dodoLogic, + address _cloneFactory, + address _defaultSupervisor + ) public { + _DODO_LOGIC_ = _dodoLogic; + _CLONE_FACTORY_ = _cloneFactory; + _DEFAULT_SUPERVISOR_ = _defaultSupervisor; + } + + // ============ Admin Function ============ + + function setDODOLogic(address _dodoLogic) external onlyOwner { + _DODO_LOGIC_ = _dodoLogic; + } + + function setCloneFactory(address _cloneFactory) external onlyOwner { + _CLONE_FACTORY_ = _cloneFactory; + } + + function setDefaultSupervisor(address _defaultSupervisor) external onlyOwner { + _DEFAULT_SUPERVISOR_ = _defaultSupervisor; + } + + function removeDODO(address dodo) external onlyOwner { + address baseToken = IDODO(dodo)._BASE_TOKEN_(); + address quoteToken = IDODO(dodo)._QUOTE_TOKEN_(); + require(isDODORegistered(baseToken, quoteToken), "DODO_NOT_REGISTERED"); + _DODO_REGISTER_[baseToken][quoteToken] = address(0); + for (uint256 i = 0; i <= _DODOs.length - 1; i++) { + if (_DODOs[i] == dodo) { + _DODOs[i] = _DODOs[_DODOs.length - 1]; + _DODOs.pop(); + break; + } + } + } + + function addDODO(address dodo) public onlyOwner { + address baseToken = IDODO(dodo)._BASE_TOKEN_(); + address quoteToken = IDODO(dodo)._QUOTE_TOKEN_(); + require(!isDODORegistered(baseToken, quoteToken), "DODO_REGISTERED"); + _DODO_REGISTER_[baseToken][quoteToken] = dodo; + _DODOs.push(dodo); + } + + // ============ Breed DODO Function ============ + + function breedDODO( + address maintainer, + address baseToken, + address quoteToken, + address oracle, + uint256 lpFeeRate, + uint256 mtFeeRate, + uint256 k, + uint256 gasPriceLimit + ) external onlyOwner returns (address newBornDODO) { + require(!isDODORegistered(baseToken, quoteToken), "DODO_REGISTERED"); + newBornDODO = ICloneFactory(_CLONE_FACTORY_).clone(_DODO_LOGIC_); + IDODO(newBornDODO).init( + _OWNER_, + _DEFAULT_SUPERVISOR_, + maintainer, + baseToken, + quoteToken, + oracle, + lpFeeRate, + mtFeeRate, + k, + gasPriceLimit + ); + addDODO(newBornDODO); + emit DODOBirth(newBornDODO, baseToken, quoteToken); + return newBornDODO; + } + + // ============ View Functions ============ + + function isDODORegistered(address baseToken, address quoteToken) public view returns (bool) { + if ( + _DODO_REGISTER_[baseToken][quoteToken] == address(0) && + _DODO_REGISTER_[quoteToken][baseToken] == address(0) + ) { + return false; + } else { + return true; + } + } + + function getDODO(address baseToken, address quoteToken) external view returns (address) { + return _DODO_REGISTER_[baseToken][quoteToken]; + } + + function getDODOs() external view returns (address[] memory) { + return _DODOs; + } +} diff --git a/contracts/SmartRoute/SmartSwap.sol b/contracts/SmartRoute/SmartSwap.sol index a501ea2..78ab7d0 100644 --- a/contracts/SmartRoute/SmartSwap.sol +++ b/contracts/SmartRoute/SmartSwap.sol @@ -15,6 +15,7 @@ import {SafeMath} from "../lib/SafeMath.sol"; import {IDODOSellHelper} from "../intf/IDODOSellHelper.sol"; import {ISmartApprove} from "../intf/ISmartApprove.sol"; import {IDODO} from "../intf/IDODO.sol"; +import {IWETH} from "../intf/IWETH.sol"; contract SmartSwap is Ownable { @@ -25,6 +26,7 @@ contract SmartSwap is Ownable { IERC20 constant ETH_ADDRESS = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); ISmartApprove public smartApprove; IDODOSellHelper public dodoSellHelper; + address payable public _WETH_; event OrderHistory( IERC20 indexed fromToken, @@ -36,9 +38,15 @@ contract SmartSwap is Ownable { event ExternalRecord(address indexed to, address indexed sender); - constructor(address _smartApprove,address _dodoSellHelper) public { + constructor(address _smartApprove,address _dodoSellHelper,address payable _weth) public { smartApprove = ISmartApprove(_smartApprove); dodoSellHelper = IDODOSellHelper(_dodoSellHelper); + _WETH_ = _weth; + } + + + fallback() external payable { + require(msg.sender == _WETH_, "WE_CAN_NOT_SAVED_YOUR_ETH"); } function dodoSwap( @@ -54,6 +62,9 @@ contract SmartSwap is Ownable { if (fromToken != ETH_ADDRESS) { smartApprove.claimTokens(fromToken, msg.sender, address(this), fromTokenAmount); + } else { + require(msg.value == fromTokenAmount, "ETH_AMOUNT_NOT_MATCH"); + IWETH(_WETH_).deposit{value: fromTokenAmount}(); } for (uint256 i = 0; i < dodoPairs.length; i++) { @@ -73,6 +84,12 @@ contract SmartSwap is Ownable { } } fromToken.universalTransfer(msg.sender, fromToken.universalBalanceOf(address(this))); + + if (toToken == ETH_ADDRESS) { + uint256 wethAmount = IWETH(_WETH_).balanceOf(address(this)); + IWETH(_WETH_).withdraw(wethAmount); + } + returnAmount = toToken.universalBalanceOf(address(this)); require(returnAmount >= minReturnAmount, "Return amount is not enough"); diff --git a/contracts/helper/CloneFactory.sol b/contracts/helper/CloneFactory.sol new file mode 100644 index 0000000..fd8f755 --- /dev/null +++ b/contracts/helper/CloneFactory.sol @@ -0,0 +1,33 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +interface ICloneFactory { + function clone(address prototype) external returns (address proxy); +} + +// introduction of proxy mode design: https://docs.openzeppelin.com/upgrades/2.8/ +// minimum implementation of transparent proxy: https://eips.ethereum.org/EIPS/eip-1167 + +contract CloneFactory is ICloneFactory { + function clone(address prototype) external override returns (address proxy) { + bytes20 targetBytes = bytes20(prototype); + assembly { + let clone := mload(0x40) + mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) + mstore(add(clone, 0x14), targetBytes) + mstore( + add(clone, 0x28), + 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000 + ) + proxy := create(0, clone, 0x37) + } + return proxy; + } +} diff --git a/contracts/helper/NativeOracle.sol b/contracts/helper/NativeOracle.sol new file mode 100644 index 0000000..b472960 --- /dev/null +++ b/contracts/helper/NativeOracle.sol @@ -0,0 +1,25 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {Ownable} from "../lib/Ownable.sol"; + + +// Oracle only for test +contract NaiveOracle is Ownable { + uint256 public tokenPrice; + + function setPrice(uint256 newPrice) external onlyOwner { + tokenPrice = newPrice; + } + + function getPrice() external view returns (uint256) { + return tokenPrice; + } +} diff --git a/contracts/helper/TestERC20.sol b/contracts/helper/TestERC20.sol new file mode 100644 index 0000000..a420d04 --- /dev/null +++ b/contracts/helper/TestERC20.sol @@ -0,0 +1,74 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; + +import {SafeMath} from "../lib/SafeMath.sol"; + +contract TestERC20 { + using SafeMath for uint256; + + string public name; + uint8 public decimals; + string public symbol; + + mapping(address => uint256) balances; + mapping(address => mapping(address => uint256)) internal allowed; + + event Transfer(address indexed from, address indexed to, uint256 amount); + event Approval(address indexed owner, address indexed spender, uint256 amount); + + constructor(string memory _name, uint8 _decimals,string memory _symbol) public { + name = _name; + decimals = _decimals; + symbol = _symbol; + } + + function transfer(address to, uint256 amount) public returns (bool) { + require(to != address(0), "TO_ADDRESS_IS_EMPTY"); + require(amount <= balances[msg.sender], "BALANCE_NOT_ENOUGH"); + + balances[msg.sender] = balances[msg.sender].sub(amount); + balances[to] = balances[to].add(amount); + emit Transfer(msg.sender, to, amount); + return true; + } + + function balanceOf(address owner) public view returns (uint256 balance) { + return balances[owner]; + } + + function transferFrom( + address from, + address to, + uint256 amount + ) public returns (bool) { + require(to != address(0), "TO_ADDRESS_IS_EMPTY"); + require(amount <= balances[from], "BALANCE_NOT_ENOUGH"); + require(amount <= allowed[from][msg.sender], "ALLOWANCE_NOT_ENOUGH"); + + balances[from] = balances[from].sub(amount); + balances[to] = balances[to].add(amount); + allowed[from][msg.sender] = allowed[from][msg.sender].sub(amount); + emit Transfer(from, to, amount); + return true; + } + + function approve(address spender, uint256 amount) public returns (bool) { + allowed[msg.sender][spender] = amount; + emit Approval(msg.sender, spender, amount); + return true; + } + + function allowance(address owner, address spender) public view returns (uint256) { + return allowed[owner][spender]; + } + + function mint(address account, uint256 amount) external { + balances[account] = balances[account].add(amount); + } +} diff --git a/contracts/helper/TestWETH.sol b/contracts/helper/TestWETH.sol new file mode 100644 index 0000000..4ebf56c --- /dev/null +++ b/contracts/helper/TestWETH.sol @@ -0,0 +1,77 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; + + +contract WETH9 { + string public name = "Wrapped Ether"; + string public symbol = "WETH"; + uint8 public decimals = 18; + + event Approval(address indexed src, address indexed guy, uint256 wad); + event Transfer(address indexed src, address indexed dst, uint256 wad); + event Deposit(address indexed dst, uint256 wad); + event Withdrawal(address indexed src, uint256 wad); + + mapping(address => uint256) public balanceOf; + mapping(address => mapping(address => uint256)) public allowance; + + fallback() external payable { + deposit(); + } + + receive() external payable { + deposit(); + } + + function deposit() public payable { + balanceOf[msg.sender] += msg.value; + emit Deposit(msg.sender, msg.value); + } + + function withdraw(uint256 wad) public { + require(balanceOf[msg.sender] >= wad); + balanceOf[msg.sender] -= wad; + msg.sender.transfer(wad); + emit Withdrawal(msg.sender, wad); + } + + function totalSupply() public view returns (uint256) { + return address(this).balance; + } + + function approve(address guy, uint256 wad) public returns (bool) { + allowance[msg.sender][guy] = wad; + emit Approval(msg.sender, guy, wad); + return true; + } + + function transfer(address dst, uint256 wad) public returns (bool) { + return transferFrom(msg.sender, dst, wad); + } + + function transferFrom( + address src, + address dst, + uint256 wad + ) public returns (bool) { + require(balanceOf[src] >= wad); + + if (src != msg.sender && allowance[src][msg.sender] != uint256(-1)) { + require(allowance[src][msg.sender] >= wad); + allowance[src][msg.sender] -= wad; + } + + balanceOf[src] -= wad; + balanceOf[dst] += wad; + + Transfer(src, dst, wad); + + return true; + } +} diff --git a/deploy-detail.txt b/deploy-detail.txt index c728994..aaf3713 100644 --- a/deploy-detail.txt +++ b/deploy-detail.txt @@ -1,8 +1,3 @@ ==================================================== -network type: kovan -Deploy time: 2020/11/12 上午9:38:54 -Deploy type: Smart Route -SmartApprove Address: 0x8D2625d0f1ed3C7E1E506Bf86b4660c1781Fd7C0 -DODOSellHelper Address: 0xbdEae617F2616b45DCB69B287D52940a76035Fe3 -SmartSwap Address: 0xC1632dD29D5c4ac1Cd7b9B7d1e23E91bB092acAC -SmartApprovce setSmartSwap tx: 0x2e641cd363b3c42579308502dbca07e45377032fb52ae5f1acbd0d865d0ce7e3 +network type: development +Deploy time: 2020/11/13 下午3:47:21 diff --git a/migrations/2_deploy.js b/migrations/2_deploy.js index b32ec7d..f88306d 100644 --- a/migrations/2_deploy.js +++ b/migrations/2_deploy.js @@ -5,15 +5,25 @@ let logger = new console.Console(file, file); const SmartApprove = artifacts.require("SmartApprove"); const SmartSwap = artifacts.require("SmartSwap"); const DODOSellHelper = artifacts.require("DODOSellHelper"); +const TestERC20 = artifacts.require("TestERC20"); +const NaiveOracle = artifacts.require("NaiveOracle"); +const DODOZoo = artifacts.require("DODOZoo"); -const DEPLOY_ROUTE = true; +const DEPLOY_ROUTE = false; +const DEPLOY_KOVAN_TOKEN = false; -module.exports = async (deployer, network) => { +module.exports = async (deployer, network,accounts) => { let DODOSellHelperAddress = "" + let DODOZooAddress = "" + let WETHAddress = "" if(network == 'kovan'){ DODOSellHelperAddress = "0xbdEae617F2616b45DCB69B287D52940a76035Fe3"; + DODOZooAddress = "0x92230e929a2226b29ed3441ae5524886347c60c8"; + WETHAddress = "0x5eca15b12d959dfcf9c71c59f8b467eb8c6efd0b"; }else { - DODOSellHelperAddress = ""; + DODOSellHelperAddress = "0x533da777aedce766ceae696bf90f8541a4ba80eb"; + DODOZooAddress = "0x3a97247df274a17c59a3bd12735ea3fcdfb49950"; + WETHAddress = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"; } logger.log("===================================================="); @@ -37,6 +47,103 @@ module.exports = async (deployer, network) => { var tx = await SmartApproveInstance.setSmartSwap(SmartSwap.address); logger.log("SmartApprovce setSmartSwap tx: ",tx.tx); } + + if(DEPLOY_KOVAN_TOKEN) { + logger.log("Deploy type: Create Tokens and Trading Pairs"); + await deployer.deploy(TestERC20,"USDC",6,"USDC"); + const USDCAddr = TestERC20.address; + logger.log("USDC Addr: ", USDCAddr); + await deployer.deploy(TestERC20,"USDT",6,"USDT"); + const USDTAddr = TestERC20.address; + logger.log("USDT Addr: ", USDTAddr); + await deployer.deploy(TestERC20,"DODO",18,"DODO"); + const DODOAddr = TestERC20.address; + logger.log("DODO Addr: ", DODOAddr); + await deployer.deploy(TestERC20,"WOO",18,"WOO"); + const WooAddr = TestERC20.address; + logger.log("WOO Addr: ", WooAddr); + const WETHAddr = WETHAddress; + logger.log("WETH Addr: ", WETHAddr); + + let config = { + lpFeeRate: "2000000000000000", + mtFeeRate: "1000000000000000", + k: "100000000000000000", + gasPriceLimit: "100000000000", + }; + + const DODOZooInstance = await DODOZoo.at(DODOZooAddress); + + //USDT-USDC + await deployer.deploy(NaiveOracle); + var USDT_USDC_Oracle = NaiveOracle.address; + await DODOZooInstance.breedDODO( + accounts[0], + USDTAddr, + USDCAddr, + USDT_USDC_Oracle, + config.lpFeeRate, + config.mtFeeRate, + config.k, + config.gasPriceLimit + ); + const USDT_USDC_Addr = await DODOZooInstance.getDODO(USDTAddr,USDCAddr); + logger.log("USDT_USDC_Addr:",USDT_USDC_Addr); + + // DODO-USDT + await deployer.deploy(NaiveOracle); + var DODO_USDT_Oracle = NaiveOracle.address; + await DODOZooInstance.breedDODO( + accounts[0], + DODOAddr, + USDTAddr, + DODO_USDT_Oracle, + config.lpFeeRate, + config.mtFeeRate, + config.k, + config.gasPriceLimit + ); + const DODO_USDT_Addr = await DODOZooInstance.getDODO(DODOAddr,USDTAddr); + logger.log("DODO_USDT_Addr:",DODO_USDT_Addr); + + // //WETH-USDC + await deployer.deploy(NaiveOracle); + var WETH_USDC_Oracle = NaiveOracle.address; + await DODOZooInstance.breedDODO( + accounts[0], + WETHAddr, + USDCAddr, + WETH_USDC_Oracle, + config.lpFeeRate, + config.mtFeeRate, + config.k, + config.gasPriceLimit + ); + const WETH_USDC_Addr = await DODOZooInstance.getDODO(WETHAddr,USDCAddr); + logger.log("WETH_USDC_Addr:",WETH_USDC_Addr); + + //WOO-USDT + await deployer.deploy(NaiveOracle); + var WOO_USDT_Oracle = NaiveOracle.address; + await DODOZooInstance.breedDODO( + accounts[0], + WooAddr, + USDTAddr, + WOO_USDT_Oracle, + config.lpFeeRate, + config.mtFeeRate, + config.k, + config.gasPriceLimit + ); + const WOO_USDT_Addr = await DODOZooInstance.getDODO(WooAddr,USDTAddr); + logger.log("WOO_USDT_Addr:",WOO_USDT_Addr); + + //TODO:ing enableBaseDeposit enableQuoteDeposit enableTrading + //TODO:ing apporve pair to token + //TODO:ing mint to lp + //TODO:ing deposit to Base && quote pool + } + }; diff --git a/test/Route/Route.test.ts b/test/Route/Route.test.ts index 31f0e2b..685cc5d 100644 --- a/test/Route/Route.test.ts +++ b/test/Route/Route.test.ts @@ -26,14 +26,14 @@ async function initDODO_USDT(ctx: DODOContext): Promise { await ctx.approvePair(DODO,USDT,DODO_USDT.options.address,lp); await ctx.approvePair(DODO,USDT,DODO_USDT.options.address,trader); - await ctx.mintToken(DODO,USDT, lp, decimalStr("10000"), mweiStr("1000")); - await ctx.mintToken(DODO,USDT,trader, decimalStr("100"), mweiStr("0")); + await ctx.mintToken(DODO,USDT, lp, decimalStr("10000000"), mweiStr("1000000")); + await ctx.mintToken(DODO,USDT,trader, decimalStr("1000"), mweiStr("0")); await DODO_USDT.methods - .depositBaseTo(lp, decimalStr("10000")) + .depositBaseTo(lp, decimalStr("10000000")) .send(ctx.sendParam(lp)); await DODO_USDT.methods - .depositQuoteTo(lp, mweiStr("1000")) + .depositQuoteTo(lp, mweiStr("1000000")) .send(ctx.sendParam(lp)); } @@ -47,13 +47,13 @@ async function initUSDT_USDC(ctx: DODOContext): Promise { let USDT_USDC = ctx.USDT_USDC; await ctx.approvePair(USDT,USDC,USDT_USDC.options.address,lp); - await ctx.mintToken(USDT,USDC,lp, mweiStr("1000"), mweiStr("1000")); + await ctx.mintToken(USDT,USDC,lp, mweiStr("1000000"), mweiStr("1000000")); await USDT_USDC.methods - .depositBaseTo(lp, mweiStr("1000")) + .depositBaseTo(lp, mweiStr("1000000")) .send(ctx.sendParam(lp)); await USDT_USDC.methods - .depositQuoteTo(lp, mweiStr("1000")) + .depositQuoteTo(lp, mweiStr("1000000")) .send(ctx.sendParam(lp)); } @@ -68,13 +68,14 @@ async function initWETH_USDC(ctx: DODOContext): Promise { let WETH_USDC = ctx.WETH_USDC; await ctx.approvePair(WETH,USDC,WETH_USDC.options.address,lp); - await ctx.mintToken(WETH,USDC,lp, decimalStr("1000"), mweiStr("450000")); + await ctx.mintToken(null,USDC,lp, decimalStr("0"), mweiStr("36000")); + await WETH.methods.deposit().send(ctx.sendParam(lp,'80')); await WETH_USDC.methods - .depositBaseTo(lp, decimalStr("1000")) + .depositBaseTo(lp, decimalStr("80")) .send(ctx.sendParam(lp)); await WETH_USDC.methods - .depositQuoteTo(lp, mweiStr("450000")) + .depositQuoteTo(lp, mweiStr("36000")) .send(ctx.sendParam(lp)); } @@ -89,7 +90,11 @@ async function calcRoute(ctx: DODOContext,fromTokenAmount:string,slippage:number let curPair = pairs[i] dodoPairs.push(curPair.pair) let curContact = pairs[i].pairContract - if (curPair.base === routes[i].address) { + if(routes[i].address == '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE') { + directions[i] = 0; + swapAmount = await curContact.methods.querySellBaseToken(swapAmount).call(); + console.log(i + "-swapAmount:",swapAmount); + }else if (curPair.base === routes[i].address) { directions[i] = 0; swapAmount = await curContact.methods.querySellBaseToken(swapAmount).call(); console.log(i + "-swapAmount:",swapAmount); @@ -257,5 +262,145 @@ describe("Trader", () => { var c_WETH = await ctx.WETH.methods.balanceOf(ctx.SmartSwap.options.address).call() console.log("Contract DODO:" + fromWei(c_DODO,'ether') + "; USDT:" + fromWei(c_USDT,'mwei') + "; USDC:" + fromWei(c_USDC,'mwei') + "; WETH:" + fromWei(c_WETH,'ether')); }); + + + it("ETH to USDT wrap eth and directly swap", async () => { + var b_ETH = await ctx.Web3.eth.getBalance(trader) + var b_WETH = await ctx.WETH.methods.balanceOf(trader).call() + var b_USDC = await ctx.USDC.methods.balanceOf(trader).call() + console.log("Before ETH:" + fromWei(b_ETH,'ether') + "; WETH:" + fromWei(b_WETH,'ether') + "; USDC:" + fromWei(b_USDC,'mwei')); + var b_w_eth = await ctx.Web3.eth.getBalance(ctx.WETH.options.address) + console.log("weth contract Before:" + fromWei(b_w_eth,'ether')) + //set route path + var routes = [{ + address: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", + decimals: 18 + },{ + address: ctx.USDC.options.address, + decimals: 6 + }]; + + var pairs = [{ + pair: ctx.WETH_USDC.options.address, + base: ctx.WETH.options.address, + pairContract: ctx.WETH_USDC + }]; + + var tx = await logGas(await calcRoute(ctx,decimalStr('1'),0.1,routes,pairs), ctx.sendParam(trader,'1'), "wrap eth and directly swap") + var a_ETH = await ctx.Web3.eth.getBalance(trader) + var a_WETH = await ctx.WETH.methods.balanceOf(trader).call() + var a_USDC = await ctx.USDC.methods.balanceOf(trader).call() + console.log("After ETH:" + fromWei(a_ETH,'ether') + "; WETH:" + fromWei(a_WETH,'ether') + "; USDC:" + fromWei(a_USDC,'mwei')); + console.log("===============================================") + var c_ETH = await ctx.Web3.eth.getBalance(ctx.SmartSwap.options.address) + var c_WETH = await ctx.WETH.methods.balanceOf(ctx.SmartSwap.options.address).call() + var c_USDT = await ctx.USDT.methods.balanceOf(ctx.SmartSwap.options.address).call() + var c_USDC = await ctx.USDC.methods.balanceOf(ctx.SmartSwap.options.address).call() + console.log("Contract ETH:" + fromWei(c_ETH,'ether') + "; WETH:" + fromWei(c_WETH,'ether') + "; USDT:" + fromWei(c_USDT,'mwei') + "; USDC:" + fromWei(c_USDC,'mwei')); + var a_w_eth = await ctx.Web3.eth.getBalance(ctx.WETH.options.address) + console.log("weth contract After:" + fromWei(a_w_eth,'ether')) + }); + + + it("ETH to USDT wrap eth and two hops swap", async () => { + var b_ETH = await ctx.Web3.eth.getBalance(trader) + var b_WETH = await ctx.WETH.methods.balanceOf(trader).call() + var b_USDT = await ctx.USDT.methods.balanceOf(trader).call() + console.log("Before ETH:" + fromWei(b_ETH,'ether') + "; WETH:" + fromWei(b_WETH,'ether') + "; USDT:" + fromWei(b_USDT,'mwei')); + var b_w_eth = await ctx.Web3.eth.getBalance(ctx.WETH.options.address) + console.log("weth contract Before:" + fromWei(b_w_eth,'ether')) + //set route path + var routes = [{ + address: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", + decimals: 18 + },{ + address: ctx.USDC.options.address, + decimals: 6 + },{ + address: ctx.USDT.options.address, + decimals: 6 + }]; + + var pairs = [{ + pair: ctx.WETH_USDC.options.address, + base: ctx.WETH.options.address, + pairContract: ctx.WETH_USDC + },{ + pair: ctx.USDT_USDC.options.address, + base: ctx.USDT.options.address, + pairContract: ctx.USDT_USDC + }]; + + var tx = await logGas(await calcRoute(ctx,decimalStr('1'),0.1,routes,pairs), ctx.sendParam(trader,'1'), "wrap eth and tow hops swap") + var a_ETH = await ctx.Web3.eth.getBalance(trader) + var a_WETH = await ctx.WETH.methods.balanceOf(trader).call() + var a_USDT = await ctx.USDT.methods.balanceOf(trader).call() + console.log("After ETH:" + fromWei(a_ETH,'ether') + "; WETH:" + fromWei(a_WETH,'ether') + "; USDT:" + fromWei(a_USDT,'mwei')); + console.log("===============================================") + var c_ETH = await ctx.Web3.eth.getBalance(ctx.SmartSwap.options.address) + var c_WETH = await ctx.WETH.methods.balanceOf(ctx.SmartSwap.options.address).call() + var c_USDT = await ctx.USDT.methods.balanceOf(ctx.SmartSwap.options.address).call() + var c_USDC = await ctx.USDC.methods.balanceOf(ctx.SmartSwap.options.address).call() + console.log("Contract ETH:" + fromWei(c_ETH,'ether') + "; WETH:" + fromWei(c_WETH,'ether') + "; USDT:" + fromWei(c_USDT,'mwei') + "; USDC:" + fromWei(c_USDC,'mwei')); + var a_w_eth = await ctx.Web3.eth.getBalance(ctx.WETH.options.address) + console.log("weth contract After:" + fromWei(a_w_eth,'ether')) + }); + + + it("DODO to ETH unwrap eth and three hops swap", async () => { + var b_DODO = await ctx.DODO.methods.balanceOf(trader).call() + var b_ETH = await ctx.Web3.eth.getBalance(trader) + var b_WETH = await ctx.WETH.methods.balanceOf(trader).call() + console.log("User Before ETH:" + fromWei(b_ETH,'ether') + "; WETH:" + fromWei(b_WETH,'ether') + "; DODO:" + fromWei(b_DODO,'ether')); + var b_w_eth = await ctx.Web3.eth.getBalance(ctx.WETH.options.address) + console.log("weth contract Before:" + fromWei(b_w_eth,'ether')) + + //approve DODO entry + await ctx.DODO.methods.approve(ctx.SmartApprove.options.address,MAX_UINT256).send(ctx.sendParam(trader)) + //set route path + var routes = [{ + address: ctx.DODO.options.address, + decimals: 18 + },{ + address: ctx.USDT.options.address, + decimals: 6 + },{ + address: ctx.USDC.options.address, + decimals: 6 + },{ + address: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", + decimals: 18 + }]; + + var pairs = [{ + pair: ctx.DODO_USDT.options.address, + base: ctx.DODO.options.address, + pairContract: ctx.DODO_USDT + },{ + pair: ctx.USDT_USDC.options.address, + base: ctx.USDT.options.address, + pairContract: ctx.USDT_USDC + },{ + pair: ctx.WETH_USDC.options.address, + base: ctx.WETH.options.address, + pairContract: ctx.WETH_USDC + }]; + + var tx = await logGas(await calcRoute(ctx,decimalStr('1000'),0.1,routes,pairs), ctx.sendParam(trader), "unwrap eth and three hops swap") + var a_ETH = await ctx.Web3.eth.getBalance(trader) + var a_WETH = await ctx.WETH.methods.balanceOf(trader).call() + var a_DODO = await ctx.DODO.methods.balanceOf(trader).call() + console.log("After ETH:" + fromWei(a_ETH,'ether') + "; WETH:" + fromWei(a_WETH,'ether') + "; DODO:" + fromWei(a_DODO,'ether')); + console.log("===============================================") + var c_ETH = await ctx.Web3.eth.getBalance(ctx.SmartSwap.options.address) + var c_WETH = await ctx.WETH.methods.balanceOf(ctx.SmartSwap.options.address).call() + var c_USDT = await ctx.USDT.methods.balanceOf(ctx.SmartSwap.options.address).call() + var c_USDC = await ctx.USDC.methods.balanceOf(ctx.SmartSwap.options.address).call() + var c_DODO = await ctx.DODO.methods.balanceOf(ctx.SmartSwap.options.address).call() + console.log("Contract ETH:" + fromWei(c_ETH,'ether') + "; WETH:" + fromWei(c_WETH,'ether') + "; USDT:" + fromWei(c_USDT,'mwei') + "; USDC:" + fromWei(c_USDC,'mwei') + "; DODO:" + fromWei(c_DODO,"ether")); + var w_eth = await ctx.Web3.eth.getBalance(ctx.WETH.options.address) + console.log("weth contract After:" + fromWei(w_eth,'ether')) + }); + }); }); diff --git a/test/utils-v1/Context-route.ts b/test/utils-v1/Context-route.ts index 43761ac..8e79e6c 100644 --- a/test/utils-v1/Context-route.ts +++ b/test/utils-v1/Context-route.ts @@ -116,9 +116,10 @@ export class DODOContext { ["USDC", 6] ); this.WETH = await contracts.newContract( - contracts.TEST_ERC20_CONTRACT_NAME, - ["WETH", 18] + contracts.WETH_CONTRACT_NAME ); + + //创建交易对 //DODO-USDT this.DODO_USDT_ORACLE = await contracts.newContract( @@ -223,7 +224,7 @@ export class DODOContext { this.SmartSwap = await contracts.newContract( contracts.SMART_SWAP, - [this.SmartApprove.options.address,this.DODOSellHelper.options.address] + [this.SmartApprove.options.address,this.DODOSellHelper.options.address,this.WETH.options.address] ); await this.SmartApprove.methods.setSmartSwap(this.SmartSwap.options.address).send(this.sendParam(this.Deployer)); @@ -247,12 +248,13 @@ export class DODOContext { } async mintToken(tokenBase:Contract,tokenQuote:Contract,to: string, base: string, quote: string) { - await tokenBase.methods.mint(to, base).send(this.sendParam(this.Deployer)); - await tokenQuote.methods - .mint(to,  quote) - .send(this.sendParam(this.Deployer)); + if(tokenBase != null) + await tokenBase.methods.mint(to, base).send(this.sendParam(this.Deployer)); + if(tokenQuote != null) + await tokenQuote.methods.mint(to,  quote).send(this.sendParam(this.Deployer)); } + async approvePair(tokenBase:Contract,tokenQuote:Contract, approveTarget:string,account: string) { await tokenBase.methods .approve(approveTarget, MAX_UINT256) diff --git a/test/utils-v1/Contracts.ts b/test/utils-v1/Contracts.ts index 306f274..b7ddecd 100644 --- a/test/utils-v1/Contracts.ts +++ b/test/utils-v1/Contracts.ts @@ -17,7 +17,6 @@ const CloneFactory = require(`${jsonPath}CloneFactory.json`) const DODO = require(`${jsonPath}DODO.json`) const DODOZoo = require(`${jsonPath}DODOZoo.json`) const DODOEthProxy = require(`${jsonPath}DODOEthProxy.json`) -const WETH = require(`${jsonPath}WETH9.json`) const TestERC20 = require(`${jsonPath}TestERC20.json`) const NaiveOracle = require(`${jsonPath}NaiveOracle.json`) const DODOLpToken = require(`${jsonPath}DODOLpToken.json`) @@ -31,6 +30,7 @@ const LockedTokenVault = require(`${jsonPath}LockedTokenVault.json`) const SmartSwap = require(`${jsonPath2}SmartSwap.json`) const SmartApprove = require(`${jsonPath2}SmartApprove.json`) const DODOSellHelper = require(`${jsonPath2}DODOSellHelper.json`) +const WETH = require(`${jsonPath2}WETH9.json`) /******/ import { getDefaultWeb3 } from './EVM'; From d6143dff09c2edf70ce5fc22d87e94d0776291c1 Mon Sep 17 00:00:00 2001 From: owen05 Date: Fri, 13 Nov 2020 18:07:27 +0800 Subject: [PATCH 116/118] smart route mainnet deploy config --- deploy-detail.txt | 8 ++++++-- migrations/2_deploy.js | 9 +++++---- truffle-config.js | 9 +++++++++ 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/deploy-detail.txt b/deploy-detail.txt index aaf3713..d393539 100644 --- a/deploy-detail.txt +++ b/deploy-detail.txt @@ -1,3 +1,7 @@ ==================================================== -network type: development -Deploy time: 2020/11/13 下午3:47:21 +network type: live +Deploy time: 2020/11/13 下午5:16:25 +Deploy type: Smart Route +SmartApprove Address: 0xe380Ad3181A69BF92133D2feb609867c4adC61eA +DODOSellHelper Address: 0x533da777aedce766ceae696bf90f8541a4ba80eb +SmartSwap Address: 0xc1e152A032130bc7b49A00c78571C858BFc959C5 diff --git a/migrations/2_deploy.js b/migrations/2_deploy.js index f88306d..e3484df 100644 --- a/migrations/2_deploy.js +++ b/migrations/2_deploy.js @@ -9,7 +9,7 @@ const TestERC20 = artifacts.require("TestERC20"); const NaiveOracle = artifacts.require("NaiveOracle"); const DODOZoo = artifacts.require("DODOZoo"); -const DEPLOY_ROUTE = false; +const DEPLOY_ROUTE = true; const DEPLOY_KOVAN_TOKEN = false; module.exports = async (deployer, network,accounts) => { @@ -20,11 +20,12 @@ module.exports = async (deployer, network,accounts) => { DODOSellHelperAddress = "0xbdEae617F2616b45DCB69B287D52940a76035Fe3"; DODOZooAddress = "0x92230e929a2226b29ed3441ae5524886347c60c8"; WETHAddress = "0x5eca15b12d959dfcf9c71c59f8b467eb8c6efd0b"; - }else { + }else if(network == 'live'){ DODOSellHelperAddress = "0x533da777aedce766ceae696bf90f8541a4ba80eb"; DODOZooAddress = "0x3a97247df274a17c59a3bd12735ea3fcdfb49950"; WETHAddress = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"; - } + }else + return; logger.log("===================================================="); logger.log("network type: " + network); @@ -40,7 +41,7 @@ module.exports = async (deployer, network,accounts) => { logger.log("SmartApprove Address: ",SmartApprove.address); logger.log("DODOSellHelper Address: ",DODOSellHelperAddress); - await deployer.deploy(SmartSwap,SmartApprove.address,DODOSellHelperAddress); + await deployer.deploy(SmartSwap,SmartApprove.address,DODOSellHelperAddress,WETHAddress); logger.log("SmartSwap Address: ",SmartSwap.address); const SmartApproveInstance = await SmartApprove.deployed(); diff --git a/truffle-config.js b/truffle-config.js index cce2b0e..563c7c4 100644 --- a/truffle-config.js +++ b/truffle-config.js @@ -64,6 +64,15 @@ module.exports = { network_id: 42, skipDryRun: true }, + live: { + provider: function() { + return new HDWalletProvider(privKey, "https://mainnet.infura.io/v3/" + infuraId); + }, + gas: 4000000, + gasPrice: 50000000000, + network_id: 1, + skipDryRun: true + }, coverage: { host: "127.0.0.1", port: 6545, From c827514ee7565008e65b09d6b1b2c4be123b99fd Mon Sep 17 00:00:00 2001 From: owen05 Date: Sun, 15 Nov 2020 15:37:03 +0800 Subject: [PATCH 117/118] swap fallback fix --- contracts/SmartRoute/SmartSwap.sol | 5 ++--- deploy-detail.txt | 5 +++-- migrations/1_initial_migration.js | 2 +- migrations/2_deploy.js | 14 ++++++++++---- truffle-config.js | 3 ++- 5 files changed, 18 insertions(+), 11 deletions(-) diff --git a/contracts/SmartRoute/SmartSwap.sol b/contracts/SmartRoute/SmartSwap.sol index 78ab7d0..9603d73 100644 --- a/contracts/SmartRoute/SmartSwap.sol +++ b/contracts/SmartRoute/SmartSwap.sol @@ -44,10 +44,9 @@ contract SmartSwap is Ownable { _WETH_ = _weth; } + fallback() external payable {} - fallback() external payable { - require(msg.sender == _WETH_, "WE_CAN_NOT_SAVED_YOUR_ETH"); - } + receive() external payable {} function dodoSwap( IERC20 fromToken, diff --git a/deploy-detail.txt b/deploy-detail.txt index d393539..94504ae 100644 --- a/deploy-detail.txt +++ b/deploy-detail.txt @@ -1,7 +1,8 @@ ==================================================== network type: live -Deploy time: 2020/11/13 下午5:16:25 +Deploy time: 2020/11/15 下午3:25:21 Deploy type: Smart Route SmartApprove Address: 0xe380Ad3181A69BF92133D2feb609867c4adC61eA DODOSellHelper Address: 0x533da777aedce766ceae696bf90f8541a4ba80eb -SmartSwap Address: 0xc1e152A032130bc7b49A00c78571C858BFc959C5 +SmartSwap Address: 0xf40be68442e8bcf900FED714246f99BE556345e7 +SmartApprovce setSmartSwap tx: 0xfd22c5e3ede777d21f0a0d2d8a64ccee584cc43fa2b72113c97360408c974beb diff --git a/migrations/1_initial_migration.js b/migrations/1_initial_migration.js index ee2135d..f389a7e 100644 --- a/migrations/1_initial_migration.js +++ b/migrations/1_initial_migration.js @@ -1,5 +1,5 @@ const Migrations = artifacts.require("Migrations"); module.exports = function(deployer) { - deployer.deploy(Migrations); + // deployer.deploy(Migrations); }; diff --git a/migrations/2_deploy.js b/migrations/2_deploy.js index e3484df..d942ca8 100644 --- a/migrations/2_deploy.js +++ b/migrations/2_deploy.js @@ -16,14 +16,17 @@ module.exports = async (deployer, network,accounts) => { let DODOSellHelperAddress = "" let DODOZooAddress = "" let WETHAddress = "" + let SmartApproveAddress = "" if(network == 'kovan'){ DODOSellHelperAddress = "0xbdEae617F2616b45DCB69B287D52940a76035Fe3"; DODOZooAddress = "0x92230e929a2226b29ed3441ae5524886347c60c8"; WETHAddress = "0x5eca15b12d959dfcf9c71c59f8b467eb8c6efd0b"; + SmartApproveAddress = "0x5627b7DEb3055e1e899003FDca0716b32C382084"; }else if(network == 'live'){ DODOSellHelperAddress = "0x533da777aedce766ceae696bf90f8541a4ba80eb"; DODOZooAddress = "0x3a97247df274a17c59a3bd12735ea3fcdfb49950"; WETHAddress = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"; + SmartApproveAddress = "0xe380Ad3181A69BF92133D2feb609867c4adC61eA"; }else return; @@ -33,18 +36,21 @@ module.exports = async (deployer, network,accounts) => { if (DEPLOY_ROUTE) { logger.log("Deploy type: Smart Route"); - await deployer.deploy(SmartApprove); + if(SmartApprove == ""){ + await deployer.deploy(SmartApprove); + SmartApproveAddress = SmartApprove.address; + } if(DODOSellHelperAddress == "") { await deployer.deploy(DODOSellHelper); DODOSellHelperAddress = DODOSellHelper.address; } - logger.log("SmartApprove Address: ",SmartApprove.address); + logger.log("SmartApprove Address: ",SmartApproveAddress); logger.log("DODOSellHelper Address: ",DODOSellHelperAddress); - await deployer.deploy(SmartSwap,SmartApprove.address,DODOSellHelperAddress,WETHAddress); + await deployer.deploy(SmartSwap,SmartApproveAddress,DODOSellHelperAddress,WETHAddress); logger.log("SmartSwap Address: ",SmartSwap.address); - const SmartApproveInstance = await SmartApprove.deployed(); + const SmartApproveInstance = await SmartApprove.at(SmartApproveAddress); var tx = await SmartApproveInstance.setSmartSwap(SmartSwap.address); logger.log("SmartApprovce setSmartSwap tx: ",tx.tx); } diff --git a/truffle-config.js b/truffle-config.js index 563c7c4..7663c47 100644 --- a/truffle-config.js +++ b/truffle-config.js @@ -65,11 +65,12 @@ module.exports = { skipDryRun: true }, live: { + networkCheckTimeout: 100000, provider: function() { return new HDWalletProvider(privKey, "https://mainnet.infura.io/v3/" + infuraId); }, gas: 4000000, - gasPrice: 50000000000, + gasPrice: 20000000000, network_id: 1, skipDryRun: true }, From bd21a14b5398693ec5ad47e52fed6a8ea1193e9b Mon Sep 17 00:00:00 2001 From: owen05 Date: Mon, 16 Nov 2020 10:54:05 +0800 Subject: [PATCH 118/118] update approve logic --- contracts/SmartRoute/SmartSwap.sol | 8 ++++---- contracts/lib/UniversalERC20.sol | 13 ++++++++++++- deploy-detail.txt | 6 +++--- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/contracts/SmartRoute/SmartSwap.sol b/contracts/SmartRoute/SmartSwap.sol index 9603d73..7896913 100644 --- a/contracts/SmartRoute/SmartSwap.sol +++ b/contracts/SmartRoute/SmartSwap.sol @@ -72,12 +72,12 @@ contract SmartSwap is Ownable { if(curDirection == 0){ address curDodoBase = IDODO(curDodoPair)._BASE_TOKEN_(); uint256 curAmountIn = IERC20(curDodoBase).balanceOf(address(this)); - IERC20(curDodoBase).approve(curDodoPair,curAmountIn); + IERC20(curDodoBase).universalApprove(curDodoPair,curAmountIn); IDODO(curDodoPair).sellBaseToken(curAmountIn, 0, ""); }else { address curDodoQuote = IDODO(curDodoPair)._QUOTE_TOKEN_(); uint256 curAmountIn = IERC20(curDodoQuote).balanceOf(address(this)); - IERC20(curDodoQuote).approve(curDodoPair,curAmountIn); + IERC20(curDodoQuote).universalApprove(curDodoPair,curAmountIn); uint256 canBuyBaseAmount = dodoSellHelper.querySellQuoteToken(curDodoPair,curAmountIn); IDODO(curDodoPair).buyBaseToken(canBuyBaseAmount, curAmountIn, ""); } @@ -112,10 +112,10 @@ contract SmartSwap is Ownable { if (fromToken != ETH_ADDRESS) { smartApprove.claimTokens(fromToken, msg.sender, address(this), fromTokenAmount); - fromToken.approve(approveTarget, fromTokenAmount); + fromToken.universalApprove(approveTarget, fromTokenAmount); } - (bool success, ) = to.call{value: msg.value, gas: gasSwap}(callDataConcat); + (bool success, ) = to.call{value: fromToken == ETH_ADDRESS ? msg.value : 0, gas: gasSwap}(callDataConcat); require(success, "Contract Swap execution Failed"); diff --git a/contracts/lib/UniversalERC20.sol b/contracts/lib/UniversalERC20.sol index 7005a5b..a1208b2 100644 --- a/contracts/lib/UniversalERC20.sol +++ b/contracts/lib/UniversalERC20.sol @@ -43,7 +43,18 @@ library UniversalERC20 { function universalApprove(IERC20 token, address to, uint256 amount) internal { if (token != ZERO_ADDRESS && token != ETH_ADDRESS) { - token.safeApprove(to, amount); + if (amount == 0) { + token.safeApprove(to, 0); + return; + } + + uint256 allowance = token.allowance(address(this), to); + if (allowance < amount) { + if (allowance > 0) { + token.safeApprove(to, 0); + } + token.safeApprove(to, amount); + } } } diff --git a/deploy-detail.txt b/deploy-detail.txt index 94504ae..0f0c76c 100644 --- a/deploy-detail.txt +++ b/deploy-detail.txt @@ -1,8 +1,8 @@ ==================================================== network type: live -Deploy time: 2020/11/15 下午3:25:21 +Deploy time: 2020/11/16 上午10:26:34 Deploy type: Smart Route SmartApprove Address: 0xe380Ad3181A69BF92133D2feb609867c4adC61eA DODOSellHelper Address: 0x533da777aedce766ceae696bf90f8541a4ba80eb -SmartSwap Address: 0xf40be68442e8bcf900FED714246f99BE556345e7 -SmartApprovce setSmartSwap tx: 0xfd22c5e3ede777d21f0a0d2d8a64ccee584cc43fa2b72113c97360408c974beb +SmartSwap Address: 0xcD8392A57ED2fBD6440037E52F176c26dEFc0ba4 +SmartApprovce setSmartSwap tx: 0x35eccc657ee0d473b6e58324123d3da568ce12389fedff914a8dada563b35b3a

w;U|C(lHdlgWo-loE|*gce0(Mh$cyzthe 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�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