diff --git a/.circleci/config.yml b/.circleci/config.yml index 7ba72b0..f2a24b6 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -20,16 +20,16 @@ jobs: # a collection of steps - ./node_modules - run: # Compile name: Compile - command: npx buidler compile + command: npx hardhat compile - run: # Formatting name: Prettier Check command: yarn prettier --check . - run: # Linting name: ESLint - command: yarn eslint . + command: yarn eslint . && yarn lint:sol - run: # Tests - name: Tests using buidler-ganache mainnet fork - command: npx buidler test + name: Tests using hardhat mainnet fork + command: npx hardhat test # - store_artifacts: # for display in Artifacts: https://circleci.com/docs/2.0/artifacts/ # path: coverage # prefix: coverage diff --git a/.gitignore b/.gitignore index b7e3d96..b50720b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ node_modules # local env variables .env -#buidler +#hardhat artifacts/ cache/ diff --git a/.prettierignore b/.prettierignore index fa5fd70..d0e41a6 100644 --- a/.prettierignore +++ b/.prettierignore @@ -2,4 +2,5 @@ #artifacts cache assets -coverage \ No newline at end of file +coverage +contracts/vendor \ No newline at end of file diff --git a/.solhint.json b/.solhint.json index 607a3f5..b979090 100644 --- a/.solhint.json +++ b/.solhint.json @@ -5,8 +5,8 @@ "prettier/prettier": "error", "code-complexity": ["warn", 5], "function-max-lines": ["warn", 40], - "max-states-count": ["warn", 2], - "reason-string": ["error", {"maxLength": 32}], + "max-states-count": ["warn", 3], + "reason-string": ["off", {"maxLength": 32}], "const-name-snakecase": "error", "contract-name-camelcase": "error", "event-name-camelcase": "error", @@ -19,8 +19,8 @@ "visibility-modifier-order": "error", "avoid-call-value": "off", "avoid-low-level-calls": "off", - "compiler-version": ["warn", "0.6.12"], - "func-visibility": ["error", {"ignoreConstructors": false}], + "compiler-version": ["warn", "0.7.4"], + "func-visibility": ["error", {"ignoreConstructors": true}], "no-inline-assembly": "off", "state-visibility": "error" } diff --git a/.solhintignore b/.solhintignore index 40b878d..f0ab30b 100644 --- a/.solhintignore +++ b/.solhintignore @@ -1 +1,2 @@ -node_modules/ \ No newline at end of file +node_modules/ +contracts/vendor \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 16d9da8..be8b4bb 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,8 @@ { "editor.defaultFormatter": "esbenp.prettier-vscode", // Solidity + "solidity.compileUsingRemoteVersion": "latest", + "solidity.enableLocalNodeCompiler": false, "solidity.formatter": "prettier", "solidity.linter": "solhint", "solidity.packageDefaultDependenciesContractsDirectory": "", diff --git a/README.md b/README.md index 9b32017..abd8b9c 100644 --- a/README.md +++ b/README.md @@ -20,11 +20,11 @@ Furtheremore the following contracts were added to showcase the automation of th - `ProviderModuleDSA`: this is needed for any Gelato integration. It tells Gelato how the execution payload should be formatted. In this prototype, it formats the payload for the `DSA.cast` function. -- `ConnectGelato`: this is a Connector needed for the DSA to be able to submit Tasks to Gelato. In the test suite we unlock the DSA MultiSig Master account at 0xfCD22438AD6eD564a1C26151Df73F6B33B817B56, in order to be able to enable this Connector in our mainnet fork running on the local ganache instance. +- `ConnectGelato`: this is a Connector needed for the DSA to be able to submit Tasks to Gelato. In the test suite we unlock the DSA MultiSig Master account at 0xfCD22438AD6eD564a1C26151Df73F6B33B817B56, in order to be able to enable this Connector in our mainnet fork running on the local hardhat network instance. To see for yourself check out the [contracts](./contracts) folder and make sure to check out `test/mv-DAI-DSR-Compound.test.js`, to see an end-to-end test showcasing the prototype. To do so follow the steps below: 1. Clone this repo -2. Put your Infura ID in .env +2. Put your Alchemy ID in .env 3. yarn install -4. npx buidler test +4. npx hardhat test diff --git a/contracts/ConditionMakerVaultIsSafe.sol b/contracts/ConditionMakerVaultIsSafe.sol deleted file mode 100644 index 987d9c3..0000000 --- a/contracts/ConditionMakerVaultIsSafe.sol +++ /dev/null @@ -1,106 +0,0 @@ -// "SPDX-License-Identifier: UNLICENSED" -pragma solidity 0.6.12; -pragma experimental ABIEncoderV2; - -import { - GelatoConditionsStandard -} from "@gelatonetwork/core/contracts/conditions/GelatoConditionsStandard.sol"; -import {GelatoBytes} from "./GelatoBytes.sol"; -import "./DSMath.sol"; - -interface IOracleAggregator { - function getMakerTokenPrice(string memory _pair) - external - view - returns (uint256); -} - -interface IVaultResolver { - struct VaultData { - uint256 id; - address owner; - string colType; - uint256 collateral; - uint256 art; - uint256 debt; - uint256 liquidatedCol; - uint256 borrowRate; - uint256 colPrice; - uint256 liquidationRatio; - address vaultAddress; - } - - function getVaultById(uint256 id) external view returns (VaultData memory); -} - -contract ConditionMakerVaultIsSafe is GelatoConditionsStandard, DSMath { - using GelatoBytes for bytes; - - address public oracleAggregator; - - constructor(address _oracleAggregator) public { - oracleAggregator = _oracleAggregator; - } - - function getConditionData( - uint256 _vaultID, - string memory _pair, - uint256 _unSafeLimit - ) public pure virtual returns (bytes memory) { - return abi.encode(_vaultID, _pair, _unSafeLimit); - } - - function ok( - uint256, - bytes calldata _conditionData, - uint256 - ) public view virtual override returns (string memory) { - (uint256 vaultID, string memory pair, uint256 unSafeLimit) = abi.decode( - _conditionData, - (uint256, string, uint256) - ); - - return _isVaultUnSafe(vaultID, pair, unSafeLimit); - } - - function _isVaultUnSafe( - uint256 _vaultID, - string memory _pair, - uint256 _unSafeLimit - ) internal view returns (string memory) { - uint256 latestPriceInRay = _getLatestPrice(_pair); - - IVaultResolver.VaultData memory vault = IVaultResolver( - _getVaultResolverAddress() - ) - .getVaultById(_vaultID); - uint256 colRatio = _vaultCollaterizationRatio( - _wmul(vault.collateral, latestPriceInRay), - vault.debt - ); - if (_unSafeLimit > colRatio) { - return OK; - } - return "NotOKMakerVaultIsSafe"; - } - - function _getVaultResolverAddress() internal pure returns (address) { - return 0x0A7008B38E7015F8C36A49eEbc32513ECA8801E5; - } - - function _vaultCollaterizationRatio(uint256 _col, uint256 _debt) - internal - pure - returns (uint256) - { - return _wdiv(_col, _debt); - } - - function _getLatestPrice(string memory _pair) - internal - view - returns (uint256) - { - return IOracleAggregator(oracleAggregator).getMakerTokenPrice(_pair); - } -} diff --git a/contracts/ConnectGelatoDebtBridge.sol b/contracts/ConnectGelatoDebtBridge.sol deleted file mode 100644 index 006b88b..0000000 --- a/contracts/ConnectGelatoDebtBridge.sol +++ /dev/null @@ -1,506 +0,0 @@ -// "SPDX-License-Identifier: UNLICENSED" -pragma solidity 0.6.12; -pragma experimental ABIEncoderV2; - -import "./IMemoryInterface.sol"; -import "./DSMath.sol"; - -interface ConnectorInterface { - function connectorID() external view returns (uint256 _type, uint256 _id); - - function name() external view returns (string memory); -} - -interface OracleAggregator { - function getMakerTokenPrice(string memory _pair) - external - view - returns (uint256); -} - -interface GelatoGasPriceOracle { - function latestAnswer() external view returns (int256); -} - -interface IMakerResolver { - struct VaultData { - uint256 id; - address owner; - string colType; - uint256 collateral; - uint256 art; - uint256 debt; - uint256 liquidatedCol; - uint256 borrowRate; - uint256 colPrice; - uint256 liquidationRatio; - address vaultAddress; - } - - function getVaultById(uint256 id) external view returns (VaultData memory); -} - -interface ICompoundResolver { - struct CompData { - uint256 tokenPriceInEth; - uint256 tokenPriceInUsd; - uint256 exchangeRateStored; - uint256 balanceOfUser; - uint256 borrowBalanceStoredUser; - uint256 supplyRatePerBlock; - uint256 borrowRatePerBlock; - } - - function getCompoundData(address owner, address[] memory cAddress) - external - view - returns (CompData[] memory); -} - -interface IAaveResolver { - struct AaveTokenData { - uint256 ltv; - uint256 threshold; - bool usageAsCollEnabled; - bool borrowEnabled; - bool stableBorrowEnabled; - bool isActive; - } - - struct AaveUserTokenData { - uint256 tokenPriceInEth; - uint256 tokenPriceInUsd; - uint256 supplyBalance; - uint256 borrowBalance; - uint256 borrowFee; - uint256 supplyRate; - uint256 borrowRate; - uint256 borrowModal; - AaveTokenData aaveTokenData; - } - - struct AaveUserData { - uint256 totalSupplyETH; - uint256 totalCollateralETH; - uint256 totalBorrowsETH; - uint256 totalFeesETH; - uint256 availableBorrowsETH; - uint256 currentLiquidationThreshold; - uint256 ltv; - uint256 healthFactor; - uint256 ethPriceInUsd; - } - - function getPosition(address user, address[] memory tokens) - external - view - returns (AaveUserTokenData[] memory, AaveUserData memory); -} - -abstract contract Helpers is ConnectorInterface, DSMath { - uint256 internal _id; - - /** - * @dev Return ethereum address - */ - function _getAddressETH() internal pure returns (address) { - return 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; // ETH Address - } - - /** - * @dev Return Memory Variable Address - */ - function _getMemoryAddr() internal pure returns (address) { - return 0x8a5419CfC711B2343c17a6ABf4B2bAFaBb06957F; // InstaMemory Address - } - - /** - * @dev Set Uint value in InstaMemory Contract. - */ - function _setUint(uint256 setId, uint256 val) internal { - if (setId != 0) IMemoryInterface(_getMemoryAddr()).setUint(setId, val); - } - - /** - * @dev Get Uint value from InstaMemory Contract. - */ - function _getUint(uint256 getId, uint256 val) - internal - returns (uint256 returnVal) - { - returnVal = getId == 0 - ? val - : IMemoryInterface(_getMemoryAddr()).getUint(getId); - } - - /** - * @dev Connector Details - */ - function connectorID() - public - view - override - returns (uint256 _type, uint256 _iD) - { - (_type, _iD) = (1, _id); // Should put specific value. - } - - function _stringToBytes32(string memory str) - internal - pure - returns (bytes32 result) - { - require(bytes(str).length != 0, "String-Empty"); - // solium-disable-next-line security/no-inline-assembly - assembly { - result := mload(add(str, 32)) - } - } -} - -abstract contract ConnectGelatoDebtBridgeHelpers is Helpers { - function _getMakerResolver() internal pure returns (address) { - return 0x0A7008B38E7015F8C36A49eEbc32513ECA8801E5; - } - - function _getCompoundResolver() internal pure returns (address) { - return 0x1f22D77365d8BFE3b901C33C83C01B584F946617; - } - - function _getAaveResolver() internal pure returns (address) { - return 0xe04Cd009fF68628BC663058dDAA7E5Bf7979BEaF; - } - - function _getGelatoGasPriceOracle() internal pure returns (address) { - return 0x169E633A2D1E6c10dD91238Ba11c4A708dfEF37C; - } - - function _getGasPrice() internal view returns (uint256) { - return - uint256( - GelatoGasPriceOracle(_getGelatoGasPriceOracle()).latestAnswer() - ); - } -} - -abstract contract ConnectGelatoDebtBridgeResolver is - ConnectGelatoDebtBridgeHelpers -{ - mapping(address => address) internal _priceFeeds; - - function getMakerVault(uint256 _vaultID) - public - view - returns (IMakerResolver.VaultData memory) - { - // call maker resolver. - return IMakerResolver(_getMakerResolver()).getVaultById(_vaultID); - } - - function getMakerVaultDebt(uint256 _vaultID) public view returns (uint256) { - return getMakerVault(_vaultID).debt; - } - - function getMakerVaultCollateralBalance(uint256 _vaultID) - public - view - returns (uint256) - { - return getMakerVault(_vaultID).collateral; - } - - function getMakerVaultCollateralType(uint256 _vaultID) - public - view - returns (string memory) - { - return getMakerVault(_vaultID).colType; - } - - function getCompoundData(address _owner, address _cAddress) - public - view - returns (ICompoundResolver.CompData memory) - { - address[] memory cAddressArray; - cAddressArray[0] = _cAddress; - return - ICompoundResolver(_getCompoundResolver()).getCompoundData( - _owner, - cAddressArray - )[0]; - } - - function getCompoundDebt(address _owner, address _cAddress) - public - view - returns (uint256) - { - return getCompoundData(_owner, _cAddress).borrowBalanceStoredUser; - } - - function getCompoundCollateralBalance(address _owner, address _cAddress) - public - view - returns (uint256) - { - return getCompoundData(_owner, _cAddress).balanceOfUser; - } - - function getAaveTokenData(address _owner, address _atoken) - public - view - returns ( - IAaveResolver.AaveUserTokenData memory, - IAaveResolver.AaveUserData memory - ) - { - address[] memory aTokenArray; - aTokenArray[0] = _atoken; - ( - IAaveResolver.AaveUserTokenData[] memory tokensData, - IAaveResolver.AaveUserData memory etherUserData - ) = IAaveResolver(_getAaveResolver()).getPosition(_owner, aTokenArray); - return (tokensData[0], etherUserData); - } - - function getAaveTokenDebt(address _owner, address _atoken) - public - view - returns (uint256) - { - (IAaveResolver.AaveUserTokenData memory tokenData, ) = getAaveTokenData( - _owner, - _atoken - ); - return tokenData.supplyBalance; - } - - function getAaveTokenCollateralBalance(address _owner, address _atoken) - public - view - returns (uint256) - { - (IAaveResolver.AaveUserTokenData memory tokenData, ) = getAaveTokenData( - _owner, - _atoken - ); - return tokenData.borrowBalance; - } -} - -contract ConnectGelatoDebtBridge is ConnectGelatoDebtBridgeResolver { - // Constant name must be in capitalized SNAKE_CASE - // solhint-disable-next-line - string public constant override name = "GelatoDebtBridge-v1.0"; - uint256 public constant GASLIMIT = 1933090 + (19331 * 2); // 1933080 + ~2% (Estimated Value) - address public immutable oracleAggregator; - - constructor(uint256 _iD, address _oracleAggregator) public { - _id = _iD; - oracleAggregator = _oracleAggregator; - } - - /// @notice Write in instaMemory the needed values for doing the refinancing between makerDAO and Compound. - /// @param _vaultID is the id of the makerDAO vault. - /// @param _vaultCollateralizationRatio is the collateralization ratio wanted by the client. - /// @param _compPosCollateralizationRatio is the collateralization ratio wanted by the client. - /// @param _pair crypto currency pair used (collateral token/ borrowed token). - /// @param _getID Id for writting in instaMemory. - /// @param _setID Id for loading from instaMemory. - function debtBridgeMakerToCompound( - uint256 _vaultID, - uint256 _vaultCollateralizationRatio, // should be in ray because maker use ray standard - uint256 _compPosCollateralizationRatio, // should be in wad because compound use wad standard - string memory _pair, - uint256 _getID, - uint256 _setID - ) external payable { - ( - uint256 paybackAmount, - uint256 collateralToWithdraw, - uint256 fees - ) = debtBridgeCompute( - _vaultID, - _vaultCollateralizationRatio, - _compPosCollateralizationRatio, - _pair - ); - - _setUint(100, paybackAmount); - _setUint(101, paybackAmount); // payback maker - _setUint(102, _add(collateralToWithdraw, fees)); // withdraw maker - _setUint(103, collateralToWithdraw); // deposit compound - _setUint(104, paybackAmount); // borrow compound - _setUint(105, fees); // pay the provider - } - - // Price Oracle - - function debtBridgeCompute( - uint256 _vaultID, - uint256 _vaultLiquidationRatio, // should be in ray because maker use ray standard - uint256 _compPosLiquidationRatio, // should be in wad because compound use wad standard - string memory _pair - ) - public - view - returns ( - uint256 paybackAmount, - uint256 collateralToWithdraw, - uint256 fees - ) - { - uint256 latestPrice = _getLatestPrice(_pair); - // uint256 fees = mul(GASLIMIT, wmul(_getGasPrice(), latestPrice)); - fees = _mul(GASLIMIT, _getGasPrice()); - - uint256 debt = getMakerVaultDebt(_vaultID); - uint256 collateral = _wmul( - _sub(getMakerVaultCollateralBalance(_vaultID), fees), - latestPrice - ); - - collateralToWithdraw = wcollateralToWithdraw( - _vaultLiquidationRatio, - _compPosLiquidationRatio, - collateral, - debt, - latestPrice - ); - paybackAmount = wborrowedTokenToPayback( - _vaultLiquidationRatio, - _compPosLiquidationRatio, - collateral, - debt - ); - } - - function _getLatestPrice(string memory _pair) - internal - view - returns (uint256) - { - return OracleAggregator(oracleAggregator).getMakerTokenPrice(_pair); - } - - /// Computation in ray - /// @notice return the amount of collateral we need to withdraw during the debt refinancing in ray standard. - /// @param _p1LiqRatio the liquidation ratio of protocol 1. - /// @param _p2LiqRatio the liquidation ratio of protocol 2. - /// @param _col token1 collateral to put on protocol 1. - /// @param _bor amount of borrowed token2 on protocol 1. - /// @param _colPrice price of the collateral. - /// @return collateral to withdraw in ray standard - function _rcollateralToWithdraw( - uint256 _p1LiqRatio, - uint256 _p2LiqRatio, - uint256 _col, - uint256 _bor, - uint256 _colPrice - ) internal pure returns (uint256) { - return - _rdiv( - _sub( - _col, - _rdiv( - _sub( - _rmul(_p1LiqRatio, _col), - _rmul(_p1LiqRatio, _rmul(_p2LiqRatio, _bor)) - ), - _sub(_p1LiqRatio, _p2LiqRatio) - ) - ), - _colPrice - ); - } - - /// Computation in ray - /// @notice return the amount of borrowed token we need to payback during the debt refinancing in ray standard. - /// @param _p1LiqRatio the liquidation ratio of protocol 1. - /// @param _p2LiqRatio the liquidation ratio of protocol 2. - /// @param _col token1 collateral to put on protocol 1. - /// @param _bor amount of borrowed token2 on protocol 1. - /// @return amount of borrowed token to pay back in ray standard - function _rborrowedTokenToPayback( - uint256 _p1LiqRatio, - uint256 _p2LiqRatio, - uint256 _col, - uint256 _bor - ) internal pure returns (uint256) { - return - _sub( - _bor, - _rmul( - _rdiv(1e18, _p1LiqRatio), - _rdiv( - _sub( - _rmul(_p1LiqRatio, _col), - _rmul(_p1LiqRatio, _rmul(_p2LiqRatio, _bor)) - ), - _sub(_p1LiqRatio, _p2LiqRatio) - ) - ) - ); - } - - /// Computation in wad - /// @notice return the amount of collateral we need to withdraw during the debt refinancing in wad standard. - /// @param _p1LiqRatio the liquidation ratio of protocol 1. - /// @param _p2LiqRatio the liquidation ratio of protocol 2. - /// @param _col token1 collateral to put on protocol 1. - /// @param _bor amount of borrowed token2 on protocol 1. - /// @param _colPrice price of the collateral. - /// @return collateral to withdraw in wad standard - function wcollateralToWithdraw( - uint256 _p1LiqRatio, - uint256 _p2LiqRatio, - uint256 _col, - uint256 _bor, - uint256 _colPrice - ) public pure returns (uint256) { - return - _wdiv( - _sub( - _col, - _wdiv( - _sub( - _wmul(_p1LiqRatio, _col), - _wmul(_p1LiqRatio, _wmul(_p2LiqRatio, _bor)) - ), - _sub(_p1LiqRatio, _p2LiqRatio) - ) - ), - _colPrice - ); - } - - /// Computation in wad - /// @notice return the amount of borrowed token we need to payback during the debt refinancing in wad standard. - /// @param _p1LiqRatio the liquidation ratio of protocol 1. - /// @param _p2LiqRatio the liquidation ratio of protocol 2. - /// @param _col token1 collateral to put on protocol 1. - /// @param _bor amount of borrowed token2 on protocol 1. - /// @return amount of borrowed token to pay back in wad standard - function wborrowedTokenToPayback( - uint256 _p1LiqRatio, - uint256 _p2LiqRatio, - uint256 _col, - uint256 _bor - ) public pure returns (uint256) { - return - _sub( - _bor, - _wmul( - _wdiv(1e18, _p1LiqRatio), - _wdiv( - _sub( - _wmul(_p1LiqRatio, _col), - _wmul(_p1LiqRatio, _wmul(_p2LiqRatio, _bor)) - ), - _sub(_p1LiqRatio, _p2LiqRatio) - ) - ) - ); - } -} diff --git a/contracts/ConnectGelatoProviderPayment.sol b/contracts/ConnectGelatoProviderPayment.sol deleted file mode 100644 index 63955af..0000000 --- a/contracts/ConnectGelatoProviderPayment.sol +++ /dev/null @@ -1,76 +0,0 @@ -// "SPDX-License-Identifier: UNLICENSED" -pragma solidity 0.6.12; - -import "./IMemoryInterface.sol"; -import {IERC20} from "@gelatonetwork/core/contracts/external/IERC20.sol"; - -interface ConnectorInterface { - function connectorID() external view returns (uint256 _type, uint256 _id); - - function name() external view returns (string memory); -} - -abstract contract ConnectGelatoProviderPaymentHelper is ConnectorInterface { - uint256 internal _id; - - function connectorID() - public - view - override - returns (uint256 _type, uint256 _iD) - { - (_type, _iD) = (1, _id); // Should put specific value. - } - - function _getMemoryAddr() internal pure returns (address) { - return 0x8a5419CfC711B2343c17a6ABf4B2bAFaBb06957F; // InstaMemory Address - } - - function _getUint(uint256 _getId, uint256 _val) - internal - returns (uint256 returnVal) - { - returnVal = _getId == 0 - ? _val - : IMemoryInterface(_getMemoryAddr()).getUint(_getId); - } - - function _setUint(uint256 setId, uint256 val) internal { - if (setId != 0) IMemoryInterface(_getMemoryAddr()).setUint(setId, val); - } - - function _getAddressETH() internal pure returns (address) { - return 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; // ETH Address - } -} - -contract ConnectGelatoProviderPayment is ConnectGelatoProviderPaymentHelper { - // Constant name must be in capitalized SNAKE_CASE - // solhint-disable-next-line - string public constant override name = "GelatoProviderPayement-v1.0"; - - constructor(uint256 _iD) public { - _id = _iD; - } - - function payProvider( - address _provider, - address _token, - uint256 _amt, - uint256 _getID, - uint256 _setID - ) public payable { - // Desable linter for too long require statement - // solhint-disable-next-line - require( - _provider != address(0x0), - "ConnectGelatoProviderPayment.payProvider:INVALIDADDESS." - ); - uint256 amt = _getUint(_getID, _amt); - if (_token == _getAddressETH()) { - payable(_provider).transfer(amt); - return; - } - IERC20(_token).transfer(_provider, amt); - } -} diff --git a/contracts/DSMath.sol b/contracts/DSMath.sol deleted file mode 100644 index 8aac369..0000000 --- a/contracts/DSMath.sol +++ /dev/null @@ -1,82 +0,0 @@ -// "SPDX-License-Identifier: UNLICENSED" -pragma solidity 0.6.12; - -contract DSMath { - 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"); - } - - function _min(uint256 x, uint256 y) internal pure returns (uint256 z) { - return x <= y ? x : y; - } - - function _max(uint256 x, uint256 y) internal pure returns (uint256 z) { - return x >= y ? x : y; - } - - function _imin(int256 x, int256 y) internal pure returns (int256 z) { - return x <= y ? x : y; - } - - function _imax(int256 x, int256 y) internal pure returns (int256 z) { - return x >= y ? x : y; - } - - uint256 internal constant _WAD = 10**18; - uint256 internal constant _RAY = 10**27; - - //rounds to zero if x*y < _WAD / 2 - function _wmul(uint256 x, uint256 y) internal pure returns (uint256 z) { - z = _add(_mul(x, y), _WAD / 2) / _WAD; - } - - //rounds to zero if x*y < _WAD / 2 - function _rmul(uint256 x, uint256 y) internal pure returns (uint256 z) { - z = _add(_mul(x, y), _RAY / 2) / _RAY; - } - - //rounds to zero if x*y < _WAD / 2 - function _wdiv(uint256 x, uint256 y) internal pure returns (uint256 z) { - z = _add(_mul(x, _WAD), y / 2) / y; - } - - //rounds to zero if x*y < _RAY / 2 - function _rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) { - z = _add(_mul(x, _RAY), y / 2) / y; - } - - // This famous algorithm is called "exponentiation by squaring" - // and calculates x^n with x as fixed-point and n as regular unsigned. - // - // It's O(log n), instead of O(n) for naive repeated _multiplication. - // - // These facts are why it works: - // - // If n is even, then x^n = (x^2)^(n/2). - // If n is odd, then x^n = x * x^(n-1), - // and applying the equation for even x gives - // x^n = x * (x^2)^((n-1) / 2). - // - // Also, EVM division is flooring and - // floor[(n-1) / 2] = floor[n / 2]. - // - function _rpow(uint256 x, uint256 n) internal pure returns (uint256 z) { - z = n % 2 != 0 ? x : _RAY; - - for (n /= 2; n != 0; n /= 2) { - x = _rmul(x, x); - - if (n % 2 != 0) { - z = _rmul(z, x); - } - } - } -} diff --git a/contracts/IMemoryInterface.sol b/contracts/IMemoryInterface.sol deleted file mode 100644 index 38549f8..0000000 --- a/contracts/IMemoryInterface.sol +++ /dev/null @@ -1,8 +0,0 @@ -// "SPDX-License-Identifier: UNLICENSED" -pragma solidity 0.6.12; - -interface IMemoryInterface { - function setUint(uint256 _id, uint256 _val) external; - - function getUint(uint256 _id) external returns (uint256); -} diff --git a/contracts/OracleAggregator.sol b/contracts/OracleAggregator.sol deleted file mode 100644 index fae5633..0000000 --- a/contracts/OracleAggregator.sol +++ /dev/null @@ -1,62 +0,0 @@ -// "SPDX-License-Identifier: UNLICENSED" -pragma solidity 0.6.12; -pragma experimental ABIEncoderV2; - -import {Ownable} from "@gelatonetwork/core/contracts/external/Ownable.sol"; -import "./DSMath.sol"; - -interface IMakerPriceFeed { - function read() external view returns (bytes32); -} - -contract OracleAggregatorStorage { - mapping(string => address) public makerOracle; - mapping(string => address) public compoundOracle; - mapping(string => address) public chainlinkOracle; -} - -// 0x729D19f657BD0614b4985Cf1D82531c67569197B for ETH/USD medianizer it return value in wad standard. -contract OracleAggregator is OracleAggregatorStorage, Ownable, DSMath { - bool public mockMode; - uint256 public mockValue; - - constructor() public Ownable() { - mockMode = false; - mockValue = 0; - } - - function mock(bool _mockMode, uint256 _mockValue) public onlyOwner { - mockMode = _mockMode; - mockValue = _mockValue; - } - - function addOracle(string memory _pair, address _oracleAddress) - external - onlyOwner - { - // Desable linter for too long require statement - // solhint-disable-next-line - require( - makerOracle[_pair] == address(0x0), - "OracleAggregator.Maker: Oracle already set." - ); - makerOracle[_pair] = _oracleAddress; - } - - function getMakerTokenPrice(string memory _pair) - external - view - returns (uint256) - { - // Desable linter for too long require statement - // solhint-disable-next-line - require( - makerOracle[_pair] != address(0x0), - "OracleAggregator.getMakerTokenPrice: CurrencyPairNotSupported." - ); - if (mockMode) { - return mockValue; - } - return uint256(IMakerPriceFeed(makerOracle[_pair]).read()); - } -} diff --git a/contracts/ProviderModuleDSA.sol b/contracts/ProviderModuleDSA.sol deleted file mode 100644 index 2855a1c..0000000 --- a/contracts/ProviderModuleDSA.sol +++ /dev/null @@ -1,121 +0,0 @@ -// "SPDX-License-Identifier: UNLICENSED" -pragma solidity 0.6.12; -pragma experimental ABIEncoderV2; - -import { - GelatoProviderModuleStandard -} from "@gelatonetwork/core/contracts/provider_modules/GelatoProviderModuleStandard.sol"; -import { - Task -} from "@gelatonetwork/core/contracts/gelato_core/interfaces/IGelatoCore.sol"; -import "./ConnectGelatoProviderPayment.sol"; - -/// @dev InstaDapp Index -interface IndexInterface { - function connectors(uint256 version) external view returns (address); - - function list() external view returns (address); -} - -/// @dev InstaDapp List -interface ListInterface { - function accountID(address _account) external view returns (uint64); -} - -/// @dev InstaDapp Defi Smart Account wallet -interface AccountInterface { - function version() external view returns (uint256); - - function isAuth(address user) external view returns (bool); - - function shield() external view returns (bool); - - function cast( - address[] calldata _targets, - bytes[] calldata _datas, - address _origin - ) external payable returns (bytes32[] memory responses); -} - -contract ProviderModuleDSA is GelatoProviderModuleStandard { - IndexInterface public immutable index; - address public immutable gelatoCore; - address public immutable connectGelatoProviderPayment; - - constructor( - IndexInterface _index, - address _gelatoCore, - address _connectGelatoProviderPayment - ) public { - index = _index; - gelatoCore = _gelatoCore; - connectGelatoProviderPayment = _connectGelatoProviderPayment; - } - - // ================= GELATO PROVIDER MODULE STANDARD ================ - function isProvided( - address _userProxy, - address, - Task calldata _task - ) external view override returns (string memory) { - // Verify InstaDapp account identity - if (ListInterface(index.list()).accountID(_userProxy) == 0) - return "ProviderModuleDSA.isProvided:InvalidUserProxy"; - - // Is GelatoCore authorized - if (!AccountInterface(_userProxy).isAuth(gelatoCore)) - return "ProviderModuleDSA.isProvided:GelatoCoreNotAuth"; - - return OK; - } - - /// @dev DS PROXY ONLY ALLOWS DELEGATE CALL for single actions, that's why we also use multisend - function execPayload( - uint256, - address, - address _provider, - Task calldata _task, - uint256 - ) external view override returns (bytes memory payload, bool) { - address[] memory targets = new address[](_task.actions.length); - for (uint256 i = 0; i < _task.actions.length; i++) - targets[i] = _task.actions[i].addr; - - bytes[] memory datas = new bytes[](_task.actions.length); - for (uint256 i = 0; i < _task.actions.length; i++) { - if (_task.actions[i].addr == connectGelatoProviderPayment) { - // input the exact address of the provider - datas[i] = _getDelegateCallDataForProviderPaymentConnector( - _provider, - _task.actions[i].data - ); - } else { - datas[i] = _task.actions[i].data; - } - } - - payload = abi.encodeWithSelector( - AccountInterface.cast.selector, - targets, - datas, - gelatoCore - ); - } - - function _getDelegateCallDataForProviderPaymentConnector( - address _provider, - bytes calldata _data - ) internal pure returns (bytes memory) { - (, address token, uint256 amt, uint256 getID, uint256 setID) = abi - .decode(_data[4:], (address, address, uint256, uint256, uint256)); - return - abi.encodeWithSelector( - ConnectGelatoProviderPayment.payProvider.selector, - _provider, - token, - amt, - getID, - setID - ); - } -} diff --git a/contracts/connectors/ConnectGelatoDebtBridgeFromMaker.sol b/contracts/connectors/ConnectGelatoDebtBridgeFromMaker.sol new file mode 100644 index 0000000..a66de99 --- /dev/null +++ b/contracts/connectors/ConnectGelatoDebtBridgeFromMaker.sol @@ -0,0 +1,450 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.7.4; +pragma experimental ABIEncoderV2; + +/* solhint-disable */ + +interface ConnectorInterface { + function connectorID() external view returns (uint256 _type, uint256 _id); + + function name() external view returns (string memory); +} + +interface MemoryInterface { + function setUint(uint256 _id, uint256 _val) external; + + function getUint(uint256 _id) external returns (uint256); +} + +interface GelatoGasPriceOracle { + function latestAnswer() external view returns (int256); +} + +interface IMakerResolver { + struct VaultData { + uint256 id; + address owner; + string colType; + uint256 collateral; + uint256 art; + uint256 debt; + uint256 liquidatedCol; + uint256 borrowRate; + uint256 colPrice; + uint256 liquidationRatio; + address vaultAddress; + } + + function getVaultById(uint256 id) external view returns (VaultData memory); +} + +library GelatoBytes { + function revertWithErrorString( + bytes memory _bytes, + string memory _tracingInfo + ) internal pure { + // 68: 32-location, 32-length, 4-ErrorSelector, UTF-8 err + if (_bytes.length % 32 == 4) { + bytes4 selector; + assembly { + selector := mload(add(0x20, _bytes)) + } + if (selector == 0x08c379a0) { + // Function selector for Error(string) + assembly { + _bytes := add(_bytes, 68) + } + revert(string(abi.encodePacked(_tracingInfo, string(_bytes)))); + } else { + revert( + string(abi.encodePacked(_tracingInfo, "NoErrorSelector")) + ); + } + } else { + revert( + string(abi.encodePacked(_tracingInfo, "UnexpectedReturndata")) + ); + } + } +} + +abstract contract DSMath { + // _add, _sub, _mul to avoid clash with Inline Assembly op naming + 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"); + } + + function min(uint256 x, uint256 y) internal pure returns (uint256 z) { + return x <= y ? x : y; + } + + function max(uint256 x, uint256 y) internal pure returns (uint256 z) { + return x >= y ? x : y; + } + + function imin(int256 x, int256 y) internal pure returns (int256 z) { + return x <= y ? x : y; + } + + function imax(int256 x, int256 y) internal pure returns (int256 z) { + return x >= y ? x : y; + } + + uint256 constant WAD = 10**18; + uint256 constant RAY = 10**27; + + //rounds to zero if x*y < WAD / 2 + function wmul(uint256 x, uint256 y) internal pure returns (uint256 z) { + z = _add(_mul(x, y), WAD / 2) / WAD; + } + + //rounds to zero if x*y < WAD / 2 + function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) { + z = _add(_mul(x, y), RAY / 2) / RAY; + } + + //rounds to zero if x*y < WAD / 2 + function wdiv(uint256 x, uint256 y) internal pure returns (uint256 z) { + z = _add(_mul(x, WAD), y / 2) / y; + } + + //rounds to zero if x*y < RAY / 2 + function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) { + z = _add(_mul(x, RAY), y / 2) / y; + } + + // This famous algorithm is called "exponentiation by squaring" + // and calculates x^n with x as fixed-point and n as regular unsigned. + // + // It's O(log n), instead of O(n) for naive repeated multiplication. + // + // These facts are why it works: + // + // If n is even, then x^n = (x^2)^(n/2). + // If n is odd, then x^n = x * x^(n-1), + // and applying the equation for even x gives + // x^n = x * (x^2)^((n-1) / 2). + // + // Also, EVM division is flooring and + // floor[(n-1) / 2] = floor[n / 2]. + // + function rpow(uint256 x, uint256 n) internal pure returns (uint256 z) { + z = n % 2 != 0 ? x : RAY; + + for (n /= 2; n != 0; n /= 2) { + x = rmul(x, x); + + if (n % 2 != 0) { + z = rmul(z, x); + } + } + } +} + +abstract contract Helpers is ConnectorInterface, DSMath { + uint256 internal __id; + + /** + * @dev Return ethereum address + */ + function getAddressETH() internal pure returns (address) { + return 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; // ETH Address + } + + /** + * @dev Return Memory Variable Address + */ + function getMemoryAddr() internal pure returns (address) { + return 0x8a5419CfC711B2343c17a6ABf4B2bAFaBb06957F; // InstaMemory Address + } + + /** + * @dev Set Uint value in InstaMemory Contract. + */ + function setUint(uint256 setId, uint256 val) internal { + if (setId != 0) MemoryInterface(getMemoryAddr()).setUint(setId, val); + } + + /** + * @dev Get Uint value from InstaMemory Contract. + */ + function getUint(uint256 getId, uint256 val) + internal + returns (uint256 returnVal) + { + returnVal = getId == 0 + ? val + : MemoryInterface(getMemoryAddr()).getUint(getId); + } + + /** + * @dev Connector Details + */ + function connectorID() + public + view + override + returns (uint256 _type, uint256 id) + { + (_type, id) = (1, __id); // Should put specific value. + } + + function stringToBytes32(string memory str) + internal + pure + returns (bytes32 result) + { + require(bytes(str).length != 0, "String-Empty"); + // solium-disable-next-line security/no-inline-assembly + assembly { + result := mload(add(str, 32)) + } + } +} + +/* solhint-enable */ + +abstract contract GelatoHelpers is Helpers { + function _getGelatoGasPriceOracle() internal pure returns (address) { + return 0x169E633A2D1E6c10dD91238Ba11c4A708dfEF37C; + } + + function _getGasPrice() internal view returns (uint256) { + return + uint256( + GelatoGasPriceOracle(_getGelatoGasPriceOracle()).latestAnswer() + ); + } +} + +abstract contract MakerResolver is GelatoHelpers { + function getMakerVault(uint256 _vaultId) + public + view + returns (IMakerResolver.VaultData memory) + { + return IMakerResolver(_getMakerResolver()).getVaultById(_vaultId); + } + + function getMakerVaultDebt(uint256 _vaultId) public view returns (uint256) { + return getMakerVault(_vaultId).debt; + } + + function getMakerVaultCollateralBalance(uint256 _vaultId) + public + view + returns (uint256) + { + return getMakerVault(_vaultId).collateral; + } + + function getMakerVaultCollateralType(uint256 _vaultId) + public + view + returns (string memory) + { + return getMakerVault(_vaultId).colType; + } + + function _getMakerResolver() internal pure returns (address) { + return 0x0A7008B38E7015F8C36A49eEbc32513ECA8801E5; + } +} + +contract ConnectGelatoDebtBridgeFromMaker is MakerResolver { + using GelatoBytes for bytes; + + // solhint-disable-next-line const-name-snakecase + string public constant override name = "GelatoDebtBridge-v1.0"; + uint256 public constant GAS_LIMIT = 1933090 + (19331 * 2); // 1933080 + ~2% (Estimated Value) + + constructor(uint256 _id) { + __id = _id; + } + + /// @notice Saves Data to InstaMemory that can be used for DebtBridge Maker->Compound + /// @dev Use wad for colRatios. The user has no influence over setUint or getUint. + /// @param _vaultId The id of the makerDAO vault. + /// @param _wMinColRatioMaker Min col ratio (wad) on Maker debt position + /// @param _wMinColRatioB Min col ratio (wad) on debt position B (e.g. Compound, Maker, ...) + /// @param _priceOracle The price oracle contract to supply the collateral price + /// e.g. Maker's ETH/USD oracle for ETH collateral pricing. + /// @param _oraclePayload The data for making the staticcall to the oracle's read + /// method e.g. the function selector of MakerOracle's read function. + // @param _getId Id for writting in instaMemory. + // @param _setId Id for loading from instaMemory. + function saveDebtBridgeDataToMemory( + uint256 _vaultId, + uint256 _wMinColRatioMaker, // should be in ray because maker use ray standard + uint256 _wMinColRatioB, // should be in wad because compound use wad standard + address _priceOracle, + bytes calldata _oraclePayload, + uint256, /*_getId,*/ + uint256 /*_setId*/ + ) public virtual { + ( + uint256 wDaiDebtToMove, + uint256 wCollateralToMove, + uint256 gasFeesPaidFromCol + ) = computeDebtBridge( + _vaultId, + _wMinColRatioMaker, + _wMinColRatioB, + _priceOracle, + _oraclePayload + ); + setUint(600, wDaiDebtToMove); // flashloan borrow + setUint(601, wDaiDebtToMove); // payback maker + setUint(602, _add(wCollateralToMove, gasFeesPaidFromCol)); // withdraw maker + setUint(603, wCollateralToMove); // deposit compound + setUint(604, wDaiDebtToMove); // borrow compound + setUint(605, gasFeesPaidFromCol); // pay the Gelato Provider (TO DO: unsafe) + } + + /// @notice Computes values needed for DebtBridge Maker->ProtocolB + /// @dev Use wad for colRatios. + /// @param _vaultId The id of the makerDAO vault. + /// @param _wMinColRatioMaker Min col ratio (wad) on Maker debt position + /// @param _wMinColRatioB Min col ratio (wad) on debt position B (e.g. Compound, Maker, ...) + /// @param _priceOracle The price oracle contract to supply the collateral price + /// e.g. Maker's ETH/USD oracle for ETH collateral pricing. + /// @param _oraclePayload The data for making the staticcall to the oracle's read + /// method e.g. the function selector of MakerOracle's read function. + /// @return wDaiDebtToMove DAI Debt (wad) to: flashBorrow->repay Maker->withdraw from B->flashPayback. + /// @return wCollateralToMove (wad) to: withdraw from Maker and deposit on B. + /// @return gasFeesPaidFromCol Gelato automation-gas-fees paid from user's collateral + // solhint-disable function-max-lines + function computeDebtBridge( + uint256 _vaultId, + uint256 _wMinColRatioMaker, + uint256 _wMinColRatioB, + address _priceOracle, + bytes calldata _oraclePayload + ) + public + view + virtual + returns ( + uint256 wDaiDebtToMove, + uint256 wCollateralToMove, + uint256 gasFeesPaidFromCol + ) + { + uint256 wColPrice; + + // Stack too deep + { + (bool success, bytes memory returndata) = _priceOracle.staticcall( + _oraclePayload + ); + + if (!success) { + returndata.revertWithErrorString( + "ConnectGelatoDebtBridgeFromMaker.computeDebtBridge:oracle:" + ); + } + + wColPrice = abi.decode(returndata, (uint256)); + } + + // TO DO: add fee mechanism for non-ETH collateral debt bridge + // uint256 gasFeesPaidFromCol = _mul(GAS_LIMIT, wmul(_getGasPrice(), latestPrice)); + gasFeesPaidFromCol = _mul(GAS_LIMIT, _getGasPrice()); + + uint256 wPricedCol = wmul( + _sub(getMakerVaultCollateralBalance(_vaultId), gasFeesPaidFromCol), + wColPrice + ); + + uint256 wDaiDebtOnMaker = getMakerVaultDebt(_vaultId); + + wCollateralToMove = wCalcCollateralToWithdraw( + _wMinColRatioMaker, + _wMinColRatioB, + wColPrice, + wPricedCol, + wDaiDebtOnMaker + ); + + wDaiDebtToMove = wCalcDebtToRepay( + _wMinColRatioMaker, + _wMinColRatioB, + wPricedCol, + wDaiDebtOnMaker + ); + } + + /// @notice Compute collateral (wad) to move from Maker to B. + /// @dev TO DO: explain or link to formula paper. + /// @param _wMinColRatioMaker Min col ratio (wad) on Maker debt position + /// @param _wMinColRatioB Min col ratio (wad) on debt position B (e.g. Compound, Maker, ...) + /// @param _wColPrice Price of the collateral (wad) in oracle price units. + /// @param _wPricedCol Collateral to move (wad) valued in oracle price. + /// @param _wDaiDebtOnMaker Amount of DAI (wad) borrowed from Maker. + /// @return collateral to withdraw from A in wad + function wCalcCollateralToWithdraw( + uint256 _wMinColRatioMaker, + uint256 _wMinColRatioB, + uint256 _wColPrice, + uint256 _wPricedCol, + uint256 _wDaiDebtOnMaker + ) public pure virtual returns (uint256) { + return + wdiv( + _sub( + _wPricedCol, + wdiv( + _sub( + wmul(_wMinColRatioMaker, _wPricedCol), + wmul( + _wMinColRatioMaker, + wmul(_wMinColRatioB, _wDaiDebtOnMaker) + ) + ), + _sub(_wMinColRatioMaker, _wMinColRatioB) + ) + ), + _wColPrice + ); + } + + /// @notice Compute debt (wad) to flashBorrow->repay Maker->withdraw from B->flashPayback + /// @dev TO DO: explain or link to formula paper. + /// @param _wMinColRatioMaker Min col ratio (wad) on Maker debt position + /// @param _wMinColRatioB Min col ratio (wad) on debt position B (e.g. Compound, Maker, ...) + /// @param _wPricedCol Collateral to move (wad) valued in oracle price. + /// @param _wDaiDebtOnMaker Amount of DAI (wad) borrowed from Maker. + /// @return amount of borrowed token to pay back in wad + function wCalcDebtToRepay( + uint256 _wMinColRatioMaker, + uint256 _wMinColRatioB, + uint256 _wPricedCol, + uint256 _wDaiDebtOnMaker + ) public pure virtual returns (uint256) { + return + _sub( + _wDaiDebtOnMaker, + wmul( + wdiv(1e18, _wMinColRatioMaker), + wdiv( + _sub( + wmul(_wMinColRatioMaker, _wPricedCol), + wmul( + _wMinColRatioMaker, + wmul(_wMinColRatioB, _wDaiDebtOnMaker) + ) + ), + _sub(_wMinColRatioMaker, _wMinColRatioB) + ) + ) + ); + } +} diff --git a/contracts/connectors/ConnectGelatoProviderPayment.sol b/contracts/connectors/ConnectGelatoProviderPayment.sol new file mode 100644 index 0000000..114911d --- /dev/null +++ b/contracts/connectors/ConnectGelatoProviderPayment.sol @@ -0,0 +1,334 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.7.4; + +/* solhint-disable */ + +interface MemoryInterface { + function setUint(uint256 _id, uint256 _val) external; + + function getUint(uint256 _id) external returns (uint256); +} + +interface ConnectorInterface { + function connectorID() external view returns (uint256 _type, uint256 _id); + + function name() external view returns (string memory); +} + +interface IERC20 { + function transfer(address recipient, uint256 amount) + external + returns (bool); +} + +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + // solhint-disable-next-line no-inline-assembly + assembly { + size := extcodesize(account) + } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require( + address(this).balance >= amount, + "Address: insufficient balance" + ); + + // solhint-disable-next-line avoid-low-level-calls, avoid-call-value + (bool success, ) = recipient.call{value: amount}(""); + require( + success, + "Address: unable to send value, recipient may have reverted" + ); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain`call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) + internal + returns (bytes memory) + { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value + ) internal returns (bytes memory) { + return + functionCallWithValue( + target, + data, + value, + "Address: low-level call with value failed" + ); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value, + string memory errorMessage + ) internal returns (bytes memory) { + require( + address(this).balance >= value, + "Address: insufficient balance for call" + ); + require(isContract(target), "Address: call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.call{value: value}( + data + ); + return _verifyCallResult(success, returndata, errorMessage); + } + + function _verifyCallResult( + bool success, + bytes memory returndata, + string memory errorMessage + ) private pure returns (bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + // solhint-disable-next-line no-inline-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + +library SafeERC20 { + using Address for address; + + function safeTransfer( + IERC20 token, + address to, + uint256 value + ) internal { + _callOptionalReturn( + token, + abi.encodeWithSelector(token.transfer.selector, 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. We use {Address.functionCall} to perform this call, which verifies that + // the target address contains contract code and also asserts for success in the low-level call. + + bytes memory returndata = address(token).functionCall( + data, + "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" + ); + } + } +} + +/* solhint-enable */ + +/* solhint-disable private-vars-leading-underscore */ + +abstract contract Helpers is ConnectorInterface { + uint256 internal __id; + + /** + * @dev Connector Details + */ + function connectorID() + public + view + override + returns (uint256 _type, uint256 id) + { + (_type, id) = (1, __id); // Should put specific value. + } + + /** + * @dev Return ethereum address + */ + function getAddressETH() internal pure returns (address) { + return 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; // ETH Address + } + + /** + * @dev Return Memory Variable Address + */ + function getMemoryAddr() internal pure returns (address) { + return 0x8a5419CfC711B2343c17a6ABf4B2bAFaBb06957F; // InstaMemory Address + } + + /** + * @dev Set Uint value in InstaMemory Contract. + */ + function setUint(uint256 setId, uint256 val) internal { + if (setId != 0) MemoryInterface(getMemoryAddr()).setUint(setId, val); + } + + /** + * @dev Get Uint value from InstaMemory Contract. + */ + function getUint(uint256 getId, uint256 val) + internal + returns (uint256 returnVal) + { + returnVal = getId == 0 + ? val + : MemoryInterface(getMemoryAddr()).getUint(getId); + } +} + +/// @title ConnectGelatoProviderPayment +/// @notice InstaDapp Connector to compensate Gelato automation-gas Providers. +/// @author Gelato Team +contract ConnectGelatoProviderPayment is Helpers { + using Address for address payable; + using SafeERC20 for IERC20; + + // solhint-disable-next-line const-name-snakecase + string public constant override name = "GelatoProviderPayement-v1.0"; + + constructor(uint256 _id) { + __id = _id; + } + + /// @notice Transfers automation gas fees to Gelato Provider + /// @dev Gelato Provider risks: + /// - _getId does not match actual InstaMemory provider payment slot + /// - _token balance not in DSA + /// - worthless _token risk + /// @param _provider The Provider who pays the Gelato network for automation. + // This param should be verified / replaced by the ProviderModule in Gelato on-chain. + // In the latter case, it does not matter what address is passed off-chain. + /// @param _token The token used to pay the Provider. + /// @param _amt The amount of _token to pay the Gelato Provider. + /// @param _getId The InstaMemory slot at which the payment amount was stored. + /// @param _setId The InstaMemory slot to save the provider payout amound in. + function payProvider( + address _provider, + address _token, + uint256 _amt, + uint256 _getId, + uint256 _setId + ) public payable virtual { + require( + _provider != address(0x0), + "ConnectGelatoProviderPayment.payProvider:addr0" + ); + uint256 amt = getUint(_getId, _amt); + setUint(_setId, amt); + _token == getAddressETH() + ? payable(_provider).sendValue(amt) + : IERC20(_token).safeTransfer(_provider, amt); + } +} diff --git a/contracts/gelato/ProviderModuleDSA.sol b/contracts/gelato/ProviderModuleDSA.sol new file mode 100644 index 0000000..5e63078 --- /dev/null +++ b/contracts/gelato/ProviderModuleDSA.sol @@ -0,0 +1,121 @@ +// "SPDX-License-Identifier: UNLICENSED" +pragma solidity 0.7.4; +pragma experimental ABIEncoderV2; + +import { + GelatoProviderModuleStandard +} from "@gelatonetwork/core/contracts/provider_modules/GelatoProviderModuleStandard.sol"; +import { + Task +} from "@gelatonetwork/core/contracts/gelato_core/interfaces/IGelatoCore.sol"; +import {AccountInterface} from "../interfaces/InstaDapp.sol"; +import { + ConnectGelatoProviderPayment +} from "../connectors/ConnectGelatoProviderPayment.sol"; + +/// @notice Gelato Provider Module for the InstaDapp DSA +/// @dev Used by Provider to sanity check any third-party Tasks they pay for +/// @author Gelato Network Team +contract ProviderModuleDSA is GelatoProviderModuleStandard { + /// @dev DSA must have gelatoCore as auth and gelatoCore is emitted as origin of cast + address public immutable gelatoCore; + + /// @notice A trusted Connector to pay Provider for e.g. User's Gelato gas usage. + /// @dev Automated InstaDapp Use Cases that rely on a third-party Gelato Provider + /// to pay for automation will likely have this Connector in their spells. + address public immutable connectGelatoProviderPayment; + + // TO DO: remove `public` after hardhat file import bugfix + // https://github.com/nomiclabs/hardhat/issues/916 + constructor(address _gelatoCore, address _connectGelatoProviderPayment) + public + { + gelatoCore = _gelatoCore; + connectGelatoProviderPayment = _connectGelatoProviderPayment; + } + + // ================= GELATO PROVIDER MODULE STANDARD ================ + /// @notice Standard Gelato function for Provider's Task sanity checks + /// @dev For more Provider security we should also check: + /// - ListInterface(index.list()).accountID(_userProxy) + /// - if (shield) connectors.isStaticConnector(targets) + /// - connectors.isConnector(targets) + /// But we skip those here to save gas + /// @param _userProxy The DSA which submitted the Task + /// @return whether the Provider is pays for the Task. + function isProvided( + address _userProxy, + address, + Task calldata + ) public view virtual override returns (string memory) { + try AccountInterface(_userProxy).isAuth(gelatoCore) returns ( + bool gelatoCoreIsAuth + ) { + if (!gelatoCoreIsAuth) + return "ProviderModuleDSA.isProvided:GelatoCoreNotAuth"; + } catch Error(string memory err) { + return + string(abi.encodePacked("ProviderModuleDSA.isProvided:", err)); + } catch { + return "ProviderModuleDSA.isProvided:undefined"; + } + + return OK; + } + + /// @notice Gelato Standard Provider function to retrieve payload for the DSA + /// @dev This formats the Gelato Task into a DSA compatible payload and + /// it also inserts the _provider into the ConnectGelatoProviderPayment payload, + /// to make sure that it cannot be spoofed thus e.g. securing Provider payments. + /// @param _provider the actual Provider address verified by GelatoCore system. + /// @param _task The Task in Gelato format. + /// @return The execution payload in DSA format + /// @return bool=false because no execRevert checks must be handled on GelatoCore + /// because the DSA reverts, if a spell revert is caught during delegatecall. + function execPayload( + uint256, + address, + address _provider, + Task calldata _task, + uint256 + ) public view virtual override returns (bytes memory, bool) { + address[] memory targets = new address[](_task.actions.length); + for (uint256 i = 0; i < _task.actions.length; i++) + targets[i] = _task.actions[i].addr; + + bytes[] memory datas = new bytes[](_task.actions.length); + for (uint256 i = 0; i < _task.actions.length; i++) { + if (_task.actions[i].addr == connectGelatoProviderPayment) + datas[i] = _replaceProvider(_provider, _task.actions[i].data); + else datas[i] = _task.actions[i].data; + } + + return ( + abi.encodeWithSelector( + AccountInterface.cast.selector, + targets, + datas, + gelatoCore + ), + false + ); + } + + function _replaceProvider(address _provider, bytes calldata _data) + internal + pure + returns (bytes memory) + { + (, address token, uint256 amt, uint256 getID, uint256 setID) = abi + .decode(_data[4:], (address, address, uint256, uint256, uint256)); + return + abi.encodeWithSelector( + ConnectGelatoProviderPayment.payProvider.selector, + _provider, + token, + amt, + getID, + setID + ); + } +} diff --git a/contracts/ConditionCompareUintsFromTwoSources.sol b/contracts/gelato/conditions/ConditionCompareUintsFromTwoSources.sol similarity index 96% rename from contracts/ConditionCompareUintsFromTwoSources.sol rename to contracts/gelato/conditions/ConditionCompareUintsFromTwoSources.sol index 9b149ec..ba4dd71 100644 --- a/contracts/ConditionCompareUintsFromTwoSources.sol +++ b/contracts/gelato/conditions/ConditionCompareUintsFromTwoSources.sol @@ -1,5 +1,5 @@ // "SPDX-License-Identifier: UNLICENSED" -pragma solidity 0.6.12; +pragma solidity 0.7.4; import { GelatoConditionsStandard @@ -9,7 +9,7 @@ import {IERC20} from "@gelatonetwork/core/contracts/external/IERC20.sol"; import { IGelatoCore } from "@gelatonetwork/core/contracts/gelato_core/interfaces/IGelatoCore.sol"; -import {GelatoBytes} from "./GelatoBytes.sol"; +import {GelatoBytes} from "../../lib/GelatoBytes.sol"; /// @notice A general contract for retrieving and comparing 2 uints from 2 contracts. /// @dev This contract only works if the refContracts fns returndata has a uint in @@ -18,7 +18,7 @@ contract ConditionCompareUintsFromTwoSources is GelatoConditionsStandard { using GelatoBytes for bytes; using SafeMath for uint256; - /// @notice Helper to encode the Condition data field off-chain + /// @notice Helper to encode the Condition.data field off-chain function getConditionData( address _sourceA, address _sourceB, diff --git a/contracts/gelato/conditions/ConditionMakerVaultUnsafe.sol b/contracts/gelato/conditions/ConditionMakerVaultUnsafe.sol new file mode 100644 index 0000000..9e12341 --- /dev/null +++ b/contracts/gelato/conditions/ConditionMakerVaultUnsafe.sol @@ -0,0 +1,90 @@ +// "SPDX-License-Identifier: UNLICENSED" +pragma solidity 0.7.4; +pragma experimental ABIEncoderV2; + +import { + GelatoConditionsStandard +} from "@gelatonetwork/core/contracts/conditions/GelatoConditionsStandard.sol"; +import {wmul, wdiv} from "../../vendor/DSMath.sol"; +import {GelatoBytes} from "../../lib/GelatoBytes.sol"; +import {IInstaMakerResolver} from "../../interfaces/IInstaMakerResolver.sol"; + +/// @title ConditionMakerVaultUnsafe +/// @notice Condition tracking Maker vault collateralization safety requirements. +/// @author Gelato Team +contract ConditionMakerVaultUnsafe is GelatoConditionsStandard { + using GelatoBytes for bytes; + + /// @notice Convenience function for off-chain _conditionData encoding + /// @dev Use the return for your Task's Condition.data field off-chain. + /// @return The encoded payload for your Task's Condition.data field. + function getConditionData( + uint256 _vaultId, + address _priceOracle, + bytes calldata _oraclePayload, + uint256 _minColRatio + ) public pure virtual returns (bytes memory) { + return abi.encode(_vaultId, _priceOracle, _oraclePayload, _minColRatio); + } + + /// @notice Standard GelatoCore system function + /// @dev A standard interface for GelatoCore to read Conditions + /// @param _conditionData The data you get from `getConditionData()` + /// @return OK if the Condition is there, else some error message. + function ok( + uint256, + bytes calldata _conditionData, + uint256 + ) public view virtual override returns (string memory) { + ( + uint256 _vaultID, + address _priceOracle, + bytes memory _oraclePayload, + uint256 _minColRatio + ) = abi.decode(_conditionData, (uint256, address, bytes, uint256)); + + return + isVaultUnsafe(_vaultID, _priceOracle, _oraclePayload, _minColRatio); + } + + /// @notice Specific implementation of this Condition's ok function + /// @dev The price oracle must return a uint256 WAD (10**18) value. + /// @param _vaultId The id of the Maker vault + /// @param _priceOracle The price oracle contract to supply the collateral price + /// e.g. Maker's ETH/USD oracle for ETH collateral pricing. + /// @param _oraclePayload The data for making the staticcall to the oracle's read + /// method e.g. the selector for MakerOracle's read fn. + /// @param _minColRatio The minimum collateral ratio measured in the price + /// of the collateral as specified by the _priceOracle. + /// @return OK if the Maker Vault is unsafe, otherwise some error message. + function isVaultUnsafe( + uint256 _vaultId, + address _priceOracle, + bytes memory _oraclePayload, + uint256 _minColRatio + ) public view virtual returns (string memory) { + (bool success, bytes memory returndata) = _priceOracle.staticcall( + _oraclePayload + ); + + if (!success) { + returndata.revertWithErrorString( + "ConditionMakerVaultUnsafe.isVaultUnsafe:oracle:" + ); + } + + uint256 colPriceInWad = abi.decode(returndata, (uint256)); + + IInstaMakerResolver.VaultData memory vault = IInstaMakerResolver( + 0x0A7008B38E7015F8C36A49eEbc32513ECA8801E5 + ) + .getVaultById(_vaultId); + + uint256 colRatio = wdiv( + wmul(vault.collateral, colPriceInWad), + vault.debt + ); + + return colRatio < _minColRatio ? OK : "MakerVaultNotUnsafe"; + } +} diff --git a/contracts/interfaces/IInstaMakerResolver.sol b/contracts/interfaces/IInstaMakerResolver.sol new file mode 100644 index 0000000..4f09aeb --- /dev/null +++ b/contracts/interfaces/IInstaMakerResolver.sol @@ -0,0 +1,21 @@ +// "SPDX-License-Identifier: UNLICENSED" +pragma solidity 0.7.4; +pragma experimental ABIEncoderV2; + +interface IInstaMakerResolver { + struct VaultData { + uint256 id; + address owner; + string colType; + uint256 collateral; + uint256 art; + uint256 debt; + uint256 liquidatedCol; + uint256 borrowRate; + uint256 colPrice; + uint256 liquidationRatio; + address vaultAddress; + } + + function getVaultById(uint256 id) external view returns (VaultData memory); +} diff --git a/contracts/interfaces/IMakerPriceFeed.sol b/contracts/interfaces/IMakerPriceFeed.sol new file mode 100644 index 0000000..f3580af --- /dev/null +++ b/contracts/interfaces/IMakerPriceFeed.sol @@ -0,0 +1,6 @@ +// "SPDX-License-Identifier: UNLICENSED" +pragma solidity 0.7.4; + +interface IMakerPriceFeed { + function read() external view returns (bytes32); +} diff --git a/contracts/interfaces/InstaDapp.sol b/contracts/interfaces/InstaDapp.sol new file mode 100644 index 0000000..eda8df3 --- /dev/null +++ b/contracts/interfaces/InstaDapp.sol @@ -0,0 +1,37 @@ +// "SPDX-License-Identifier: UNLICENSED" +pragma solidity 0.7.4; +pragma experimental ABIEncoderV2; + +/// @notice Interface InstaDapp Index +interface IndexInterface { + function connectors(uint256 version) external view returns (address); + + function list() external view returns (address); +} + +/// @notice Interface InstaDapp List +interface ListInterface { + function accountID(address _account) external view returns (uint64); +} + +/// @notice Interface InstaDapp InstaMemory +interface MemoryInterface { + function setUint(uint256 _id, uint256 _val) external; + + function getUint(uint256 _id) external returns (uint256); +} + +/// @notice Interface InstaDapp Defi Smart Account wallet +interface AccountInterface { + function cast( + address[] calldata _targets, + bytes[] calldata _datas, + address _origin + ) external payable returns (bytes32[] memory responses); + + function version() external view returns (uint256); + + function isAuth(address user) external view returns (bool); + + function shield() external view returns (bool); +} diff --git a/contracts/GelatoBytes.sol b/contracts/lib/GelatoBytes.sol similarity index 99% rename from contracts/GelatoBytes.sol rename to contracts/lib/GelatoBytes.sol index 45034c4..71a60bc 100644 --- a/contracts/GelatoBytes.sol +++ b/contracts/lib/GelatoBytes.sol @@ -1,5 +1,5 @@ // "SPDX-License-Identifier: UNLICENSED" -pragma solidity 0.6.12; +pragma solidity 0.7.4; library GelatoBytes { function calldataSliceSelector(bytes calldata _bytes) diff --git a/contracts/MockCDAI.sol b/contracts/mocks/MockCDAI.sol similarity index 92% rename from contracts/MockCDAI.sol rename to contracts/mocks/MockCDAI.sol index d299f6c..b7f0304 100644 --- a/contracts/MockCDAI.sol +++ b/contracts/mocks/MockCDAI.sol @@ -1,5 +1,5 @@ // "SPDX-License-Identifier: UNLICENSED" -pragma solidity 0.6.12; +pragma solidity 0.7.4; contract MockCDAI { // DSR @@ -11,7 +11,7 @@ contract MockCDAI { uint256 public supplyRatePerSecond; - constructor(uint256 _sRPS) public { + constructor(uint256 _sRPS) { supplyRatePerSecond = _sRPS; } diff --git a/contracts/MockDSR.sol b/contracts/mocks/MockDSR.sol similarity index 92% rename from contracts/MockDSR.sol rename to contracts/mocks/MockDSR.sol index 7900d68..59b3c16 100644 --- a/contracts/MockDSR.sol +++ b/contracts/mocks/MockDSR.sol @@ -1,5 +1,5 @@ // "SPDX-License-Identifier: UNLICENSED" -pragma solidity 0.6.12; +pragma solidity 0.7.4; contract MockDSR { // DSR @@ -13,7 +13,7 @@ contract MockDSR { uint256 public dsr; - constructor(uint256 _dsr) public { + constructor(uint256 _dsr) { dsr = _dsr; } diff --git a/contracts/resolvers/PriceOracleResolver.sol b/contracts/resolvers/PriceOracleResolver.sol new file mode 100644 index 0000000..b09270e --- /dev/null +++ b/contracts/resolvers/PriceOracleResolver.sol @@ -0,0 +1,69 @@ +// "SPDX-License-Identifier: UNLICENSED" +pragma solidity 0.7.4; +pragma experimental ABIEncoderV2; + +import {Ownable} from "../vendor/Ownable.sol"; +import {GelatoBytes} from "../lib/GelatoBytes.sol"; + +/// @title PriceOracleResolver +/// @notice Contract with convenience methods to retrieve oracle addresses or to mock test. +/// @dev Can be used to: +/// - Query oracle address for Gelato Condition payloads on frontend +/// - Test Conditions by using `getMockPrice(address _test)` as `oraclePayload` +contract PriceOracleResolver is Ownable { + using GelatoBytes for bytes; + + mapping(string => address) public oracle; + mapping(string => bytes) public oraclePayload; + mapping(address => uint256) public mockPrice; + + /// @notice Adds a new Oracle address + /// @dev Only owner can call this, but existing oracle entries are immutable + /// @param _oracle The descriptor of the oracle e.g. ETH/USD-Maker-v1 + /// @param _oracleAddress The address of the oracle contract + /// @param _oraclePayload The payload with function selector for the oracle request. + function addOracle( + string memory _oracle, + address _oracleAddress, + bytes calldata _oraclePayload + ) external onlyOwner { + require( + oracle[_oracle] == address(0), + "PriceOracleResolver.addOracle: set" + ); + oracle[_oracle] = _oracleAddress; + oraclePayload[_oracle] = _oraclePayload; + } + + /// @notice Function that allows easy oracle data testing in production. + /// @dev Your mock prices cannot be overriden by someone else. + /// @param _mockPrice The mock data you want to test against. + function setMockPrice(uint256 _mockPrice) public { + mockPrice[msg.sender] = _mockPrice; + } + + /// @notice Use with setMockPrice for easy testing in production. + /// @dev Encode oracle=PriceOracleResolver and oraclePayload=getMockPrice(tester) + /// to test your Conditions or Actions that make dynamic calls to price oracles. + /// @param _tester The msg.sender during setMockPrice. + /// @return The tester's mockPrice. + function getMockPrice(address _tester) external view returns (uint256) { + return mockPrice[_tester]; + } + + /// @notice A generelized getter for a price supplied by an oracle contract. + /// @dev The oracle returndata must be formatted as a single uint256. + /// @param _oracle The descriptor of our oracle e.g. ETH/USD-Maker-v1 + /// @return The uint256 oracle price + function getPrice(string memory _oracle) external view returns (uint256) { + address oracleAddr = oracle[_oracle]; + if (oracleAddr == address(0)) + revert("PriceOracleResolver.getPrice: no oracle"); + (bool success, bytes memory returndata) = oracleAddr.staticcall( + oraclePayload[_oracle] + ); + if (!success) + returndata.revertWithErrorString("PriceOracleResolver.getPrice:"); + return abi.decode(returndata, (uint256)); + } +} diff --git a/contracts/vendor/DSMath.sol b/contracts/vendor/DSMath.sol new file mode 100644 index 0000000..bcfe15a --- /dev/null +++ b/contracts/vendor/DSMath.sol @@ -0,0 +1,87 @@ +// "SPDX-License-Identifier: AGPL-3.0-or-later" +/// math.sol -- mixin for inline numerical wizardry + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity 0.7.4; + +function add(uint x, uint y) pure returns (uint z) { + require((z = x + y) >= x, "ds-math-add-overflow"); +} +function sub(uint x, uint y) pure returns (uint z) { + require((z = x - y) <= x, "ds-math-sub-underflow"); +} +function mul(uint x, uint y) pure returns (uint z) { + require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow"); +} + +function min(uint x, uint y) pure returns (uint z) { + return x <= y ? x : y; +} +function max(uint x, uint y) pure returns (uint z) { + return x >= y ? x : y; +} +function imin(int x, int y) pure returns (int z) { + return x <= y ? x : y; +} +function imax(int x, int y) pure returns (int z) { + return x >= y ? x : y; +} + +uint constant WAD = 10 ** 18; +uint constant RAY = 10 ** 27; + +//rounds to zero if x*y < WAD / 2 +function wmul(uint x, uint y) pure returns (uint z) { + z = add(mul(x, y), WAD / 2) / WAD; +} +//rounds to zero if x*y < WAD / 2 +function rmul(uint x, uint y) pure returns (uint z) { + z = add(mul(x, y), RAY / 2) / RAY; +} +//rounds to zero if x*y < WAD / 2 +function wdiv(uint x, uint y) pure returns (uint z) { + z = add(mul(x, WAD), y / 2) / y; +} +//rounds to zero if x*y < RAY / 2 +function rdiv(uint x, uint y) pure returns (uint z) { + z = add(mul(x, RAY), y / 2) / y; +} + +// This famous algorithm is called "exponentiation by squaring" +// and calculates x^n with x as fixed-point and n as regular unsigned. +// +// It's O(log n), instead of O(n) for naive repeated multiplication. +// +// These facts are why it works: +// +// If n is even, then x^n = (x^2)^(n/2). +// If n is odd, then x^n = x * x^(n-1), +// and applying the equation for even x gives +// x^n = x * (x^2)^((n-1) / 2). +// +// Also, EVM division is flooring and +// floor[(n-1) / 2] = floor[n / 2]. +// +function rpow(uint x, uint n) pure returns (uint z) { + z = n % 2 != 0 ? x : RAY; + + for (n /= 2; n != 0; n /= 2) { + x = rmul(x, x); + + if (n % 2 != 0) { + z = rmul(z, x); + } + } +} diff --git a/contracts/vendor/Ownable.sol b/contracts/vendor/Ownable.sol new file mode 100644 index 0000000..b068637 --- /dev/null +++ b/contracts/vendor/Ownable.sol @@ -0,0 +1,82 @@ +// "SPDX-License-Identifier: UNLICENSED" +pragma solidity 0.7.4; + +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +abstract contract Ownable { + address private _owner; + + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); + + /** + * @dev Initializes the contract setting the deployer as the initial owner. + */ + constructor() { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view returns (address) { + return _owner; + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + require(isOwner(), "Ownable: caller is not the owner"); + _; + } + + /** + * @dev Returns true if the caller is the current owner. + */ + function isOwner() public view returns (bool) { + return msg.sender == _owner; + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions anymore. Can only be called by the current owner. + * + * NOTE: Renouncing ownership will leave the contract without an owner, + * thereby removing any functionality that is only available to the owner. + */ + function renounceOwnership() public virtual onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + _transferOwnership(newOwner); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + */ + function _transferOwnership(address newOwner) internal virtual { + require( + newOwner != address(0), + "Ownable: new owner is the zero address" + ); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } +} diff --git a/buidler.config.js b/hardhat.config.js similarity index 84% rename from buidler.config.js rename to hardhat.config.js index 5fd27c2..f7e41dc 100644 --- a/buidler.config.js +++ b/hardhat.config.js @@ -1,5 +1,7 @@ // Buidler -const {task, usePlugin, types} = require("@nomiclabs/buidler/config"); +const {task, types} = require("hardhat/config"); +require("@nomiclabs/hardhat-ethers"); +require("@nomiclabs/hardhat-waffle"); // Libraries const assert = require("assert"); @@ -9,20 +11,23 @@ const GelatoCoreLib = require("@gelatonetwork/core"); // Process Env Variables require("dotenv").config(); -const INFURA_ID = process.env.INFURA_ID; -assert.ok(INFURA_ID, "no Infura ID in process.env"); +// const INFURA_ID = process.env.INFURA_ID; +// assert.ok(INFURA_ID, "no Infura ID in process.env"); +const ALCHEMY_ID = process.env.ALCHEMY_ID; +assert.ok(ALCHEMY_ID, "no Alchemy ID in process.env"); const INSTA_MASTER = "0xb1DC62EC38E6E3857a887210C38418E4A17Da5B2"; // ================================= CONFIG ========================================= module.exports = { - defaultNetwork: "ganache", + defaultNetwork: "hardhat", networks: { - ganache: { - timeout: 150000, + hardhat: { // Standard config - url: "http://localhost:8545", - fork: `https://mainnet.infura.io/v3/${INFURA_ID}`, - unlocked_accounts: [INSTA_MASTER], + // timeout: 150000, + forking: { + url: `https://eth-mainnet.alchemyapi.io/v2/${ALCHEMY_ID}`, + blockNumber: 11104384, + }, // Custom GelatoCore: "0x1d681d76ce96E4d70a88A00EBbcfc1E47808d0b8", GelatoGasPriceOracle: "0x169E633A2D1E6c10dD91238Ba11c4A708dfEF37C", @@ -48,17 +53,12 @@ module.exports = { ProviderModuleDSA: "0x0C25452d20cdFeEd2983fa9b9b9Cf4E81D6f2fE2", }, }, - solc: { - version: "0.6.12", - optimizer: {enabled: true}, + solidity: { + version: "0.7.4", + optimizer: {enabled: process.env.DEBUG ? false : true}, }, }; -// ================================= PLUGINS ========================================= -usePlugin("@nomiclabs/buidler-ethers"); -usePlugin("@nomiclabs/buidler-ganache"); -usePlugin("@nomiclabs/buidler-waffle"); - // ================================= TASKS ========================================= task("abi-encode-withselector") .addPositionalParam( @@ -128,13 +128,13 @@ task( ) .addOptionalParam("gelatocoreaddress") .addFlag("log", "Logs return values to stdout") - .setAction(async (taskArgs, bre) => { + .setAction(async (taskArgs, hre) => { try { - const gelatoCore = await bre.ethers.getContractAt( + const gelatoCore = await hre.ethers.getContractAt( GelatoCoreLib.GelatoCore.abi, taskArgs.gelatocoreaddress ? taskArgs.gelatocoreaddress - : bre.network.config.GelatoCore + : hre.network.config.GelatoCore ); const oracleAbi = ["function latestAnswer() view returns (int256)"]; @@ -142,7 +142,7 @@ task( const gelatoGasPriceOracleAddress = await gelatoCore.gelatoGasPriceOracle(); // Get gelatoGasPriceOracleAddress - const gelatoGasPriceOracle = await bre.ethers.getContractAt( + const gelatoGasPriceOracle = await hre.ethers.getContractAt( oracleAbi, gelatoGasPriceOracleAddress ); diff --git a/package.json b/package.json index 75cfe5c..6baa6a7 100644 --- a/package.json +++ b/package.json @@ -7,25 +7,25 @@ "private": false, "scripts": { "rebase": "HUSKY_SKIP_HOOKS=1 git rebase", - "compile": "npx buidler compile", + "compile": "npx hardhat compile", "format": "prettier --write .", "lint": "eslint --cache . && yarn lint:sol", "lint:sol": "solhint contracts/**/*.sol", "lint:fix": "eslint --cache --fix . && solhint --fix contracts/**/*.sol", - "test": "npx buidler test" + "test": "npx hardhat test", + "debug": "DEBUG=true npx hardhat test" }, "devDependencies": { - "@gelatonetwork/core": "0.5.3", - "@nomiclabs/buidler": "1.4.7", - "@nomiclabs/buidler-ethers": "2.0.2", - "@nomiclabs/buidler-ganache": "1.3.3", - "@nomiclabs/buidler-waffle": "2.1.0", + "@gelatonetwork/core": "1.0.0", + "@nomiclabs/hardhat-ethers": "2.0.0", + "@nomiclabs/hardhat-waffle": "2.0.0", "chai": "4.2.0", "dotenv": "8.2.0", "eslint": "7.10.0", "eslint-config-prettier": "6.12.0", "ethereum-waffle": "3.1.1", - "ethers": "5.0.17", + "ethers": "5.0.19", + "hardhat": "2.0.0", "husky": ">=4", "lint-staged": ">=10", "prettier": "2.1.2", @@ -42,7 +42,6 @@ }, "lint-staged": { "*.js": "eslint --cache --fix", - "*.sol": "solhint", "*.{js,sol,css,md}": "prettier --write" } } diff --git a/test/0_setup-DSA-Gelato.test.js b/test/0_setup-DSA-Gelato.test.js index 3d4c6a5..25ffdc7 100644 --- a/test/0_setup-DSA-Gelato.test.js +++ b/test/0_setup-DSA-Gelato.test.js @@ -1,8 +1,8 @@ -// running `npx buidler test` automatically makes use of buidler-waffle plugin +// running `npx hardhat test` automatically makes use of hardhat-waffle plugin // => only dependency we need is "chai" const {expect} = require("chai"); -const bre = require("@nomiclabs/buidler"); -const {ethers} = bre; +const hre = require("hardhat"); +const {ethers} = hre; const GelatoCoreLib = require("@gelatonetwork/core"); //const { sleep } = GelatoCoreLib; @@ -20,8 +20,8 @@ const ProviderModuleDSA_ABI = require("../pre-compiles/ProviderModuleDSA_ABI.jso describe("DSA setup with Gelato Tests", function () { this.timeout(50000); - if (bre.network.name !== "ganache") { - console.error("Test Suite is meant to be run on ganache only"); + if (hre.network.name !== "hardhat") { + console.error("Test Suite is meant to be run on hardhat only"); process.exit(1); } @@ -53,19 +53,19 @@ describe("DSA setup with Gelato Tests", function () { // ===== DSA LOCAL SETUP ================== instaIndex = await ethers.getContractAt( InstaIndex.abi, - bre.network.config.InstaIndex + hre.network.config.InstaIndex ); instaList = await ethers.getContractAt( InstaList.abi, - bre.network.config.InstaList + hre.network.config.InstaList ); instaConnectors = await ethers.getContractAt( InstaConnectors.abi, - bre.network.config.InstaConnectors + hre.network.config.InstaConnectors ); instaAccount = await ethers.getContractAt( InstaAccount.abi, - bre.network.config.InstaAccount + hre.network.config.InstaAccount ); dsaVersion = await instaAccount.version(); @@ -86,11 +86,11 @@ describe("DSA setup with Gelato Tests", function () { // ===== GELATO LOCAL SETUP ================== gelatoCore = await ethers.getContractAt( GelatoCoreLib.GelatoCore.abi, - bre.network.config.GelatoCore + hre.network.config.GelatoCore ); providerModuleDSA = await ethers.getContractAt( ProviderModuleDSA_ABI, - bre.network.config.ProviderModuleDSA + hre.network.config.ProviderModuleDSA ); }); @@ -100,13 +100,13 @@ describe("DSA setup with Gelato Tests", function () { expect(await instaIndex.connectors(dsaVersion)).to.be.equal( instaConnectors.address ); - expect(await instaConnectors.connectors(bre.network.config.ConnectAuth)).to + expect(await instaConnectors.connectors(hre.network.config.ConnectAuth)).to .be.true; - expect(await instaConnectors.connectors(bre.network.config.ConnectBasic)).to + expect(await instaConnectors.connectors(hre.network.config.ConnectBasic)).to .be.true; - expect(await instaConnectors.connectors(bre.network.config.ConnectMaker)).to + expect(await instaConnectors.connectors(hre.network.config.ConnectMaker)).to .be.true; - expect(await instaConnectors.connectors(bre.network.config.ConnectCompound)) + expect(await instaConnectors.connectors(hre.network.config.ConnectCompound)) .to.be.true; }); @@ -137,14 +137,14 @@ describe("DSA setup with Gelato Tests", function () { ); // Encode Payloads for ConnectBasic.withdraw - const withdrawData = await bre.run("abi-encode-withselector", { + const withdrawData = await hre.run("abi-encode-withselector", { abi: ConnectBasic.abi, functionname: "withdraw", inputs: [ETH, ethers.utils.parseEther("1"), userAddress, 0, 0], }); await expect( - dsa.cast([bre.network.config.ConnectBasic], [withdrawData], userAddress, { + dsa.cast([hre.network.config.ConnectBasic], [withdrawData], userAddress, { gasLimit, gasPrice, }) @@ -162,14 +162,14 @@ describe("DSA setup with Gelato Tests", function () { expect(await dsa.isAuth(gelatoCore.address)).to.be.false; // Encode Payloads for ConnectAuth.addModule - const addAuthData = await bre.run("abi-encode-withselector", { + const addAuthData = await hre.run("abi-encode-withselector", { abi: ConnectAuth.abi, functionname: "add", inputs: [gelatoCore.address], }); await expect( - dsa.cast([bre.network.config.ConnectAuth], [addAuthData], userAddress) + dsa.cast([hre.network.config.ConnectAuth], [addAuthData], userAddress) ) .to.emit(dsa, "LogCast") .withArgs(userAddress, userAddress, 0); @@ -179,7 +179,7 @@ describe("DSA setup with Gelato Tests", function () { it("#5: ConnectGelato is deployed and whitelisted on mainnet", async function () { expect( - await instaConnectors.isConnector([bre.network.config.ConnectGelato]) + await instaConnectors.isConnector([hre.network.config.ConnectGelato]) ).to.be.true; }); @@ -200,8 +200,8 @@ describe("DSA setup with Gelato Tests", function () { const withdrawFromDSATask = new GelatoCoreLib.Task({ actions: [ new GelatoCoreLib.Action({ - addr: bre.network.config.ConnectBasic, - data: await bre.run("abi-encode-withselector", { + addr: hre.network.config.ConnectBasic, + data: await hre.run("abi-encode-withselector", { abi: ConnectBasic.abi, functionname: "withdraw", inputs: [ @@ -218,13 +218,13 @@ describe("DSA setup with Gelato Tests", function () { }); // otherWallet needs to be an authority to qualify as withdraw to address. - const addAuthData = await bre.run("abi-encode-withselector", { + const addAuthData = await hre.run("abi-encode-withselector", { abi: ConnectAuth.abi, functionname: "add", inputs: [await otherWallet.getAddress()], }); await dsa.cast( - [bre.network.config.ConnectAuth], + [hre.network.config.ConnectAuth], [addAuthData], userAddress ); diff --git a/test/1_mv-DAI-DSR-Compound.test.js b/test/1_mv-DAI-DSR-Compound.test.js index 28d3047..8aa617f 100644 --- a/test/1_mv-DAI-DSR-Compound.test.js +++ b/test/1_mv-DAI-DSR-Compound.test.js @@ -1,8 +1,8 @@ -// running `npx buidler test` automatically makes use of buidler-waffle plugin +// running `npx hardhat test` automatically makes use of hardhat-waffle plugin // => only dependency we need is "chai" const {expect} = require("chai"); -const bre = require("@nomiclabs/buidler"); -const {ethers} = bre; +const hre = require("hardhat"); +const {ethers} = hre; const GelatoCoreLib = require("@gelatonetwork/core"); //const { sleep } = GelatoCoreLib; @@ -25,8 +25,8 @@ const IUniswapExchange = require("../pre-compiles/IUniswapExchange.json"); describe("Move DAI lending from DSR to Compound", function () { this.timeout(0); - if (bre.network.name !== "ganache") { - console.error("Test Suite is meant to be run on ganache only"); + if (hre.network.name !== "hardhat") { + console.error("Test Suite is meant to be run on hardhat only"); process.exit(1); } @@ -52,7 +52,7 @@ describe("Move DAI lending from DSR to Compound", function () { [userWallet] = await ethers.getSigners(); userAddress = await userWallet.getAddress(); - // Ganache default accounts prefilled with 100 ETH + // Hardhat default accounts prefilled with 100 ETH expect(await userWallet.getBalance()).to.be.gt( ethers.utils.parseEther("10") ); @@ -60,19 +60,19 @@ describe("Move DAI lending from DSR to Compound", function () { // ===== DSA SETUP ================== const instaIndex = await ethers.getContractAt( InstaIndex.abi, - bre.network.config.InstaIndex + hre.network.config.InstaIndex ); const instaList = await ethers.getContractAt( InstaList.abi, - bre.network.config.InstaList + hre.network.config.InstaList ); connectMaker = await ethers.getContractAt( ConnectMaker.abi, - bre.network.config.ConnectMaker + hre.network.config.ConnectMaker ); connectCompound = await ethers.getContractAt( ConnectCompound.abi, - bre.network.config.ConnectCompound + hre.network.config.ConnectCompound ); // Deploy DSA and get and verify ID of newly deployed DSA @@ -91,17 +91,17 @@ describe("Move DAI lending from DSR to Compound", function () { // ===== GELATO SETUP ================== gelatoCore = await ethers.getContractAt( GelatoCoreLib.GelatoCore.abi, - bre.network.config.GelatoCore + hre.network.config.GelatoCore ); // Add GelatoCore as auth on DSA - const addAuthData = await bre.run("abi-encode-withselector", { + const addAuthData = await hre.run("abi-encode-withselector", { abi: ConnectAuth.abi, functionname: "add", inputs: [gelatoCore.address], }); await dsa.cast( - [bre.network.config.ConnectAuth], + [hre.network.config.ConnectAuth], [addAuthData], userAddress ); @@ -125,13 +125,13 @@ describe("Move DAI lending from DSR to Compound", function () { // ===== Dapp Dependencies SETUP ================== // This test assumes our user has 100 DAI deposited in Maker DSR - dai = await ethers.getContractAt(IERC20.abi, bre.network.config.DAI); + dai = await ethers.getContractAt(IERC20.abi, hre.network.config.DAI); expect(await dai.balanceOf(userAddress)).to.be.equal(0); // Let's get the test user 100 DAI++ from Kyber const daiUniswapExchange = await ethers.getContractAt( IUniswapExchange.abi, - bre.network.config.DAI_UNISWAP + hre.network.config.DAI_UNISWAP ); await daiUniswapExchange.ethToTokenTransferInput( 1, @@ -148,14 +148,14 @@ describe("Move DAI lending from DSR to Compound", function () { expect(await dai.balanceOf(dsa.address)).to.be.eq(DAI_100); // Next we deposit the 100 DAI into the DSR - const depositDai = await bre.run("abi-encode-withselector", { + const depositDai = await hre.run("abi-encode-withselector", { abi: ConnectMaker.abi, functionname: "depositDai", inputs: [DAI_100, 0, 0], }); await expect( - dsa.cast([bre.network.config.ConnectMaker], [depositDai], userAddress) + dsa.cast([hre.network.config.ConnectMaker], [depositDai], userAddress) ) .to.emit(dsa, "LogCast") .withArgs(userAddress, userAddress, 0); @@ -172,12 +172,12 @@ describe("Move DAI lending from DSR to Compound", function () { data: await conditionCompareUints.getConditionData( mockCDAI.address, // We are in DSR so we compare against CDAI => SourceA=CDAI mockDSR.address, // SourceB=DSR - await bre.run("abi-encode-withselector", { - abi: require("../artifacts/MockCDAI.json").abi, + await hre.run("abi-encode-withselector", { + abi: (await hre.artifacts.readArtifact("MockCDAI")).abi, functionname: "supplyRatePerSecond", }), // CDAI data feed first (sourceAData) - await bre.run("abi-encode-withselector", { - abi: require("../artifacts/MockDSR.json").abi, + await hre.run("abi-encode-withselector", { + abi: (await hre.artifacts.readArtifact("MockDSR")).abi, functionname: "dsr", }), // DSR data feed second (sourceBData) MIN_SPREAD @@ -192,7 +192,7 @@ describe("Move DAI lending from DSR to Compound", function () { // target2 Compound deposit to fetch DAI amount. const connectorWithdrawFromDSR = new GelatoCoreLib.Action({ addr: connectMaker.address, - data: await bre.run("abi-encode-withselector", { + data: await hre.run("abi-encode-withselector", { abi: ConnectMaker.abi, functionname: "withdrawDai", inputs: [ethers.constants.MaxUint256, 0, 1], @@ -204,7 +204,7 @@ describe("Move DAI lending from DSR to Compound", function () { // We instantiate target2: Deposit DAI to CDAI and getId 1 const connectorDepositCompound = new GelatoCoreLib.Action({ addr: connectCompound.address, - data: await bre.run("abi-encode-withselector", { + data: await hre.run("abi-encode-withselector", { abi: ConnectCompound.abi, functionname: "deposit", inputs: [dai.address, 0, 1, 0], @@ -240,7 +240,7 @@ describe("Move DAI lending from DSR to Compound", function () { // protocol. Check out ./contracts/ProviderModuleDSA.sol to see what it does. const gelatoSelfProvider = new GelatoCoreLib.GelatoProvider({ addr: dsa.address, - module: bre.network.config.ProviderModuleDSA, + module: hre.network.config.ProviderModuleDSA, }); // ======= Executor Setup ========= @@ -263,15 +263,15 @@ describe("Move DAI lending from DSR to Compound", function () { GAS_PRICE_CEIL ); await dsa.cast( - [bre.network.config.ConnectGelato], // targets + [hre.network.config.ConnectGelato], // targets [ - await bre.run("abi-encode-withselector", { + await hre.run("abi-encode-withselector", { abi: ConnectGelato_ABI, functionname: "multiProvide", inputs: [ userAddress, [], - [bre.network.config.ProviderModuleDSA], + [hre.network.config.ProviderModuleDSA], TASK_AUTOMATION_FUNDS, 0, // _getId 0, // _setId @@ -296,7 +296,7 @@ describe("Move DAI lending from DSR to Compound", function () { expect( await gelatoCore.isModuleProvided( dsa.address, - bre.network.config.ProviderModuleDSA + hre.network.config.ProviderModuleDSA ) ).to.be.true; @@ -306,9 +306,9 @@ describe("Move DAI lending from DSR to Compound", function () { const expiryDate = 0; await expect( dsa.cast( - [bre.network.config.ConnectGelato], // targets + [hre.network.config.ConnectGelato], // targets [ - await bre.run("abi-encode-withselector", { + await hre.run("abi-encode-withselector", { abi: ConnectGelato_ABI, functionname: "submitTask", inputs: [ @@ -345,7 +345,7 @@ describe("Move DAI lending from DSR to Compound", function () { // First we fetch the gelatoGasPrice as fed by ChainLink oracle. Gelato // allows Users to specify a maximum fast gwei gas price for their Tasks // to remain executable up until. - const gelatoGasPrice = await bre.run("fetchGelatoGasPrice"); + const gelatoGasPrice = await hre.run("fetchGelatoGasPrice"); expect(gelatoGasPrice).to.be.lte( taskRebalanceDSRToCDAIifBetter.selfProviderGasPriceCeil ); @@ -383,7 +383,7 @@ describe("Move DAI lending from DSR to Compound", function () { // we look at changes in the CDAI balance of the DSA const cDAI = await ethers.getContractAt( IERC20.abi, - bre.network.config.CDAI + hre.network.config.CDAI ); const dsaCDAIBefore = await cDAI.balanceOf(dsa.address); diff --git a/test/2_Debt-Bridge-External-Provider.test.js b/test/2_Debt-Bridge-External-Provider.test.js index 4c38ea5..f03deb1 100644 --- a/test/2_Debt-Bridge-External-Provider.test.js +++ b/test/2_Debt-Bridge-External-Provider.test.js @@ -1,10 +1,9 @@ const {expect} = require("chai"); -const bre = require("@nomiclabs/buidler"); -const {constants} = require("ethers"); -const {ethers} = bre; +const hre = require("hardhat"); +const {ethers} = hre; const GelatoCoreLib = require("@gelatonetwork/core"); -// #region Contracts ABI +// #region Contracts ABI and Constants const InstaIndex = require("../pre-compiles/InstaIndex.json"); const InstaList = require("../pre-compiles/InstaList.json"); @@ -14,97 +13,111 @@ const ConnectMaker = require("../pre-compiles/ConnectMaker.json"); const ConnectCompound = require("../pre-compiles/ConnectCompound.json"); const ConnectInstaPool = require("../pre-compiles/ConnectInstaPool.json"); const ConnectAuth = require("../pre-compiles/ConnectAuth.json"); -const ConnectGelatoDebtBridgeABI = require("../artifacts/ConnectGelatoDebtBridge.json"); -const ConnectGelatoProviderPaymentABI = require("../artifacts/ConnectGelatoProviderPayment.json"); +const ConnectGelatoDebtBridgeFromMakerABI = require("../artifacts/contracts/connectors/ConnectGelatoDebtBridgeFromMaker.sol/ConnectGelatoDebtBridgeFromMaker.json") + .abi; +const ConnectGelatoProviderPaymentABI = require("../artifacts/contracts/connectors/ConnectGelatoProviderPayment.sol/ConnectGelatoProviderPayment.json") + .abi; const InstaConnector = require("../pre-compiles/InstaConnectors.json"); const DssCdpManager = require("../pre-compiles/DssCdpManager.json"); const GetCdps = require("../pre-compiles/GetCdps.json"); const IERC20 = require("../pre-compiles/IERC20.json"); const CTokenInterface = require("../pre-compiles/CTokenInterface.json"); -const GelatoGasPriceOracle = require("../pre-compiles/GelatoGasPriceOracle.json"); const CompoundResolver = require("../pre-compiles/InstaCompoundResolver.json"); +const PriceOracleResolverABI = require("../artifacts/contracts/resolvers/PriceOracleResolver.sol/PriceOracleResolver.json") + .abi; const ETH = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; const GAS_LIMIT = "4000000"; const GAS_PRICE_CEIL = ethers.utils.parseUnits("1000", "gwei"); const WAD = ethers.utils.parseUnits("1", 18); +// const ORACLE_MAKER_ETH_USD = "ETH/USD-Maker-v1"; +// const ORACLE_MAKER_ETH_USD_ADDR = "0x729D19f657BD0614b4985Cf1D82531c67569197B"; +// const PRICE_ORACLE_MAKER_PAYLOAD = "0x57de26a4"; // IMakerOracle.read() + +const MIN_COL_RATIO_MAKER = ethers.utils.parseUnits("3", 18); +const MIN_COL_RATIO_B = ethers.utils.parseUnits("19", 17); + +// TO DO: make dynamic based on real time Collateral Price and Ratios +const MAKER_INITIAL_ETH = ethers.utils.parseEther("10"); +const MAKER_INITIAL_DEBT = ethers.utils.parseUnits("1000", 18); + // #endregion //#region Mock Math Function -let wdiv = (x, y) => { +function wdiv(x, y) { return x.mul(WAD).add(y.div(2)).div(y); -}; +} -let wmul = (x, y) => { +function wmul(x, y) { return x.mul(y).add(WAD.div(2)).div(WAD); -}; +} -let wcollateralToWithdraw = ( - wantedLiquidationRatioOnProtocol1, - wantedLiquidationRatioOnProtocol2, - collateral, - borrowedToken, - collateralPrice -) => { +function wCalcCollateralToWithdraw( + minColRatioOnMaker, + minColRatioOnPositionB, + collateralPrice, + pricedCollateral, + daiDebtOnMaker +) { //#region CALCULATION REPLICATION let expectedColToWithdraw = wmul( - wmul(wantedLiquidationRatioOnProtocol1, wantedLiquidationRatioOnProtocol2), - borrowedToken + wmul(minColRatioOnMaker, minColRatioOnPositionB), + daiDebtOnMaker ); // doc ref : c_r x comp_r x d_2 expectedColToWithdraw = expectedColToWithdraw.sub( - wmul(wantedLiquidationRatioOnProtocol1, collateral) + wmul(minColRatioOnMaker, pricedCollateral) ); // doc ref : c_r x comp_r x d_2 - c_r x e_2 expectedColToWithdraw = wdiv( expectedColToWithdraw, - wantedLiquidationRatioOnProtocol2.sub(wantedLiquidationRatioOnProtocol1) + minColRatioOnPositionB.sub(minColRatioOnMaker) ); // doc ref : (c_r x comp_r x d_2 - c_r x e_2)/ (comp_r - c_r) - expectedColToWithdraw = collateral.sub(expectedColToWithdraw); // doc ref : e_2 - ((c_r x comp_r x d_2 - c_r x e_2)/ (comp_r - c_r)) + expectedColToWithdraw = pricedCollateral.sub(expectedColToWithdraw); // doc ref : e_2 - ((c_r x comp_r x d_2 - c_r x e_2)/ (comp_r - c_r)) // Extra step to convert back to col type expectedColToWithdraw = wdiv(expectedColToWithdraw, collateralPrice); //#endregion return expectedColToWithdraw; -}; +} -let wborrowedTokenToPayback = ( - wantedLiquidationRatioOnProtocol1, - wantedLiquidationRatioOnProtocol2, - collateral, - borrowedToken -) => { +function wCalcDebtToRepay( + minColRatioOnMaker, + minColRatioOnPositionB, + pricedCollateral, + daiDebtOnMaker +) { //#region CALCULATION REPLICATION let expectedBorToPayBack = wmul( - wmul(wantedLiquidationRatioOnProtocol1, wantedLiquidationRatioOnProtocol2), - borrowedToken + wmul(minColRatioOnMaker, minColRatioOnPositionB), + daiDebtOnMaker ); // doc ref : c_r x comp_r x d_2 expectedBorToPayBack = expectedBorToPayBack.sub( - wmul(wantedLiquidationRatioOnProtocol1, collateral) + wmul(minColRatioOnMaker, pricedCollateral) ); // doc ref : c_r x comp_r x d_2 - c_r x e_2 expectedBorToPayBack = wdiv( expectedBorToPayBack, - wantedLiquidationRatioOnProtocol2.sub(wantedLiquidationRatioOnProtocol1) + minColRatioOnPositionB.sub(minColRatioOnMaker) ); // doc ref : (c_r x comp_r x d_2 - c_r x e_2)/ (comp_r - c_r) expectedBorToPayBack = wmul( - wdiv(ethers.utils.parseUnits("1", 18), wantedLiquidationRatioOnProtocol1), + wdiv(ethers.utils.parseUnits("1", 18), minColRatioOnMaker), expectedBorToPayBack ); // doc ref : (1/c_r)((c_r x comp_r x d_2 - c_r x e_2)/ (comp_r - c_r)) - expectedBorToPayBack = borrowedToken.sub(expectedBorToPayBack); // doc ref : d_2 - (1/c_r)((c_r x comp_r x d_2 - c_r x e_2)/ (comp_r - c_r)) + expectedBorToPayBack = daiDebtOnMaker.sub(expectedBorToPayBack); // doc ref : d_2 - (1/c_r)((c_r x comp_r x d_2 - c_r x e_2)/ (comp_r - c_r)) //#endregion return expectedBorToPayBack; -}; +} //#endregion describe("Debt Bridge with External Provider", function () { this.timeout(0); - if (bre.network.name !== "ganache") { - console.error("Test Suite is meant to be run on ganache only"); + if (hre.network.name !== "hardhat") { + console.error("Test Suite is meant to be run on hardhat only"); process.exit(1); } @@ -113,6 +126,8 @@ describe("Debt Bridge with External Provider", function () { let userAddress; let providerWallet; let providerAddress; + let executorWallet; + let executorAddress; // Deployed instances let connectGelato; @@ -129,33 +144,36 @@ describe("Debt Bridge with External Provider", function () { let cEthToken; let instaMaster; let instaConnectors; - let gelatoGasPriceOracle; let compoundResolver; // Contracts to deploy and use for local testing - let conditionMakerVaultIsSafe; - let connectGelatoDebtBridge; + let conditionMakerVaultUnsafe; + let connectGelatoDebtBridgeFromMaker; let connectGelatoProviderPayment; - let oracleAggregator; + let priceOracleResolver; let dsaProviderModule; // Creation during test let dsa; - let connectedGelatoCore; + + // Payload Params for ConnectGelatoDebtBridgeFromMaker and ConditionMakerVaultUnsafe + let vaultId; + + // For TaskSpec and for Task + let spells = []; before(async function () { // Get Test Wallet for local testnet - [userWallet] = await ethers.getSigners(); + [userWallet, providerWallet, executorWallet] = await ethers.getSigners(); userAddress = await userWallet.getAddress(); - - [, providerWallet] = await ethers.getSigners(); providerAddress = await providerWallet.getAddress(); + executorAddress = await executorWallet.getAddress(); instaMaster = await ethers.provider.getSigner( - bre.network.config.InstaMaster + hre.network.config.InstaMaster ); - // Ganache default accounts prefilled with 100 ETH + // Hardhat default accounts prefilled with 100 ETH expect(await userWallet.getBalance()).to.be.gt( ethers.utils.parseEther("10") ); @@ -163,99 +181,89 @@ describe("Debt Bridge with External Provider", function () { // ===== Get Deployed Contract Instance ================== instaIndex = await ethers.getContractAt( InstaIndex.abi, - bre.network.config.InstaIndex + hre.network.config.InstaIndex ); instaList = await ethers.getContractAt( InstaList.abi, - bre.network.config.InstaList + hre.network.config.InstaList ); connectGelato = await ethers.getContractAt( ConnectGelato.abi, - bre.network.config.ConnectGelato + hre.network.config.ConnectGelato ); connectMaker = await ethers.getContractAt( ConnectMaker.abi, - bre.network.config.ConnectMaker + hre.network.config.ConnectMaker ); connectInstaPool = await ethers.getContractAt( ConnectInstaPool.abi, - bre.network.config.ConnectInstaPool + hre.network.config.ConnectInstaPool ); connectCompound = await ethers.getContractAt( ConnectCompound.abi, - bre.network.config.ConnectCompound + hre.network.config.ConnectCompound ); dssCdpManager = await ethers.getContractAt( DssCdpManager.abi, - bre.network.config.DssCdpManager + hre.network.config.DssCdpManager ); getCdps = await ethers.getContractAt( GetCdps.abi, - bre.network.config.GetCdps + hre.network.config.GetCdps ); - daiToken = await ethers.getContractAt(IERC20.abi, bre.network.config.DAI); + daiToken = await ethers.getContractAt(IERC20.abi, hre.network.config.DAI); gelatoCore = await ethers.getContractAt( GelatoCoreLib.GelatoCore.abi, - bre.network.config.GelatoCore + hre.network.config.GelatoCore ); cDaiToken = await ethers.getContractAt( CTokenInterface.abi, - bre.network.config.CDAI + hre.network.config.CDAI ); cEthToken = await ethers.getContractAt( CTokenInterface.abi, - bre.network.config.CETH + hre.network.config.CETH ); instaConnectors = await ethers.getContractAt( InstaConnector.abi, - bre.network.config.InstaConnectors - ); - gelatoGasPriceOracle = await ethers.getContractAt( - GelatoGasPriceOracle.abi, - bre.network.config.GelatoGasPriceOracle + hre.network.config.InstaConnectors ); compoundResolver = await ethers.getContractAt( CompoundResolver.abi, - bre.network.config.CompoundResolver + hre.network.config.CompoundResolver ); // instaEvent = await ethers.getContractAt( // InstaEvent.abi, - // bre.network.config.InstaEvent + // hre.network.config.InstaEvent // ) // ===== Deploy Needed Contract ================== - const OracleAggregator = await ethers.getContractFactory( - "OracleAggregator" + const PriceOracleResolver = await ethers.getContractFactory( + "PriceOracleResolver" ); - oracleAggregator = await OracleAggregator.deploy(); - await oracleAggregator.deployed(); + priceOracleResolver = await PriceOracleResolver.deploy(); + await priceOracleResolver.deployed(); - const ConditionMakerVaultIsSafe = await ethers.getContractFactory( - "ConditionMakerVaultIsSafe" + const ConditionMakerVaultUnsafe = await ethers.getContractFactory( + "ConditionMakerVaultUnsafe" ); - conditionMakerVaultIsSafe = await ConditionMakerVaultIsSafe.deploy( - oracleAggregator.address - ); - await conditionMakerVaultIsSafe.deployed(); + conditionMakerVaultUnsafe = await ConditionMakerVaultUnsafe.deploy(); + await conditionMakerVaultUnsafe.deployed(); - const connectorLength = await instaConnectors.connectorLength(); - const connectorId = connectorLength.add(1); - - const ConnectGelatoDebtBridge = await ethers.getContractFactory( - "ConnectGelatoDebtBridge" + const ConnectGelatoDebtBridgeFromMaker = await ethers.getContractFactory( + "ConnectGelatoDebtBridgeFromMaker" ); - connectGelatoDebtBridge = await ConnectGelatoDebtBridge.deploy( - connectorId, - oracleAggregator.address + connectGelatoDebtBridgeFromMaker = await ConnectGelatoDebtBridgeFromMaker.deploy( + (await instaConnectors.connectorLength()).add(1) ); - await connectGelatoDebtBridge.deployed(); + await connectGelatoDebtBridgeFromMaker.deployed(); const ConnectGelatoProviderPayment = await ethers.getContractFactory( "ConnectGelatoProviderPayment" ); connectGelatoProviderPayment = await ConnectGelatoProviderPayment.deploy( - connectorId.add(1) + (await instaConnectors.connectorLength()).add(2) ); await connectGelatoProviderPayment.deployed(); @@ -263,8 +271,7 @@ describe("Debt Bridge with External Provider", function () { "ProviderModuleDSA" ); dsaProviderModule = await ProviderModuleDSA.deploy( - bre.network.config.InstaIndex, - bre.network.config.GelatoCore, + hre.network.config.GelatoCore, connectGelatoProviderPayment.address ); await dsaProviderModule.deployed(); @@ -276,25 +283,29 @@ describe("Debt Bridge with External Provider", function () { /////////////////////////////////////////////////////////////////////////////////////////////////// // Gelato Testing environment setup. - // Step 1 : Add EUR/USD Maker Medianizer in the Oracle Aggregator + // Step 1 : Add EUR/USD Maker Medianizer in the PriceOracleResolver // Step 2 : Enable Debt Bridge Connector and Gelato Provider Payment Connector // Step 3 : Executor Staking on Gelato // Step 4 : Provider put some fund on gelato for paying future tasks executions // Step 5 : Provider choose a executor // Step 6 : Provider will add a module - // Step 7 : Provider should whitelist task + // Step 7 : User create a DeFi Smart Account + // Step 8 : User open a Vault, put some ether on it and borrow some dai + // Step 9 : User give authorization to gelato to use his DSA on his behalf. + // Step 10 : Provider should whitelist task - //#region Step 1 Add EUR/USD Maker Medianizer in the Oracle Aggregator + //#region Step 1 Add EUR/USD Maker Medianizer in the PriceOracleResolver - // Oracle Aggregator is a price feeder aggregator + // PriceOracleResolver is a price feeder aggregator // You will be able to query price from multiple source through this aggregator // For the demo we add the ETH/USD Medianizer to the aggregator // MakerDAO price oracle are called Medianizer - await oracleAggregator.addOracle( - "ETH/USD", - "0x729D19f657BD0614b4985Cf1D82531c67569197B" - ); + // await priceOracleResolver.addOracle( + // ORACLE_MAKER_ETH_USD, + // ORACLE_MAKER_ETH_USD_ADDR, + // PRICE_ORACLE_MAKER_PAYLOAD + // ); //#endregion @@ -310,18 +321,32 @@ describe("Debt Bridge with External Provider", function () { // be executed. Improvind user experience. await userWallet.sendTransaction({ - to: bre.network.config.InstaMaster, + to: hre.network.config.InstaMaster, value: ethers.utils.parseEther("0.1"), }); + + await hre.network.provider.request({ + method: "hardhat_impersonateAccount", + params: [await instaMaster.getAddress()], + }); + await instaConnectors .connect(instaMaster) - .enable(connectGelatoDebtBridge.address); + .enable(connectGelatoDebtBridgeFromMaker.address); + await instaConnectors .connect(instaMaster) .enable(connectGelatoProviderPayment.address); + await hre.network.provider.request({ + method: "hardhat_stopImpersonatingAccount", + params: [await instaMaster.getAddress()], + }); + expect( - await instaConnectors.isConnector([connectGelatoDebtBridge.address]) + await instaConnectors.isConnector([ + connectGelatoDebtBridgeFromMaker.address, + ]) ).to.be.true; expect( await instaConnectors.isConnector([connectGelatoProviderPayment.address]) @@ -338,16 +363,11 @@ describe("Debt Bridge with External Provider", function () { // For safety measure Gelato ask the executor to stake a minimum // amount. - connectedGelatoCore = gelatoCore.connect(providerWallet); - gelatoCore = gelatoCore.connect(userWallet); - await connectedGelatoCore.stakeExecutor({ - from: providerAddress, - value: await connectedGelatoCore.minExecutorStake(), + await gelatoCore.connect(executorWallet).stakeExecutor({ + value: await gelatoCore.minExecutorStake(), }); - expect( - await connectedGelatoCore.isExecutorMinStaked(providerAddress) - ).to.be.true; + expect(await gelatoCore.isExecutorMinStaked(executorAddress)).to.be.true; //#endregion @@ -364,14 +384,14 @@ describe("Debt Bridge with External Provider", function () { ); await expect( - connectedGelatoCore.provideFunds(providerAddress, { + gelatoCore.connect(providerWallet).provideFunds(providerAddress, { value: TASK_AUTOMATION_FUNDS, }) ).to.emit(gelatoCore, "LogFundsProvided"); - expect( - await connectedGelatoCore.providerFunds(providerAddress) - ).to.be.equal(TASK_AUTOMATION_FUNDS); + expect(await gelatoCore.providerFunds(providerAddress)).to.be.equal( + TASK_AUTOMATION_FUNDS + ); //#endregion @@ -381,12 +401,14 @@ describe("Debt Bridge with External Provider", function () { // for the provider, it will be compensated by the provider. await expect( - connectedGelatoCore.providerAssignsExecutor(providerAddress) + gelatoCore + .connect(providerWallet) + .providerAssignsExecutor(executorAddress) ).to.emit(gelatoCore, "LogProviderAssignedExecutor"); - expect( - await connectedGelatoCore.executorByProvider(providerAddress) - ).to.be.equal(providerAddress); + expect(await gelatoCore.executorByProvider(providerAddress)).to.be.equal( + executorAddress + ); //#endregion @@ -397,156 +419,20 @@ describe("Debt Bridge with External Provider", function () { // Payment connector for receiving payment of User. await expect( - connectedGelatoCore.addProviderModules([dsaProviderModule.address]) + gelatoCore + .connect(providerWallet) + .addProviderModules([dsaProviderModule.address]) ).to.emit(gelatoCore, "LogProviderModuleAdded"); expect( - await connectedGelatoCore.isModuleProvided( - providerAddress, - dsaProviderModule.address - ) + await gelatoCore + .connect(providerWallet) + .isModuleProvided(providerAddress, dsaProviderModule.address) ).to.be.true; //#endregion - //#region Step 7 Provider should whitelist task - - // By WhiteList task, the provider can constrain the type - // of task the user can submitting. - - //#region Actions - - const spells = []; - - let debtBridge = new GelatoCoreLib.Action({ - addr: connectGelatoDebtBridge.address, - data: constants.HashZero, - operation: GelatoCoreLib.Operation.Delegatecall, - dataFlow: GelatoCoreLib.DataFlow.None, - termsOkCheck: false, - value: 0, - }); - - spells.push(debtBridge); - - let flashBorrow = new GelatoCoreLib.Action({ - addr: connectInstaPool.address, - data: constants.HashZero, - operation: GelatoCoreLib.Operation.Delegatecall, - dataFlow: GelatoCoreLib.DataFlow.None, - termsOkCheck: false, - value: 0, - }); - - spells.push(flashBorrow); - - let paybackMaker = new GelatoCoreLib.Action({ - addr: connectMaker.address, - data: constants.HashZero, - operation: GelatoCoreLib.Operation.Delegatecall, - dataFlow: GelatoCoreLib.DataFlow.None, - termsOkCheck: false, - value: 0, - }); - - spells.push(paybackMaker); - - let withdrawMaker = new GelatoCoreLib.Action({ - addr: connectMaker.address, - data: constants.HashZero, - operation: GelatoCoreLib.Operation.Delegatecall, - dataFlow: GelatoCoreLib.DataFlow.None, - termsOkCheck: false, - value: 0, - }); - - spells.push(withdrawMaker); - - let depositCompound = new GelatoCoreLib.Action({ - addr: connectCompound.address, - data: constants.HashZero, - operation: GelatoCoreLib.Operation.Delegatecall, - dataFlow: GelatoCoreLib.DataFlow.None, - termsOkCheck: false, - value: 0, - }); - - spells.push(depositCompound); - - let borrowCompound = new GelatoCoreLib.Action({ - addr: connectCompound.address, - data: constants.HashZero, - operation: GelatoCoreLib.Operation.Delegatecall, - dataFlow: GelatoCoreLib.DataFlow.None, - termsOkCheck: false, - value: 0, - }); - - spells.push(borrowCompound); - - let flashPayBack = new GelatoCoreLib.Action({ - addr: connectInstaPool.address, - data: constants.HashZero, - operation: GelatoCoreLib.Operation.Delegatecall, - dataFlow: GelatoCoreLib.DataFlow.None, - termsOkCheck: false, - value: 0, - }); - - spells.push(flashPayBack); - - let payProvider = new GelatoCoreLib.Action({ - addr: connectGelatoProviderPayment.address, - data: constants.HashZero, - operation: GelatoCoreLib.Operation.Delegatecall, - dataFlow: GelatoCoreLib.DataFlow.None, - termsOkCheck: false, - value: 0, - }); - - spells.push(payProvider); - - const gasPriceCeil = constants.MaxUint256; - - const gelatoFlashLoanTaskSpec = new GelatoCoreLib.TaskSpec({ - conditions: [conditionMakerVaultIsSafe.address], - actions: spells, - gasPriceCeil, - }); - - await expect( - connectedGelatoCore.provideTaskSpecs([gelatoFlashLoanTaskSpec]) - ).to.emit(gelatoCore, "LogTaskSpecProvided"); - - expect( - await connectedGelatoCore.isTaskSpecProvided( - providerAddress, - gelatoFlashLoanTaskSpec - ) - ).to.be.equal("OK"); - - expect( - await connectedGelatoCore.taskSpecGasPriceCeil( - providerAddress, - await connectedGelatoCore.hashTaskSpec(gelatoFlashLoanTaskSpec) - ) - ).to.be.equal(gasPriceCeil); - - //#endregion - - //#endregion - }); - - it("#1: Use Maker Compound refinancing if the maker vault become unsafe after a market move.", async function () { - // User Actions - // Step 1 : User create a DeFi Smart Account - // Step 2 : User open a Vault, put some ether on it and borrow some dai - // Step 3 : User give authorization to gelato to use his DSA on his behalf. - // Step 4 : User submit a Debt Refinancing task if market move against him - // Step 5 : Market Move against the user (Mock) - // Step 6 : Executor execute the user's task - - //#region Step 1 User create a DeFi Smart Account + //#region Step 7 User create a DeFi Smart Account // User create a Instadapp DeFi Smart Account // who give him the possibility to interact @@ -570,61 +456,58 @@ describe("Debt Bridge with External Provider", function () { //#endregion - //#region Step 2 User open a Vault, put some ether on it and borrow some dai + //#region Step 8 User open a Vault, put some ether on it and borrow some dai // User open a maker vault // He deposit 10 Eth on it // He borrow a 1000 DAI - const openVault = await bre.run("abi-encode-withselector", { + const openVault = await hre.run("abi-encode-withselector", { abi: ConnectMaker.abi, functionname: "open", inputs: ["ETH-A"], }); - await dsa.cast([bre.network.config.ConnectMaker], [openVault], userAddress); - - let cdps = await getCdps.getCdpsAsc(dssCdpManager.address, dsa.address); - let cdpId = String(cdps.ids[0]); + await dsa.cast([hre.network.config.ConnectMaker], [openVault], userAddress); + const cdps = await getCdps.getCdpsAsc(dssCdpManager.address, dsa.address); + vaultId = String(cdps.ids[0]); expect(cdps.ids[0].isZero()).to.be.false; await dsa.cast( - [bre.network.config.ConnectMaker], + [hre.network.config.ConnectMaker], [ - await bre.run("abi-encode-withselector", { + await hre.run("abi-encode-withselector", { abi: ConnectMaker.abi, functionname: "deposit", - inputs: [cdpId, ethers.utils.parseEther("10"), 0, 0], + inputs: [vaultId, MAKER_INITIAL_ETH, 0, 0], }), ], userAddress, { - value: ethers.utils.parseEther("10"), + value: MAKER_INITIAL_ETH, } ); - let makerVaultInitialBorrow = ethers.utils.parseUnits("1000", 18); - await dsa.cast( - [bre.network.config.ConnectMaker], + [hre.network.config.ConnectMaker], [ - await bre.run("abi-encode-withselector", { + await hre.run("abi-encode-withselector", { abi: ConnectMaker.abi, functionname: "borrow", - inputs: [cdpId, makerVaultInitialBorrow, 0, 0], + inputs: [vaultId, MAKER_INITIAL_DEBT, 0, 0], }), ], userAddress ); expect(await daiToken.balanceOf(dsa.address)).to.be.equal( - ethers.utils.parseEther("1000") + MAKER_INITIAL_DEBT ); //#endregion - //#region Step 3 User give authorization to gelato to use his DSA on his behalf. + //#region Step 9 User give authorization to gelato to use his DSA on his behalf. // Instadapp DSA contract give the possibility to the user to delegate // action by giving authorization. @@ -632,9 +515,9 @@ describe("Debt Bridge with External Provider", function () { // task for him if needed. await dsa.cast( - [bre.network.config.ConnectAuth], + [hre.network.config.ConnectAuth], [ - await bre.run("abi-encode-withselector", { + await hre.run("abi-encode-withselector", { abi: ConnectAuth.abi, functionname: "add", inputs: [gelatoCore.address], @@ -647,41 +530,28 @@ describe("Debt Bridge with External Provider", function () { //#endregion - //#region Step 4 User submit a Debt Refinancing task if market move against him + //#region Step 10 Provider should whitelist task - // User submit the refinancing task if market move against him. - // So in this case if the maker vault go to the unsafe area - // the refinancing task will be executed and the position - // will be split on two position on maker and compound. - // It will be done through a algorithm that will optimize the - // total borrow rate. + // By WhiteList task, the provider can constrain the type + // of task the user can submitting. - let wantedLiquidationRatioOnProtocol1 = ethers.utils.parseUnits("3", 18); - let wantedLiquidationRatioOnProtocol2 = ethers.utils.parseUnits("19", 17); - let currencyPair = "ETH/USD"; + //#region Actions - const debtBridgeCondition = new GelatoCoreLib.Condition({ - inst: conditionMakerVaultIsSafe.address, - data: await conditionMakerVaultIsSafe.getConditionData( - cdpId, - "ETH/USD", - ethers.utils.parseUnits("3", 18) - ), - }); - - // ======= Action/Spells setup ====== - const spells = []; - - let debtBridgeCalculation = new GelatoCoreLib.Action({ - addr: connectGelatoDebtBridge.address, - data: await bre.run("abi-encode-withselector", { - abi: ConnectGelatoDebtBridgeABI.abi, - functionname: "debtBridgeMakerToCompound", + const debtBridgeCalculation = new GelatoCoreLib.Action({ + addr: connectGelatoDebtBridgeFromMaker.address, + data: await hre.run("abi-encode-withselector", { + abi: ConnectGelatoDebtBridgeFromMakerABI, + functionname: "saveDebtBridgeDataToMemory", inputs: [ - cdpId, - wantedLiquidationRatioOnProtocol1, - wantedLiquidationRatioOnProtocol2, - currencyPair, + vaultId, + MIN_COL_RATIO_MAKER, + MIN_COL_RATIO_B, + priceOracleResolver.address, + await hre.run("abi-encode-withselector", { + abi: PriceOracleResolverABI, + functionname: "getMockPrice", + inputs: [userAddress], + }), 0, 0, ], @@ -691,92 +561,163 @@ describe("Debt Bridge with External Provider", function () { spells.push(debtBridgeCalculation); - let flashBorrow = new GelatoCoreLib.Action({ + const flashBorrow = new GelatoCoreLib.Action({ addr: connectInstaPool.address, - data: await bre.run("abi-encode-withselector", { + data: await hre.run("abi-encode-withselector", { abi: ConnectInstaPool.abi, functionname: "flashBorrow", - inputs: [bre.network.config.DAI, 0, "100", 0], + inputs: [hre.network.config.DAI, 0, "600", 0], }), operation: GelatoCoreLib.Operation.Delegatecall, }); spells.push(flashBorrow); - let paybackMaker = new GelatoCoreLib.Action({ + const paybackMaker = new GelatoCoreLib.Action({ addr: connectMaker.address, - data: await bre.run("abi-encode-withselector", { + data: await hre.run("abi-encode-withselector", { abi: ConnectMaker.abi, functionname: "payback", - inputs: [cdpId, 0, "101", 0], + inputs: [vaultId, 0, "601", 0], }), operation: GelatoCoreLib.Operation.Delegatecall, }); spells.push(paybackMaker); - let withdrawMaker = new GelatoCoreLib.Action({ + const withdrawMaker = new GelatoCoreLib.Action({ addr: connectMaker.address, - data: await bre.run("abi-encode-withselector", { + data: await hre.run("abi-encode-withselector", { abi: ConnectMaker.abi, functionname: "withdraw", - inputs: [cdpId, 0, "102", 0], + inputs: [vaultId, 0, "602", 0], }), operation: GelatoCoreLib.Operation.Delegatecall, }); spells.push(withdrawMaker); - let depositCompound = new GelatoCoreLib.Action({ + const depositCompound = new GelatoCoreLib.Action({ addr: connectCompound.address, - data: await bre.run("abi-encode-withselector", { + data: await hre.run("abi-encode-withselector", { abi: ConnectCompound.abi, functionname: "deposit", - inputs: [ETH, 0, "103", 0], + inputs: [ETH, 0, "603", 0], }), operation: GelatoCoreLib.Operation.Delegatecall, }); spells.push(depositCompound); - let borrowCompound = new GelatoCoreLib.Action({ + const borrowCompound = new GelatoCoreLib.Action({ addr: connectCompound.address, - data: await bre.run("abi-encode-withselector", { + data: await hre.run("abi-encode-withselector", { abi: ConnectCompound.abi, functionname: "borrow", - inputs: [bre.network.config.DAI, 0, "104", 0], + inputs: [hre.network.config.DAI, 0, "604", 0], }), operation: GelatoCoreLib.Operation.Delegatecall, }); spells.push(borrowCompound); - let flashPayBack = new GelatoCoreLib.Action({ + const flashPayBack = new GelatoCoreLib.Action({ addr: connectInstaPool.address, - data: await bre.run("abi-encode-withselector", { + data: await hre.run("abi-encode-withselector", { abi: ConnectInstaPool.abi, functionname: "flashPayback", - inputs: [bre.network.config.DAI, 0, 0], + inputs: [hre.network.config.DAI, 0, 0], }), operation: GelatoCoreLib.Operation.Delegatecall, }); spells.push(flashPayBack); - let payProvider = new GelatoCoreLib.Action({ + const payProvider = new GelatoCoreLib.Action({ addr: connectGelatoProviderPayment.address, - data: await bre.run("abi-encode-withselector", { - abi: ConnectGelatoProviderPaymentABI.abi, + data: await hre.run("abi-encode-withselector", { + abi: ConnectGelatoProviderPaymentABI, functionname: "payProvider", - inputs: [ethers.constants.AddressZero, ETH, 0, "105", 0], + inputs: [providerAddress, ETH, 0, "605", 0], }), operation: GelatoCoreLib.Operation.Delegatecall, }); spells.push(payProvider); + const gasPriceCeil = ethers.constants.MaxUint256; + + const connectGelatoDebtBridgeFromMakerTaskSpec = new GelatoCoreLib.TaskSpec( + { + conditions: [conditionMakerVaultUnsafe.address], + actions: spells, + gasPriceCeil, + } + ); + + await expect( + gelatoCore + .connect(providerWallet) + .provideTaskSpecs([connectGelatoDebtBridgeFromMakerTaskSpec]) + ).to.emit(gelatoCore, "LogTaskSpecProvided"); + + expect( + await gelatoCore + .connect(providerWallet) + .isTaskSpecProvided( + providerAddress, + connectGelatoDebtBridgeFromMakerTaskSpec + ) + ).to.be.equal("OK"); + + expect( + await gelatoCore + .connect(providerWallet) + .taskSpecGasPriceCeil( + providerAddress, + await gelatoCore + .connect(providerWallet) + .hashTaskSpec(connectGelatoDebtBridgeFromMakerTaskSpec) + ) + ).to.be.equal(gasPriceCeil); + + //#endregion + + //#endregion + }); + + it("#1: Use Maker Compound refinancing if the maker vault become unsafe after a market move.", async function () { + // User Actions + // Step 1: User submit a Debt Refinancing task if market move against him + // Step 2: Market Move against the user (Mock) + // Step 3: Executor execute the user's task + + //#region Step 1 User submit a Debt Refinancing task if market move against him + + // User submit the refinancing task if market move against him. + // So in this case if the maker vault go to the unsafe area + // the refinancing task will be executed and the position + // will be split on two position on maker and compound. + // It will be done through a algorithm that will optimize the + // total borrow rate. + + const conditionMakerVaultUnsafeObj = new GelatoCoreLib.Condition({ + inst: conditionMakerVaultUnsafe.address, + data: await conditionMakerVaultUnsafe.getConditionData( + vaultId, + priceOracleResolver.address, + await hre.run("abi-encode-withselector", { + abi: PriceOracleResolverABI, + functionname: "getMockPrice", + inputs: [userAddress], + }), + MIN_COL_RATIO_MAKER + ), + }); + + // ======= GELATO TASK SETUP ====== const refinanceIfCompoundBorrowIsBetter = new GelatoCoreLib.Task({ - conditions: [debtBridgeCondition], + conditions: [conditionMakerVaultUnsafeObj], actions: spells, }); @@ -786,11 +727,12 @@ describe("Debt Bridge with External Provider", function () { }); const expiryDate = 0; + await expect( dsa.cast( [connectGelato.address], // targets [ - await bre.run("abi-encode-withselector", { + await hre.run("abi-encode-withselector", { abi: ConnectGelato.abi, functionname: "submitTask", inputs: [ @@ -817,26 +759,34 @@ describe("Debt Bridge with External Provider", function () { //#endregion - //#region Step 5 Market Move against the user (Mock) + //#region Step 2 Market Move against the user (Mock) // Ether market price went from the current price to 250$ - const gelatoGasPrice = await bre.run("fetchGelatoGasPrice"); + const gelatoGasPrice = await hre.run("fetchGelatoGasPrice"); expect(gelatoGasPrice).to.be.lte(GAS_PRICE_CEIL); - expect( - await connectedGelatoCore.canExec(taskReceipt, GAS_LIMIT, gelatoGasPrice) - ).to.be.equal("ConditionNotOk:NotOKMakerVaultIsSafe"); - - await oracleAggregator.mock(true, ethers.utils.parseUnits("250", 18)); + // TO DO: base mock price off of real price data + await priceOracleResolver.setMockPrice(ethers.utils.parseUnits("400", 18)); expect( - await connectedGelatoCore.canExec(taskReceipt, GAS_LIMIT, gelatoGasPrice) + await gelatoCore + .connect(executorWallet) + .canExec(taskReceipt, GAS_LIMIT, gelatoGasPrice) + ).to.be.equal("ConditionNotOk:MakerVaultNotUnsafe"); + + // TO DO: base mock price off of real price data + await priceOracleResolver.setMockPrice(ethers.utils.parseUnits("250", 18)); + + expect( + await gelatoCore + .connect(executorWallet) + .canExec(taskReceipt, GAS_LIMIT, gelatoGasPrice) ).to.be.equal("OK"); //#endregion - //#region Step 6 Executor execute the user's task + //#region Step 3 Executor execute the user's task // The market move make the vault unsafe, so the executor // will execute the user's task to make the user position safe @@ -844,62 +794,78 @@ describe("Debt Bridge with External Provider", function () { //#region EXPECTED OUTCOME - let latestPrice = await oracleAggregator.getMakerTokenPrice(currencyPair); - let fees = ethers.utils + const latestPrice = await priceOracleResolver.getMockPrice(userAddress); + const gasFeesPaidFromCol = ethers.utils .parseUnits(String(1933090 + 19331 * 2), 0) - .mul(await gelatoGasPriceOracle.latestAnswer()); - let debt = await connectGelatoDebtBridge.getMakerVaultDebt(cdpId); - let collateral = wmul( - (await connectGelatoDebtBridge.getMakerVaultCollateralBalance(cdpId)).sub( - fees - ), + .mul(gelatoGasPrice); + const debtOnMakerBefore = await connectGelatoDebtBridgeFromMaker.getMakerVaultDebt( + vaultId + ); + const pricedCollateral = wmul( + ( + await connectGelatoDebtBridgeFromMaker.getMakerVaultCollateralBalance( + vaultId + ) + ).sub(gasFeesPaidFromCol), latestPrice ); - let expectedColWithdrawAmount = wcollateralToWithdraw( - wantedLiquidationRatioOnProtocol1, - wantedLiquidationRatioOnProtocol2, - collateral, - debt, - latestPrice + const expectedColWithdrawAmount = wCalcCollateralToWithdraw( + MIN_COL_RATIO_MAKER, + MIN_COL_RATIO_B, + latestPrice, + pricedCollateral, + debtOnMakerBefore ); - let expectedBorAmountToPayBack = wborrowedTokenToPayback( - wantedLiquidationRatioOnProtocol1, - wantedLiquidationRatioOnProtocol2, - collateral, - debt + const expectedBorAmountToPayBack = wCalcDebtToRepay( + MIN_COL_RATIO_MAKER, + MIN_COL_RATIO_B, + pricedCollateral, + debtOnMakerBefore ); - //console.log(String(wdiv(collateral.sub(wmul(expectedColWithdrawAmount, latestPrice).add(fees)),debt.sub(expectedBorAmountToPayBack)))); + //console.log(String(wdiv(pricedCollateral.sub(wmul(expectedColWithdrawAmount, latestPrice).add(gasFeesPaidFromCol)),debt.sub(expectedBorAmountToPayBack)))); //#endregion - - let providerBalanceBeforeExecution = await providerWallet.getBalance(); + const providerBalanceBeforeExecution = await providerWallet.getBalance(); await expect( - connectedGelatoCore.exec(taskReceipt, { + gelatoCore.connect(executorWallet).exec(taskReceipt, { gasPrice: gelatoGasPrice, // Exectutor must use gelatoGasPrice (Chainlink fast gwei) gasLimit: GAS_LIMIT, }) ).to.emit(gelatoCore, "LogExecSuccess"); - let providerBalanceAfterExecution = await providerWallet.getBalance(); + // 🚧 For Debugging: + // const txResponse2 = await gelatoCore + // .connect(providerWallet) + // .exec(taskReceipt, { + // gasPrice: gelatoGasPrice, + // gasLimit: GAS_LIMIT, + // }); + // const {blockHash} = await txResponse2.wait(); + // const logs = await ethers.provider.getLogs({blockHash}); + // const iFace = new ethers.utils.Interface(GelatoCoreLib.GelatoCore.abi); + // for (const log of logs) { + // console.log(iFace.parseLog(log).args.reason); + // } + // await GelatoCoreLib.sleep(10000); - expect(providerBalanceAfterExecution).to.be.gt( + expect(await providerWallet.getBalance()).to.be.gt( providerBalanceBeforeExecution ); // compound position of DSA on cDai and cEth - let compoundPosition = await compoundResolver.getCompoundData(dsa.address, [ - cDaiToken.address, - cEthToken.address, - ]); + const compoundPosition = await compoundResolver.getCompoundData( + dsa.address, + [cDaiToken.address, cEthToken.address] + ); // https://compound.finance/docs/ctokens#exchange-rate // calculate cEth/ETH rate to convert back cEth to ETH // for comparing with the withdrew Ether to the deposited one. - let exchangeRateCethToEth = (await cEthToken.getCash()) + const exchangeRateCethToEth = (await cEthToken.getCash()) .add(await cEthToken.totalBorrows()) .sub(await cEthToken.totalReserves()) .div(await cEthToken.totalSupply()); @@ -909,30 +875,32 @@ describe("Debt Bridge with External Provider", function () { compoundPosition[0].borrowBalanceStoredUser ); - // Estimated amount of collateral should be equal to the actual one read on compound contracts + // Estimated amount of pricedCollateral should be equal to the actual one read on compound contracts expect( expectedColWithdrawAmount.sub( compoundPosition[1].balanceOfUser.mul(exchangeRateCethToEth) ) ).to.be.lt(ethers.utils.parseUnits("1", 12)); - debt = await connectGelatoDebtBridge.getMakerVaultDebt(cdpId); - collateral = await connectGelatoDebtBridge.getMakerVaultCollateralBalance( - cdpId + const debtOnMakerAfter = await connectGelatoDebtBridgeFromMaker.getMakerVaultDebt( + vaultId + ); + const collateralOnMakerAfter = await connectGelatoDebtBridgeFromMaker.getMakerVaultCollateralBalance( + vaultId ); // in Ether. // Total Borrowed Amount on both protocol should equal to the initial borrowed amount on maker vault. expect( - debt + debtOnMakerAfter .add(compoundPosition[0].borrowBalanceStoredUser) - .sub(makerVaultInitialBorrow) + .sub(MAKER_INITIAL_DEBT) ).to.be.lte(ethers.utils.parseUnits("1", 0)); - // Total Ether col on Maker and Compound (+ fees) should equal to the initial col on maker vault + // Total Ether col on Maker and Compound (+ gasFeesPaidFromCol) should equal to the initial col on maker vault expect( compoundPosition[1].balanceOfUser .mul(exchangeRateCethToEth) - .add(fees) - .add(collateral) + .add(gasFeesPaidFromCol) + .add(collateralOnMakerAfter) .sub(ethers.utils.parseEther("10")) ).to.be.lt(ethers.utils.parseUnits("1", 12)); @@ -944,21 +912,21 @@ describe("Debt Bridge with External Provider", function () { latestPrice ), compoundPosition[0].borrowBalanceStoredUser - ).sub(wantedLiquidationRatioOnProtocol2) + ).sub(MIN_COL_RATIO_MAKER) ).to.be.lt(ethers.utils.parseUnits("1", 12)); expect( wdiv( wmul( - collateral, - await oracleAggregator.getMakerTokenPrice(currencyPair) + collateralOnMakerAfter, + await priceOracleResolver.getMockPrice(userAddress) ), - debt - ).sub(wantedLiquidationRatioOnProtocol1) + debtOnMakerAfter + ).sub(MIN_COL_RATIO_MAKER) ).to.be.lt(ethers.utils.parseUnits("1", 1)); // DSA contain 1000 DAI expect(await daiToken.balanceOf(dsa.address)).to.be.equal( - makerVaultInitialBorrow + MAKER_INITIAL_DEBT ); //#endregion diff --git a/test/3_ConditionMakerVaultIsSafe.test.js b/test/3_ConditionMakerVaultUnsafe.test.js similarity index 54% rename from test/3_ConditionMakerVaultIsSafe.test.js rename to test/3_ConditionMakerVaultUnsafe.test.js index b7a0197..3016273 100644 --- a/test/3_ConditionMakerVaultIsSafe.test.js +++ b/test/3_ConditionMakerVaultUnsafe.test.js @@ -1,6 +1,6 @@ const {expect} = require("chai"); -const bre = require("@nomiclabs/buidler"); -const {ethers} = bre; +const hre = require("hardhat"); +const {ethers} = hre; // #region Contracts ABI @@ -12,12 +12,16 @@ const InstaAccount = require("../pre-compiles/InstaAccount.json"); const InstaIndex = require("../pre-compiles/InstaIndex.json"); const IERC20 = require("../pre-compiles/IERC20.json"); +const ORACLE_MAKER_ETH_USD = "ETH/USD-Maker-v1"; +const ORACLE_MAKER_ETH_USD_ADDR = "0x729D19f657BD0614b4985Cf1D82531c67569197B"; +const PRICE_ORACLE_MAKER_PAYLOAD = "0x57de26a4"; // IMakerOracle.read() + // #endregion -describe("ConditionMakerVaultIsSafe gelato condition contract unit test", function () { +describe("ConditionMakerVaultUnsafe Unit Test", function () { this.timeout(0); - if (bre.network.name !== "ganache") { - console.error("Test Suite is meant to be run on ganache only"); + if (hre.network.name !== "hardhat") { + console.error("Test Suite is meant to be run on hardhat only"); process.exit(1); } @@ -30,8 +34,8 @@ describe("ConditionMakerVaultIsSafe gelato condition contract unit test", functi let instaIndex; let daiToken; - let conditionMakerVaultIsSafe; - let oracleAggregator; + let conditionMakerVaultUnsafe; + let priceOracleResolver; let cdpId; let dsa; @@ -41,46 +45,44 @@ describe("ConditionMakerVaultIsSafe gelato condition contract unit test", functi [userWallet] = await ethers.getSigners(); userAddress = await userWallet.getAddress(); - // Ganache default accounts prefilled with 100 ETH + // Hardhat default accounts prefilled with 100 ETH expect(await userWallet.getBalance()).to.be.gt( ethers.utils.parseEther("10") ); instaIndex = await ethers.getContractAt( InstaIndex.abi, - bre.network.config.InstaIndex + hre.network.config.InstaIndex ); instaList = await ethers.getContractAt( InstaList.abi, - bre.network.config.InstaList + hre.network.config.InstaList ); getCdps = await ethers.getContractAt( GetCdps.abi, - bre.network.config.GetCdps + hre.network.config.GetCdps ); dssCdpManager = await ethers.getContractAt( DssCdpManager.abi, - bre.network.config.DssCdpManager + hre.network.config.DssCdpManager ); - daiToken = await ethers.getContractAt(IERC20.abi, bre.network.config.DAI); + daiToken = await ethers.getContractAt(IERC20.abi, hre.network.config.DAI); // ========== Test Setup ============ - const OracleAggregator = await ethers.getContractFactory( - "OracleAggregator" + const PriceOracleResolver = await ethers.getContractFactory( + "PriceOracleResolver" ); - oracleAggregator = await OracleAggregator.deploy(); - await oracleAggregator.deployed(); + priceOracleResolver = await PriceOracleResolver.deploy(); + await priceOracleResolver.deployed(); - const ConditionMakerVaultIsSafe = await ethers.getContractFactory( - "ConditionMakerVaultIsSafe" + const ConditionMakerVaultUnsafe = await ethers.getContractFactory( + "ConditionMakerVaultUnsafe" ); - conditionMakerVaultIsSafe = await ConditionMakerVaultIsSafe.deploy( - oracleAggregator.address - ); - await conditionMakerVaultIsSafe.deployed(); + conditionMakerVaultUnsafe = await ConditionMakerVaultUnsafe.deploy(); + await conditionMakerVaultUnsafe.deployed(); // Create DeFi Smart Account @@ -100,13 +102,13 @@ describe("ConditionMakerVaultIsSafe gelato condition contract unit test", functi ); // Create/Deposit/Borrow a Vault - const openVault = await bre.run("abi-encode-withselector", { + const openVault = await hre.run("abi-encode-withselector", { abi: ConnectMaker.abi, functionname: "open", inputs: ["ETH-A"], }); - await dsa.cast([bre.network.config.ConnectMaker], [openVault], userAddress); + await dsa.cast([hre.network.config.ConnectMaker], [openVault], userAddress); let cdps = await getCdps.getCdpsAsc(dssCdpManager.address, dsa.address); cdpId = String(cdps.ids[0]); @@ -114,9 +116,9 @@ describe("ConditionMakerVaultIsSafe gelato condition contract unit test", functi expect(cdps.ids[0].isZero()).to.be.false; await dsa.cast( - [bre.network.config.ConnectMaker], + [hre.network.config.ConnectMaker], [ - await bre.run("abi-encode-withselector", { + await hre.run("abi-encode-withselector", { abi: ConnectMaker.abi, functionname: "deposit", inputs: [cdpId, ethers.utils.parseEther("10"), 0, 0], @@ -128,9 +130,9 @@ describe("ConditionMakerVaultIsSafe gelato condition contract unit test", functi } ); await dsa.cast( - [bre.network.config.ConnectMaker], + [hre.network.config.ConnectMaker], [ - await bre.run("abi-encode-withselector", { + await hre.run("abi-encode-withselector", { abi: ConnectMaker.abi, functionname: "borrow", inputs: [cdpId, ethers.utils.parseUnits("1000", 18), 0, 0], @@ -142,41 +144,48 @@ describe("ConditionMakerVaultIsSafe gelato condition contract unit test", functi expect(await daiToken.balanceOf(dsa.address)).to.be.equal( ethers.utils.parseEther("1000") ); - // Add ETH/USD Maker Medianizer in the Oracle Aggregator + // Add ETH/USD Maker Medianizer in the PriceOracleResolver - await oracleAggregator.addOracle( - "ETH/USD", - "0x729D19f657BD0614b4985Cf1D82531c67569197B" + await priceOracleResolver.addOracle( + ORACLE_MAKER_ETH_USD, + ORACLE_MAKER_ETH_USD_ADDR, + PRICE_ORACLE_MAKER_PAYLOAD ); }); - it("#1: ok should return NotOKMakerVaultIsSafe when the ETH/USD price is above the defined limit", async function () { - let data = await conditionMakerVaultIsSafe.getConditionData( + it("#1: ok should return MakerVaultNotUnsafe when the ETH/USD price is above the defined limit", async function () { + const conditionData = await conditionMakerVaultUnsafe.getConditionData( cdpId, - "ETH/USD", + ORACLE_MAKER_ETH_USD_ADDR, + PRICE_ORACLE_MAKER_PAYLOAD, ethers.utils.parseUnits("30", 17) ); - expect(await conditionMakerVaultIsSafe.ok(0, data, 0)).to.be.equal( - "NotOKMakerVaultIsSafe" + expect(await conditionMakerVaultUnsafe.ok(0, conditionData, 0)).to.be.equal( + "MakerVaultNotUnsafe" ); }); it("#2: ok should return OK when the ETH/USD price is lower than the defined limit", async function () { - let data = await conditionMakerVaultIsSafe.getConditionData( + const conditionData = await conditionMakerVaultUnsafe.getConditionData( cdpId, - "ETH/USD", + priceOracleResolver.address, + await hre.run("abi-encode-withselector", { + abi: (await hre.artifacts.readArtifact("PriceOracleResolver")).abi, + functionname: "getMockPrice", + inputs: [userAddress], + }), ethers.utils.parseUnits("30", 17) ); //#region Mock Part - oracleAggregator.mock(true, ethers.utils.parseUnits("299", 18)); + priceOracleResolver.setMockPrice(ethers.utils.parseUnits("299", 18)); //#endregion - expect(await conditionMakerVaultIsSafe.ok(0, data, 0)).to.be.equal( - "NotOKMakerVaultIsSafe" + expect(await conditionMakerVaultUnsafe.ok(0, conditionData, 0)).to.be.equal( + "OK" ); }); }); diff --git a/test/4_ConnectGelatoProviderPayment.test.js b/test/4_ConnectGelatoProviderPayment.test.js index 5abc6c4..b244c1f 100644 --- a/test/4_ConnectGelatoProviderPayment.test.js +++ b/test/4_ConnectGelatoProviderPayment.test.js @@ -1,6 +1,6 @@ const {expect} = require("chai"); -const bre = require("@nomiclabs/buidler"); -const {ethers} = bre; +const hre = require("hardhat"); +const {ethers} = hre; // #region Contracts ABI @@ -13,14 +13,13 @@ const InstaAccount = require("../pre-compiles/InstaAccount.json"); const InstaIndex = require("../pre-compiles/InstaIndex.json"); const IERC20 = require("../pre-compiles/IERC20.json"); const InstaConnector = require("../pre-compiles/InstaConnectors.json"); -const ConnectGelatoProviderPaymentABI = require("../artifacts/ConnectGelatoProviderPayment.json"); // #endregion -describe("Gelato Provider Payment Connector unit test", function () { +describe("ConnectGelatoProviderPayment Unit Test", function () { this.timeout(0); - if (bre.network.name !== "ganache") { - console.error("Test Suite is meant to be run on ganache only"); + if (hre.network.name !== "hardhat") { + console.error("Test Suite is meant to be run on hardhat only"); process.exit(1); } @@ -52,39 +51,39 @@ describe("Gelato Provider Payment Connector unit test", function () { providerAddress = await providerWallet.getAddress(); instaMaster = await ethers.provider.getSigner( - bre.network.config.InstaMaster + hre.network.config.InstaMaster ); - // Ganache default accounts prefilled with 100 ETH + // Hardhat default accounts prefilled with 100 ETH expect(await userWallet.getBalance()).to.be.gt( ethers.utils.parseEther("10") ); instaIndex = await ethers.getContractAt( InstaIndex.abi, - bre.network.config.InstaIndex + hre.network.config.InstaIndex ); instaList = await ethers.getContractAt( InstaList.abi, - bre.network.config.InstaList + hre.network.config.InstaList ); connectBasic = await ethers.getContractAt( ConnectBasic.abi, - bre.network.config.ConnectBasic + hre.network.config.ConnectBasic ); instaConnectors = await ethers.getContractAt( InstaConnector.abi, - bre.network.config.InstaConnectors + hre.network.config.InstaConnectors ); getCdps = await ethers.getContractAt( GetCdps.abi, - bre.network.config.GetCdps + hre.network.config.GetCdps ); dssCdpManager = await ethers.getContractAt( DssCdpManager.abi, - bre.network.config.DssCdpManager + hre.network.config.DssCdpManager ); - daiToken = await ethers.getContractAt(IERC20.abi, bre.network.config.DAI); + daiToken = await ethers.getContractAt(IERC20.abi, hre.network.config.DAI); // ========== Test Setup ============ @@ -99,13 +98,23 @@ describe("Gelato Provider Payment Connector unit test", function () { ); connectGelatoProviderPayment.deployed(); + await userWallet.sendTransaction({ + to: hre.network.config.InstaMaster, + value: ethers.utils.parseEther("0.1"), + }); + + await hre.network.provider.request({ + method: "hardhat_impersonateAccount", + params: [await instaMaster.getAddress()], + }); + await instaConnectors .connect(instaMaster) .enable(connectGelatoProviderPayment.address); - await userWallet.sendTransaction({ - to: bre.network.config.InstaMaster, - value: ethers.utils.parseEther("0.1"), + await hre.network.provider.request({ + method: "hardhat_stopImpersonatingAccount", + params: [await instaMaster.getAddress()], }); expect( @@ -130,13 +139,13 @@ describe("Gelato Provider Payment Connector unit test", function () { ); }); - it("#1: payProvider should pay to Provider 300x10^18 token dai", async function () { - let providerDAIBalanceBefore = await daiToken.balanceOf(providerAddress); + it("#1: payProvider should pay to Provider 300 Dai", async function () { + const providerDAIBalanceBefore = await daiToken.balanceOf(providerAddress); await dsa.cast( - [bre.network.config.ConnectMaker], + [hre.network.config.ConnectMaker], [ - await bre.run("abi-encode-withselector", { + await hre.run("abi-encode-withselector", { abi: ConnectMaker.abi, functionname: "open", inputs: ["ETH-A"], @@ -145,15 +154,15 @@ describe("Gelato Provider Payment Connector unit test", function () { userAddress ); - let cdps = await getCdps.getCdpsAsc(dssCdpManager.address, dsa.address); + const cdps = await getCdps.getCdpsAsc(dssCdpManager.address, dsa.address); cdpId = String(cdps.ids[0]); expect(cdps.ids[0].isZero()).to.be.false; await dsa.cast( - [bre.network.config.ConnectMaker], + [hre.network.config.ConnectMaker], [ - await bre.run("abi-encode-withselector", { + await hre.run("abi-encode-withselector", { abi: ConnectMaker.abi, functionname: "deposit", inputs: [cdpId, ethers.utils.parseEther("10"), 0, 0], @@ -165,9 +174,9 @@ describe("Gelato Provider Payment Connector unit test", function () { } ); await dsa.cast( - [bre.network.config.ConnectMaker], + [hre.network.config.ConnectMaker], [ - await bre.run("abi-encode-withselector", { + await hre.run("abi-encode-withselector", { abi: ConnectMaker.abi, functionname: "borrow", inputs: [cdpId, ethers.utils.parseUnits("1000", 18), 0, 0], @@ -183,8 +192,10 @@ describe("Gelato Provider Payment Connector unit test", function () { await dsa.cast( [connectGelatoProviderPayment.address], [ - await bre.run("abi-encode-withselector", { - abi: ConnectGelatoProviderPaymentABI.abi, + await hre.run("abi-encode-withselector", { + abi: ( + await hre.artifacts.readArtifact("ConnectGelatoProviderPayment") + ).abi, functionname: "payProvider", inputs: [ providerAddress, @@ -204,12 +215,12 @@ describe("Gelato Provider Payment Connector unit test", function () { }); it("#2: payProvider should pay to Provider 1 ether", async function () { - let providerBalanceBefore = await providerWallet.getBalance(); + const providerBalanceBefore = await providerWallet.getBalance(); await dsa.cast( [connectBasic.address, connectGelatoProviderPayment.address], [ - await bre.run("abi-encode-withselector", { + await hre.run("abi-encode-withselector", { abi: ConnectBasic.abi, functionname: "deposit", inputs: [ @@ -219,8 +230,10 @@ describe("Gelato Provider Payment Connector unit test", function () { "105", ], }), - await bre.run("abi-encode-withselector", { - abi: ConnectGelatoProviderPaymentABI.abi, + await hre.run("abi-encode-withselector", { + abi: ( + await hre.artifacts.readArtifact("ConnectGelatoProviderPayment") + ).abi, functionname: "payProvider", inputs: [ providerAddress, @@ -243,11 +256,11 @@ describe("Gelato Provider Payment Connector unit test", function () { }); it("#3: payProvider should return error message ConnectGelatoProviderPayment.payProvider:INVALIDADDESS when provider is Zero Address", async function () { - expect( + await expect( dsa.cast( [connectBasic.address, connectGelatoProviderPayment.address], [ - await bre.run("abi-encode-withselector", { + await hre.run("abi-encode-withselector", { abi: ConnectBasic.abi, functionname: "deposit", inputs: [ @@ -257,8 +270,10 @@ describe("Gelato Provider Payment Connector unit test", function () { "105", ], }), - await bre.run("abi-encode-withselector", { - abi: ConnectGelatoProviderPaymentABI.abi, + await hre.run("abi-encode-withselector", { + abi: ( + await hre.artifacts.readArtifact("ConnectGelatoProviderPayment") + ).abi, functionname: "payProvider", inputs: [ ethers.constants.AddressZero, @@ -274,8 +289,6 @@ describe("Gelato Provider Payment Connector unit test", function () { value: ethers.utils.parseEther("1"), } ) - ).to.be.revertedWith( - "ConnectGelatoProviderPayment.payProvider:INVALIDADDESS." - ); + ).to.be.revertedWith("ConnectGelatoProviderPayment.payProvider:addr0"); }); }); diff --git a/test/5_OracleAggregator.test.js b/test/5_OracleAggregator.test.js deleted file mode 100644 index e77596d..0000000 --- a/test/5_OracleAggregator.test.js +++ /dev/null @@ -1,51 +0,0 @@ -const {expect} = require("chai"); -const bre = require("@nomiclabs/buidler"); -const {ethers} = bre; - -describe("Oracle Aggregator unit test", function () { - this.timeout(0); - if (bre.network.name !== "ganache") { - console.error("Test Suite is meant to be run on ganache only"); - process.exit(1); - } - - let oracleAggregator; - - before(async function () { - const OracleAggregator = await ethers.getContractFactory( - "OracleAggregator" - ); - oracleAggregator = await OracleAggregator.deploy(); - oracleAggregator.deployed(); - }); - - it("#1: addOracle should add a maker medianizer for a currencyPair", async function () { - await oracleAggregator.addOracle( - "ETH/USD", - "0x729D19f657BD0614b4985Cf1D82531c67569197B" - ); - expect(await oracleAggregator.makerOracle("ETH/USD")).to.be.equal( - "0x729D19f657BD0614b4985Cf1D82531c67569197B" - ); - }); - - it("#2: addOracle should revert when adding a maker medianizer and for this currency pair it was been already added", async function () { - expect( - oracleAggregator.addOracle( - "ETH/USD", - "0x729D19f657BD0614b4985Cf1D82531c67569197B" - ) - ).to.be.revertedWith("OracleAggregator.Maker: Oracle already set."); - }); - - it("#3: getMakerTokenPrice should return ETH/USD prize", async function () { - expect((await oracleAggregator.getMakerTokenPrice("ETH/USD")).isZero()).to - .be.false; - }); - - it("#4: getMakerTokenPrice should return OracleAggregator.getMakerTokenPrice: CurrencyPairNotSupported. when currencyPair are not supported / not been added", async function () { - expect(oracleAggregator.getMakerTokenPrice("ETH/DAI")).to.be.revertedWith( - "OracleAggregator.getMakerTokenPrice: CurrencyPairNotSupported." - ); - }); -}); diff --git a/test/5_PriceOracleResolver.test.js b/test/5_PriceOracleResolver.test.js new file mode 100644 index 0000000..d3638b1 --- /dev/null +++ b/test/5_PriceOracleResolver.test.js @@ -0,0 +1,60 @@ +const {expect} = require("chai"); +const hre = require("hardhat"); +const {ethers} = hre; + +const ORACLE_MAKER_ETH_USD = "ETH/USD-Maker-v1"; +const ORACLE_MAKER_ETH_USD_ADDR = "0x729D19f657BD0614b4985Cf1D82531c67569197B"; +const PRICE_ORACLE_MAKER_PAYLOAD = "0x57de26a4"; // IMakerOracle.read() + +describe("PriceOracleResolver Unit Test", function () { + this.timeout(0); + if (hre.network.name !== "hardhat") { + console.error("Test Suite is meant to be run on hardhat only"); + process.exit(1); + } + + let priceOracleResolver; + + before(async function () { + const PriceOracleResolver = await ethers.getContractFactory( + "PriceOracleResolver" + ); + priceOracleResolver = await PriceOracleResolver.deploy(); + priceOracleResolver.deployed(); + }); + + it("#1: addOracle should add a maker medianizer for a currencyPair", async function () { + await priceOracleResolver.addOracle( + ORACLE_MAKER_ETH_USD, + ORACLE_MAKER_ETH_USD_ADDR, + PRICE_ORACLE_MAKER_PAYLOAD + ); + expect(await priceOracleResolver.oracle(ORACLE_MAKER_ETH_USD)).to.be.equal( + ORACLE_MAKER_ETH_USD_ADDR + ); + expect( + await priceOracleResolver.oraclePayload(ORACLE_MAKER_ETH_USD) + ).to.be.equal(PRICE_ORACLE_MAKER_PAYLOAD); + }); + + it("#2: addOracle should revert when adding a maker medianizer and for this currency pair it was been already added", async function () { + await expect( + priceOracleResolver.addOracle( + ORACLE_MAKER_ETH_USD, + ethers.constants.AddressZero, + PRICE_ORACLE_MAKER_PAYLOAD + ) + ).to.be.revertedWith("PriceOracleResolver.addOracle: set"); + }); + + it("#3: getPrice returns price", async function () { + expect((await priceOracleResolver.getPrice(ORACLE_MAKER_ETH_USD)).isZero()) + .to.be.false; + }); + + it("#4: getMakerTokenPrice should return PriceOracleResolver.getMakerTokenPrice: CurrencyPairNotSupported. when currencyPair are not supported / not been added", async function () { + await expect(priceOracleResolver.getPrice("ETH/DAI")).to.be.revertedWith( + "PriceOracleResolver.getPrice: no oracle" + ); + }); +}); diff --git a/test/6_ProviderModuleDSA.test.js b/test/6_ProviderModuleDSA.test.js index eccac4f..1c5dce5 100644 --- a/test/6_ProviderModuleDSA.test.js +++ b/test/6_ProviderModuleDSA.test.js @@ -1,6 +1,6 @@ const {expect} = require("chai"); -const bre = require("@nomiclabs/buidler"); -const {ethers} = bre; +const hre = require("hardhat"); +const {ethers} = hre; const GelatoCoreLib = require("@gelatonetwork/core"); // #region Contracts ABI @@ -10,16 +10,15 @@ const InstaList = require("../pre-compiles/InstaList.json"); const InstaAccount = require("../pre-compiles/InstaAccount.json"); const InstaIndex = require("../pre-compiles/InstaIndex.json"); const InstaConnectors = require("../pre-compiles/InstaConnectors.json"); -const ConnectGelatoProviderPaymentABI = require("../artifacts/ConnectGelatoProviderPayment.json"); const ETH = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; // #endregion -describe("Provider Module unit test", function () { +describe("Provider Module Unit Test", function () { this.timeout(0); - if (bre.network.name !== "ganache") { - console.error("Test Suite is meant to be run on ganache only"); + if (hre.network.name !== "hardhat") { + console.error("Test Suite is meant to be run on hardhat only"); process.exit(1); } @@ -45,26 +44,26 @@ describe("Provider Module unit test", function () { [, providerWallet] = await ethers.getSigners(); providerAddress = await providerWallet.getAddress(); - // Ganache default accounts prefilled with 100 ETH + // Hardhat default accounts prefilled with 100 ETH expect(await userWallet.getBalance()).to.be.gt( ethers.utils.parseEther("10") ); /////////////////// Get Deployed Contract ////////////////// instaIndex = await ethers.getContractAt( InstaIndex.abi, - bre.network.config.InstaIndex + hre.network.config.InstaIndex ); instaConnectors = await ethers.getContractAt( InstaConnectors.abi, - bre.network.config.InstaConnectors + hre.network.config.InstaConnectors ); gelatoCore = await ethers.getContractAt( GelatoCoreLib.GelatoCore.abi, - bre.network.config.GelatoCore + hre.network.config.GelatoCore ); instaList = await ethers.getContractAt( InstaList.abi, - bre.network.config.InstaList + hre.network.config.InstaList ); ////////////////// Deploy Needed Contracts //////////////////////// @@ -83,7 +82,6 @@ describe("Provider Module unit test", function () { "ProviderModuleDSA" ); providerModuleDSA = await ProviderModuleDSA.deploy( - instaIndex.address, gelatoCore.address, connectGelatoProviderPayment.address ); @@ -128,11 +126,21 @@ describe("Provider Module unit test", function () { // }); it("#1: isProvided should return OK", async function () { + expect(await dsa.isAuth(gelatoCore.address)).to.be.false; + + expect( + await providerModuleDSA.isProvided( + dsa.address, + ethers.constants.AddressZero, + [[], [], 0, 0] + ) + ).to.not.be.equal("OK"); + // Give authorization to Gelato on user DSA await dsa.cast( - [bre.network.config.ConnectAuth], + [hre.network.config.ConnectAuth], [ - await bre.run("abi-encode-withselector", { + await hre.run("abi-encode-withselector", { abi: ConnectAuth.abi, functionname: "add", inputs: [gelatoCore.address], @@ -154,10 +162,11 @@ describe("Provider Module unit test", function () { it("#2: execPayload should return payload with the right provider", async function () { // Task creation for sending to execPayload - let payProvider = new GelatoCoreLib.Action({ + const payProvider = new GelatoCoreLib.Action({ addr: connectGelatoProviderPayment.address, - data: await bre.run("abi-encode-withselector", { - abi: ConnectGelatoProviderPaymentABI.abi, + data: await hre.run("abi-encode-withselector", { + abi: (await hre.artifacts.readArtifact("ConnectGelatoProviderPayment")) + .abi, functionname: "payProvider", inputs: [ethers.constants.AddressZero, ETH, 0, "105", 0], }), @@ -169,7 +178,7 @@ describe("Provider Module unit test", function () { actions: [payProvider], }); - let result = await providerModuleDSA.execPayload( + const result = await providerModuleDSA.execPayload( 0, ethers.constants.AddressZero, providerAddress, @@ -178,14 +187,14 @@ describe("Provider Module unit test", function () { ); //#region retrieving the replaced provider address from the payload - let abi = new ethers.utils.AbiCoder(); + const abi = new ethers.utils.AbiCoder(); - let datas = abi.decode( + const datas = abi.decode( ["address[]", "bytes[]", "address"], - ethers.utils.hexDataSlice(result.payload, 4) + ethers.utils.hexDataSlice(result[0], 4) )[1]; - let paymentReceivingAddress = abi.decode( + const paymentReceivingAddress = abi.decode( ["address", "address", "uint256", "uint256", "uint256"], ethers.utils.hexDataSlice(datas[0], 4) )[0]; diff --git a/test/7_ConnectGelatoDebtBridge.test.js b/test/7_ConnectGelatoDebtBridge.test.js index cda5b9e..4f80494 100644 --- a/test/7_ConnectGelatoDebtBridge.test.js +++ b/test/7_ConnectGelatoDebtBridge.test.js @@ -1,6 +1,6 @@ const {expect} = require("chai"); -const bre = require("@nomiclabs/buidler"); -const {ethers} = bre; +const hre = require("hardhat"); +const {ethers} = hre; const WAD = ethers.utils.parseUnits("1", 18); @@ -16,30 +16,29 @@ let wmul = (x, y) => { //#endregion -describe("Gelato Debt Bridge Connector unit test", function () { +describe("Gelato Debt Bridge Connector Unit Test", function () { this.timeout(0); - if (bre.network.name !== "ganache") { - console.error("Test Suite is meant to be run on ganache only"); + if (hre.network.name !== "hardhat") { + console.error("Test Suite is meant to be run on hardhat only"); process.exit(1); } - let connectGelatoDebtBridge; + let connectGelatoDebtBridgeFromMaker; before(async function () { - const ConnectGelatoDebtBridge = await ethers.getContractFactory( - "ConnectGelatoDebtBridge" + const ConnectGelatoDebtBridgeFromMaker = await ethers.getContractFactory( + "ConnectGelatoDebtBridgeFromMaker" ); - connectGelatoDebtBridge = await ConnectGelatoDebtBridge.deploy( - 0, - ethers.constants.AddressZero + connectGelatoDebtBridgeFromMaker = await ConnectGelatoDebtBridgeFromMaker.deploy( + 0 ); - connectGelatoDebtBridge.deployed(); + connectGelatoDebtBridgeFromMaker.deployed(); }); - it("#1: _wcollateralToWithdraw should return the amount of collateral to withdraw on protocol 1 and to put on protocol 2", async function () { + it("#1: wCalcCollateralToWithdraw should return the amount of collateral to withdraw on protocol 1 and to put on protocol 2", async function () { // 3 times more collateral than borrowed amount in protocol 1 - let wantedLiquidationRatioOnProtocol1 = ethers.utils.parseUnits("3", 18); + let minColRatioOnMaker = ethers.utils.parseUnits("3", 18); // 1.5 times more collateral than borrowed amount in protocol 2 - let wantedLiquidationRatioOnProtocol2 = ethers.utils.parseUnits("15", 17); + let minColRatioOnPositionB = ethers.utils.parseUnits("15", 17); // The amount of collateral locked let col = ethers.utils.parseUnits("1", 18); // The amount of borrowed token @@ -56,18 +55,15 @@ describe("Gelato Debt Bridge Connector unit test", function () { //#region CALCULATION REPLICATION let expectedColToWithdraw = wmul( - wmul( - wantedLiquidationRatioOnProtocol1, - wantedLiquidationRatioOnProtocol2 - ), + wmul(minColRatioOnMaker, minColRatioOnPositionB), borrowedToken ); // doc ref : c_r x comp_r x d_2 expectedColToWithdraw = expectedColToWithdraw.sub( - wmul(wantedLiquidationRatioOnProtocol1, collateral) + wmul(minColRatioOnMaker, collateral) ); // doc ref : c_r x comp_r x d_2 - c_r x e_2 expectedColToWithdraw = wdiv( expectedColToWithdraw, - wantedLiquidationRatioOnProtocol2.sub(wantedLiquidationRatioOnProtocol1) + minColRatioOnPositionB.sub(minColRatioOnMaker) ); // doc ref : (c_r x comp_r x d_2 - c_r x e_2)/ (comp_r - c_r) expectedColToWithdraw = collateral.sub(expectedColToWithdraw); // doc ref : e_2 - ((c_r x comp_r x d_2 - c_r x e_2)/ (comp_r - c_r)) @@ -77,21 +73,21 @@ describe("Gelato Debt Bridge Connector unit test", function () { //#endregion expect( - await connectGelatoDebtBridge.wcollateralToWithdraw( - wantedLiquidationRatioOnProtocol1, - wantedLiquidationRatioOnProtocol2, + await connectGelatoDebtBridgeFromMaker.wCalcCollateralToWithdraw( + minColRatioOnMaker, + minColRatioOnPositionB, + collateralPrice, collateral, - borrowedToken, - collateralPrice + borrowedToken ) ).to.be.equal(expectedColToWithdraw); }); - it("#2: _wborrowedTokenToPayback should return the amount of borrowed token to pay back on protocol 1", async function () { + it("#2: _wCalcDebtToRepay should return the amount of borrowed token to pay back on protocol 1", async function () { // 3 times more collateral than borrowed amount in protocol 1 - let wantedLiquidationRatioOnProtocol1 = ethers.utils.parseUnits("3", 18); + let minColRatioOnMaker = ethers.utils.parseUnits("3", 18); // 1.5 times more collateral than borrowed amount in protocol 2 - let wantedLiquidationRatioOnProtocol2 = ethers.utils.parseUnits("15", 17); + let minColRatioOnPositionB = ethers.utils.parseUnits("15", 17); // The amount of collateral locked let col = ethers.utils.parseUnits("1", 18); // The amount of borrowed token @@ -108,21 +104,18 @@ describe("Gelato Debt Bridge Connector unit test", function () { //#region CALCULATION REPLICATION let expectedBorToPayBack = wmul( - wmul( - wantedLiquidationRatioOnProtocol1, - wantedLiquidationRatioOnProtocol2 - ), + wmul(minColRatioOnMaker, minColRatioOnPositionB), borrowedToken ); // doc ref : c_r x comp_r x d_2 expectedBorToPayBack = expectedBorToPayBack.sub( - wmul(wantedLiquidationRatioOnProtocol1, collateral) + wmul(minColRatioOnMaker, collateral) ); // doc ref : c_r x comp_r x d_2 - c_r x e_2 expectedBorToPayBack = wdiv( expectedBorToPayBack, - wantedLiquidationRatioOnProtocol2.sub(wantedLiquidationRatioOnProtocol1) + minColRatioOnPositionB.sub(minColRatioOnMaker) ); // doc ref : (c_r x comp_r x d_2 - c_r x e_2)/ (comp_r - c_r) expectedBorToPayBack = wmul( - wdiv(ethers.utils.parseUnits("1", 18), wantedLiquidationRatioOnProtocol1), + wdiv(ethers.utils.parseUnits("1", 18), minColRatioOnMaker), expectedBorToPayBack ); // doc ref : (1/c_r)((c_r x comp_r x d_2 - c_r x e_2)/ (comp_r - c_r)) expectedBorToPayBack = borrowedToken.sub(expectedBorToPayBack); // doc ref : d_2 - (1/c_r)((c_r x comp_r x d_2 - c_r x e_2)/ (comp_r - c_r)) @@ -130,9 +123,9 @@ describe("Gelato Debt Bridge Connector unit test", function () { //#endregion expect( - await connectGelatoDebtBridge.wborrowedTokenToPayback( - wantedLiquidationRatioOnProtocol1, - wantedLiquidationRatioOnProtocol2, + await connectGelatoDebtBridgeFromMaker.wCalcDebtToRepay( + minColRatioOnMaker, + minColRatioOnPositionB, collateral, borrowedToken ) diff --git a/yarn.lock b/yarn.lock index 0321e2d..bb7b289 100644 --- a/yarn.lock +++ b/yarn.lock @@ -159,7 +159,18 @@ "@ethersproject/logger" "^5.0.5" "@ethersproject/properties" "^5.0.3" -"@ethersproject/address@5.0.5", "@ethersproject/address@>=5.0.0-beta.128", "@ethersproject/address@^5.0.4": +"@ethersproject/abstract-signer@5.0.7", "@ethersproject/abstract-signer@^5.0.6": + version "5.0.7" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.0.7.tgz#cdbd3bd479edf77c71b7f6a6156b0275b1176ded" + integrity sha512-8W8gy/QutEL60EoMEpvxZ8MFAEWs/JvH5nmZ6xeLXoZvmBCasGmxqHdYjo2cxg0nevkPkq9SeenSsBBZSCx+SQ== + dependencies: + "@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@5.0.5", "@ethersproject/address@>=5.0.0-beta.128", "@ethersproject/address@^5.0.4", "@ethersproject/address@^5.0.5": version "5.0.5" resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.0.5.tgz#2caa65f6b7125015395b1b54c985ee0b27059cc7" integrity sha512-DpkQ6rwk9jTefrRsJzEm6nhRiJd9pvhn1xN0rw5N/jswXG5r7BLk/GVA0mMAVWAsYfvi2xSc5L41FMox43RYEA== @@ -186,7 +197,7 @@ "@ethersproject/bytes" "^5.0.4" "@ethersproject/properties" "^5.0.3" -"@ethersproject/bignumber@5.0.8", "@ethersproject/bignumber@>=5.0.0-beta.130", "@ethersproject/bignumber@^5.0.7": +"@ethersproject/bignumber@5.0.8", "@ethersproject/bignumber@>=5.0.0-beta.130", "@ethersproject/bignumber@^5.0.7", "@ethersproject/bignumber@^5.0.8": version "5.0.8" resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.0.8.tgz#cee33bd8eb0266176def0d371b45274b1d2c4ec0" integrity sha512-KXFVAFKS1jdTXYN8BE5Oj+ZfPMh28iRdFeNGBVT6cUFdtiPVqeXqc0ggvBqA3A1VoFFGgM7oAeaagA393aORHA== @@ -234,6 +245,20 @@ "@ethersproject/logger" "^5.0.5" "@ethersproject/strings" "^5.0.4" +"@ethersproject/hash@5.0.6": + version "5.0.6" + resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.0.6.tgz#2a2e8a1470685421217e9e86e9971ca636e609ce" + integrity sha512-Gvh57v6BWhwnud6l7tMfQm32PRQ2DYx2WaAAQmAxAfYvmzUkpQCBstnGeNMXIL8/2wdkvcB2u+WZRWaZtsFuUQ== + dependencies: + "@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/hdnode@5.0.5", "@ethersproject/hdnode@^5.0.4": version "5.0.5" resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.0.5.tgz#1f89aad0a5ba9dfae3a85a36e0669f8bc7a74781" @@ -299,7 +324,7 @@ "@ethersproject/bytes" "^5.0.4" "@ethersproject/sha2" "^5.0.3" -"@ethersproject/properties@5.0.4", "@ethersproject/properties@>=5.0.0-beta.131", "@ethersproject/properties@^5.0.3": +"@ethersproject/properties@5.0.4", "@ethersproject/properties@>=5.0.0-beta.131", "@ethersproject/properties@^5.0.3", "@ethersproject/properties@^5.0.4": version "5.0.4" resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.0.4.tgz#a67a1f5a52c30850b5062c861631e73d131f666e" integrity sha512-UdyX3GqBxFt15B0uSESdDNmhvEbK3ACdDXl2soshoPcneXuTswHDeA0LoPlnaZzhbgk4p6jqb4GMms5C26Qu6A== @@ -331,6 +356,31 @@ bech32 "1.1.4" ws "7.2.3" +"@ethersproject/providers@5.0.14": + version "5.0.14" + resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.0.14.tgz#751ccb14b4a8c8e9e4be171818c23f4601be90ba" + integrity sha512-K9QRRkkHWyprm3g4L8U9aPx5uyivznL4RYemkN2shCQumyGqFJ5SO+OtQrgebVm0JpGwFAUGugnhRUh49sjErw== + dependencies: + "@ethersproject/abstract-provider" "^5.0.4" + "@ethersproject/abstract-signer" "^5.0.4" + "@ethersproject/address" "^5.0.4" + "@ethersproject/basex" "^5.0.3" + "@ethersproject/bignumber" "^5.0.7" + "@ethersproject/bytes" "^5.0.4" + "@ethersproject/constants" "^5.0.4" + "@ethersproject/hash" "^5.0.4" + "@ethersproject/logger" "^5.0.5" + "@ethersproject/networks" "^5.0.3" + "@ethersproject/properties" "^5.0.3" + "@ethersproject/random" "^5.0.3" + "@ethersproject/rlp" "^5.0.3" + "@ethersproject/sha2" "^5.0.3" + "@ethersproject/strings" "^5.0.4" + "@ethersproject/transactions" "^5.0.5" + "@ethersproject/web" "^5.0.6" + bech32 "1.1.4" + ws "7.2.3" + "@ethersproject/random@5.0.4", "@ethersproject/random@^5.0.3": version "5.0.4" resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.0.4.tgz#98f7cf65b0e588cec39ef24843e391ed5004556f" @@ -431,6 +481,27 @@ "@ethersproject/transactions" "^5.0.5" "@ethersproject/wordlists" "^5.0.4" +"@ethersproject/wallet@5.0.7": + version "5.0.7" + resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.0.7.tgz#9d4540f97d534e3d61548ace30f15857209b3f02" + integrity sha512-n2GX1+2Tc0qV8dguUcLkjNugINKvZY7u/5fEsn0skW9rz5+jHTR5IKMV6jSfXA+WjQT8UCNMvkI3CNcdhaPbTQ== + dependencies: + "@ethersproject/abstract-provider" "^5.0.4" + "@ethersproject/abstract-signer" "^5.0.4" + "@ethersproject/address" "^5.0.4" + "@ethersproject/bignumber" "^5.0.7" + "@ethersproject/bytes" "^5.0.4" + "@ethersproject/hash" "^5.0.4" + "@ethersproject/hdnode" "^5.0.4" + "@ethersproject/json-wallets" "^5.0.6" + "@ethersproject/keccak256" "^5.0.3" + "@ethersproject/logger" "^5.0.5" + "@ethersproject/properties" "^5.0.3" + "@ethersproject/random" "^5.0.3" + "@ethersproject/signing-key" "^5.0.4" + "@ethersproject/transactions" "^5.0.5" + "@ethersproject/wordlists" "^5.0.4" + "@ethersproject/web@5.0.9", "@ethersproject/web@^5.0.6": version "5.0.9" resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.0.9.tgz#b08f8295f4bfd4777c8723fe9572f5453b9f03cb" @@ -453,82 +524,10 @@ "@ethersproject/properties" "^5.0.3" "@ethersproject/strings" "^5.0.4" -"@gelatonetwork/core@0.5.3": - version "0.5.3" - resolved "https://registry.yarnpkg.com/@gelatonetwork/core/-/core-0.5.3.tgz#8193c25cc4a91aca08c4cdb4d6fc38459902065d" - integrity sha512-yZXpuFLMXY8gFI14S1CPelrYmRJCOq5hy6J5hI8/yov9Ksi9kTSL9iAyxbA+HdP1BEKQBucB5vneEFqFC6PD4Q== - -"@nomiclabs/buidler-ethers@2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@nomiclabs/buidler-ethers/-/buidler-ethers-2.0.2.tgz#56c7f3d6f2d1bbf701e97a0003abb30f1071b2c4" - integrity sha512-lFcM7HVi44JB5xl7MKD8qChPQ5tfeO02ZYlrI6uef7J1SJCgE+wiokrl7HQ/jb7DgTHS5agfZxVO9yUbkrMIrQ== - -"@nomiclabs/buidler-ganache@1.3.3": - version "1.3.3" - resolved "https://registry.yarnpkg.com/@nomiclabs/buidler-ganache/-/buidler-ganache-1.3.3.tgz#220beb381b0df45bf1860396df4a639267711066" - integrity sha512-5dReZ3qqkA8Y46qeuw4gM3hzyzTB8DPvc5xTz7TKSkCHE5iwe4mMBLjyJ0ZwVaxmQvr4zxkNC9LsQ8JVC/j6IA== - dependencies: - debug "^4.1.1" - ganache-core "^2.7.0" - ts-essentials "^2.0.7" - ts-interface-checker "^0.1.9" - -"@nomiclabs/buidler-waffle@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@nomiclabs/buidler-waffle/-/buidler-waffle-2.1.0.tgz#9869ac829162eb57ac4e4096f0a02bd7ef54a71a" - integrity sha512-Z1SJOGrRCcSu9E87mFaBHi4QimNxP9ZTYtJwLZCcyszS1fi0XLgp4syzTH3QXrQUBOP2P5oQMD6uCp0gNNS3hw== - dependencies: - "@types/sinon-chai" "^3.2.3" - "@types/web3" "1.0.19" - -"@nomiclabs/buidler@1.4.7": - version "1.4.7" - resolved "https://registry.yarnpkg.com/@nomiclabs/buidler/-/buidler-1.4.7.tgz#88436ba53e0e830d37c16601df59da4dbffde524" - integrity sha512-TyJKwKyKwu82uYPneqLf5HKFr96QX7cHDT7O7Ro93zmk1b84+EH9tn3zNIO/+96DMGISp8cCRwZhct89OwblRA== - dependencies: - "@nomiclabs/ethereumjs-vm" "^4.1.1" - "@sentry/node" "^5.18.1" - "@solidity-parser/parser" "^0.5.2" - "@types/bn.js" "^4.11.5" - "@types/lru-cache" "^5.1.0" - abort-controller "^3.0.0" - ansi-escapes "^4.3.0" - chalk "^2.4.2" - chokidar "^3.4.0" - ci-info "^2.0.0" - debug "^4.1.1" - deepmerge "^2.1.0" - download "^7.1.0" - enquirer "^2.3.0" - env-paths "^2.2.0" - eth-sig-util "^2.5.2" - ethereum-cryptography "^0.1.2" - ethereumjs-abi "^0.6.8" - ethereumjs-account "^3.0.0" - ethereumjs-block "^2.2.0" - ethereumjs-common "^1.3.2" - ethereumjs-tx "^2.1.1" - ethereumjs-util "^6.1.0" - find-up "^2.1.0" - fp-ts "1.19.3" - fs-extra "^7.0.1" - glob "^7.1.3" - io-ts "1.10.4" - is-installed-globally "^0.2.0" - lodash "^4.17.11" - merkle-patricia-tree "^3.0.0" - mocha "^7.1.2" - node-fetch "^2.6.0" - qs "^6.7.0" - raw-body "^2.4.1" - semver "^6.3.0" - slash "^3.0.0" - solc "0.6.8" - source-map-support "^0.5.13" - ts-essentials "^2.0.7" - tsort "0.0.1" - uuid "^3.3.2" - ws "^7.2.1" +"@gelatonetwork/core@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@gelatonetwork/core/-/core-1.0.0.tgz#57caedca0a19c945f509fc714358ab695aec7909" + integrity sha512-VuN+bVD8w+X/zwfFDOZHivuNOnzIHhHU0nYj8KJ01toFRnX6ABX428xUOO73mRQsiPVhmRxTu3eBBn9roWaNJw== "@nomiclabs/ethereumjs-vm@^4.1.1": version "4.2.0" @@ -551,6 +550,19 @@ safe-buffer "^5.1.1" util.promisify "^1.0.0" +"@nomiclabs/hardhat-ethers@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.0.0.tgz#ebab032b3aed03945ea560f56bb67aec56a30cbc" + integrity sha512-fIi6XP9PgKqwSNVcLDr6S5hvGlc21PendaLD5eGdXEXc9aYQ0OJX8Mk3evs+p78x7W9n9U3ZcKtTiGc1+YScDw== + +"@nomiclabs/hardhat-waffle@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-waffle/-/hardhat-waffle-2.0.0.tgz#b06533c802da1a9d614e432f719d2816384df9b3" + integrity sha512-CnG9JC0rgqa68LTgyETxBUEWYAovvNGVs5abqaXjG80eF7iMLjDjM8IjOM87siAaxaxFCf6VBMJmtueqVq7jZw== + dependencies: + "@types/sinon-chai" "^3.2.3" + "@types/web3" "1.0.19" + "@resolver-engine/core@^0.3.3": version "0.3.3" resolved "https://registry.yarnpkg.com/@resolver-engine/core/-/core-0.3.3.tgz#590f77d85d45bc7ecc4e06c654f41345db6ca967" @@ -661,15 +673,10 @@ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== -"@sindresorhus/is@^0.7.0": - version "0.7.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" - integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow== - -"@solidity-parser/parser@^0.5.2": - version "0.5.2" - resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.5.2.tgz#4d74670ead39e4f4fdab605a393ba8ea2390a2c4" - integrity sha512-uRyvnvVYmgNmTBpWDbBsH/0kPESQhQpEc4KsvMRLVzFJ1o1s0uIv0Y6Y9IB5vI1Dwz2CbS4X/y4Wyw/75cTFnQ== +"@solidity-parser/parser@^0.7.1": + version "0.7.1" + resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.7.1.tgz#660210130e4237476cb55e2882064809f80f861e" + integrity sha512-5ma2uuwPAEX1TPl2rAPAAuGlBkKnn2oUKQvnhTFlDIB8U/KDWX77FpHtL6Rcz+OwqSCWx9IClxACgyIEJ/GhIw== "@solidity-parser/parser@^0.8.1": version "0.8.1" @@ -840,6 +847,11 @@ acorn@^7.4.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== +adm-zip@^0.4.16: + version "0.4.16" + resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.16.tgz#cf4c508fdffab02c269cbc7f471a875f05570365" + integrity sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg== + aes-js@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" @@ -959,13 +971,6 @@ anymatch@~3.1.1: normalize-path "^3.0.0" picomatch "^2.0.4" -archive-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/archive-type/-/archive-type-4.0.0.tgz#f92e72233056dfc6969472749c267bdb046b1d70" - integrity sha1-+S5yIzBW38aWlHJ0nCZ72wRrHXA= - dependencies: - file-type "^4.2.0" - argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" @@ -1685,14 +1690,6 @@ bip39@2.5.0: safe-buffer "^5.0.1" unorm "^1.3.3" -bl@^1.0.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.3.tgz#1e8dd80142eac80d7158c9dccc047fb620e035e7" - integrity sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww== - dependencies: - readable-stream "^2.3.5" - safe-buffer "^5.1.1" - blakejs@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.1.0.tgz#69df92ef953aa88ca51a32df6ab1c54a155fc7a5" @@ -1853,29 +1850,6 @@ bs58check@^2.1.2: create-hash "^1.1.0" safe-buffer "^5.1.2" -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" - integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== - -buffer-alloc@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" - integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== - 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" - integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= - -buffer-fill@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" - integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= - buffer-from@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" @@ -1948,19 +1922,6 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" -cacheable-request@^2.1.1: - version "2.1.4" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-2.1.4.tgz#0d808801b6342ad33c91df9d0b44dc09b91e5c3d" - integrity sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0= - dependencies: - clone-response "1.0.2" - get-stream "3.0.0" - http-cache-semantics "3.8.1" - keyv "3.0.0" - lowercase-keys "1.0.0" - normalize-url "2.0.1" - responselike "1.0.2" - cacheable-request@^6.0.0: version "6.1.0" resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" @@ -2026,16 +1987,6 @@ caseless@~0.12.0: resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= -caw@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/caw/-/caw-2.0.1.tgz#6c3ca071fc194720883c2dc5da9b074bfc7e9e95" - integrity sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA== - dependencies: - get-proxy "^2.0.0" - isurl "^1.0.0-alpha5" - tunnel-agent "^0.6.0" - url-to-options "^1.0.1" - chai@4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5" @@ -2217,7 +2168,7 @@ cliui@^5.0.0: strip-ansi "^5.2.0" wrap-ansi "^5.1.0" -clone-response@1.0.2, clone-response@^1.0.2: +clone-response@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= @@ -2288,11 +2239,6 @@ commander@3.0.2: resolved "https://registry.yarnpkg.com/commander/-/commander-3.0.2.tgz#6837c3fb677ad9933d1cfba42dd14d5117d6b39e" integrity sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow== -commander@^2.8.1: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - commander@^6.0.0: version "6.1.0" resolved "https://registry.yarnpkg.com/commander/-/commander-6.1.0.tgz#f8d722b78103141006b66f4c7ba1e97315ba75bc" @@ -2323,15 +2269,7 @@ concat-stream@^1.5.1: readable-stream "^2.2.2" typedarray "^0.0.6" -config-chain@^1.1.11: - version "1.1.12" - resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa" - integrity sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA== - dependencies: - ini "^1.3.4" - proto-list "~1.2.1" - -content-disposition@0.5.3, content-disposition@^0.5.2: +content-disposition@0.5.3: version "0.5.3" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== @@ -2557,59 +2495,6 @@ decompress-response@^3.2.0, decompress-response@^3.3.0: 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" - integrity sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ== - 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" - integrity sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A== - 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" - integrity sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w== - 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" - integrity sha1-3qrM39FK6vhVePczroIQ+bSEj2k= - dependencies: - file-type "^3.8.0" - get-stream "^2.2.0" - pify "^2.3.0" - yauzl "^2.4.2" - -decompress@^4.2.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/decompress/-/decompress-4.2.1.tgz#007f55cc6a62c055afa37c07eb6a4ee1b773f118" - integrity sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ== - 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" - dedent@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" @@ -2639,11 +2524,6 @@ deep-is@^0.1.3, deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= -deepmerge@^2.1.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170" - integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA== - 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" @@ -2771,24 +2651,6 @@ dotignore@~0.1.2: dependencies: minimatch "^3.0.4" -download@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/download/-/download-7.1.0.tgz#9059aa9d70b503ee76a132897be6dec8e5587233" - integrity sha512-xqnBTVd/E+GxJVrX5/eUJiLYjCGPwMpdL+jGhGU57BvtcA7wwhtHVbXBeUk51kOpW3S7Jn3BQbN9Q1R1Km2qDQ== - dependencies: - archive-type "^4.0.0" - caw "^2.0.1" - content-disposition "^0.5.2" - decompress "^4.2.0" - ext-name "^5.0.0" - file-type "^8.1.0" - filenamify "^2.0.0" - get-stream "^3.0.0" - got "^8.3.1" - make-dir "^1.2.0" - p-event "^2.1.0" - pify "^3.0.0" - duplexer3@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" @@ -2863,7 +2725,7 @@ encoding@^0.1.11: dependencies: iconv-lite "^0.6.2" -end-of-stream@^1.0.0, end-of-stream@^1.1.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" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== @@ -3374,15 +3236,7 @@ ethereumjs-abi@0.6.7: bn.js "^4.11.8" ethereumjs-util "^6.0.0" -ethereumjs-abi@^0.6.8: - version "0.6.8" - resolved "https://registry.yarnpkg.com/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz#71bc152db099f70e62f108b7cdfca1b362c6fcae" - integrity sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA== - dependencies: - bn.js "^4.11.8" - ethereumjs-util "^6.0.0" - -"ethereumjs-abi@git+https://github.com/ethereumjs/ethereumjs-abi.git": +ethereumjs-abi@^0.6.8, "ethereumjs-abi@git+https://github.com/ethereumjs/ethereumjs-abi.git": version "0.6.8" resolved "git+https://github.com/ethereumjs/ethereumjs-abi.git#1ce6a1d64235fabe2aaf827fd606def55693508f" dependencies: @@ -3573,7 +3427,43 @@ ethereumjs-wallet@0.6.5: utf8 "^3.0.0" uuid "^3.3.2" -ethers@5.0.17, ethers@^5.0.0, ethers@^5.0.1: +ethers@5.0.19: + version "5.0.19" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.0.19.tgz#a4636f62a180135b13fd1f0a393477beafd535b7" + integrity sha512-0AZnUgZh98q888WAd1oI3aLeI+iyDtrupjANVtPPS7O63lVopkR/No8A1NqSkgl/rU+b2iuu2mUZor6GD4RG2w== + dependencies: + "@ethersproject/abi" "5.0.7" + "@ethersproject/abstract-provider" "5.0.5" + "@ethersproject/abstract-signer" "5.0.7" + "@ethersproject/address" "5.0.5" + "@ethersproject/base64" "5.0.4" + "@ethersproject/basex" "5.0.4" + "@ethersproject/bignumber" "5.0.8" + "@ethersproject/bytes" "5.0.5" + "@ethersproject/constants" "5.0.5" + "@ethersproject/contracts" "5.0.5" + "@ethersproject/hash" "5.0.6" + "@ethersproject/hdnode" "5.0.5" + "@ethersproject/json-wallets" "5.0.7" + "@ethersproject/keccak256" "5.0.4" + "@ethersproject/logger" "5.0.6" + "@ethersproject/networks" "5.0.4" + "@ethersproject/pbkdf2" "5.0.4" + "@ethersproject/properties" "5.0.4" + "@ethersproject/providers" "5.0.14" + "@ethersproject/random" "5.0.4" + "@ethersproject/rlp" "5.0.4" + "@ethersproject/sha2" "5.0.4" + "@ethersproject/signing-key" "5.0.5" + "@ethersproject/solidity" "5.0.5" + "@ethersproject/strings" "5.0.5" + "@ethersproject/transactions" "5.0.6" + "@ethersproject/units" "5.0.6" + "@ethersproject/wallet" "5.0.7" + "@ethersproject/web" "5.0.9" + "@ethersproject/wordlists" "5.0.5" + +ethers@^5.0.0, ethers@^5.0.1: version "5.0.17" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.0.17.tgz#35dea41f1d09d31f80e0bb4c03cb633cd6673756" integrity sha512-E0MrwCttHgdD6Irfa0B9cNdX0VoWVWLusaj51+EQalkl3pqhV2zGMPncfhYbc9+4nD2u81dbX8Pk9UN5kh/jew== @@ -3712,21 +3602,6 @@ express@^4.14.0: utils-merge "1.0.1" vary "~1.1.2" -ext-list@^2.0.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/ext-list/-/ext-list-2.2.2.tgz#0b98e64ed82f5acf0f2931babf69212ef52ddd37" - integrity sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA== - dependencies: - mime-db "^1.28.0" - -ext-name@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ext-name/-/ext-name-5.0.0.tgz#70781981d183ee15d13993c8822045c506c8f0a6" - integrity sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ== - dependencies: - ext-list "^2.0.0" - sort-keys-length "^1.0.0" - ext@^1.1.2: version "1.4.0" resolved "https://registry.yarnpkg.com/ext/-/ext-1.4.0.tgz#89ae7a07158f79d35517882904324077e4379244" @@ -3822,13 +3697,6 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= -fd-slicer@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" - integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4= - 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" @@ -3857,45 +3725,6 @@ file-entry-cache@^5.0.1: dependencies: flat-cache "^2.0.1" -file-type@^3.8.0: - version "3.9.0" - resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9" - integrity sha1-JXoHg4TR24CHvESdEH1SpSZyuek= - -file-type@^4.2.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/file-type/-/file-type-4.4.0.tgz#1b600e5fca1fbdc6e80c0a70c71c8dba5f7906c5" - integrity sha1-G2AOX8ofvcboDApwxxyNul95BsU= - -file-type@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/file-type/-/file-type-5.2.0.tgz#2ddbea7c73ffe36368dfae49dc338c058c2b8ad6" - integrity sha1-LdvqfHP/42No365J3DOMBYwritY= - -file-type@^6.1.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/file-type/-/file-type-6.2.0.tgz#e50cd75d356ffed4e306dc4f5bcf52a79903a919" - integrity sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg== - -file-type@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/file-type/-/file-type-8.1.0.tgz#244f3b7ef641bbe0cca196c7276e4b332399f68c" - integrity sha512-qyQ0pzAy78gVoJsmYeNgl8uH8yKhr1lVhW7JbzJmnlRi0I4R2eEDEJZVKG8agpDnLpacwNbDhLNG/LMdxHD2YQ== - -filename-reserved-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz#abf73dfab735d045440abfea2d91f389ebbfa229" - integrity sha1-q/c9+rc10EVECr/qLZHzieu/oik= - -filenamify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/filenamify/-/filenamify-2.1.0.tgz#88faf495fb1b47abfd612300002a16228c677ee9" - integrity sha512-ICw7NTT6RsDp2rnYKVd8Fu4cr6ITzGy3+u4vUujPkabyaz+03F24NWEX7fs5fp+kBonlaqPH8fAO2NM+SXt/JA== - dependencies: - filename-reserved-regex "^2.0.0" - strip-outer "^1.0.0" - trim-repeated "^1.0.0" - fill-range@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" @@ -3997,6 +3826,11 @@ flow-stoplight@^1.0.0: resolved "https://registry.yarnpkg.com/flow-stoplight/-/flow-stoplight-1.0.0.tgz#4a292c5bcff8b39fa6cc0cb1a853d86f27eeff7b" integrity sha1-SiksW8/4s5+mzAyxqFPYbyfu/3s= +follow-redirects@^1.12.1: + version "1.13.0" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db" + integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA== + for-each@~0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" @@ -4059,19 +3893,6 @@ fresh@0.5.2: resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= -from2@^2.1.1: - version "2.3.0" - resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" - integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= - dependencies: - inherits "^2.0.1" - readable-stream "^2.0.0" - -fs-constants@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" - integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== - fs-extra@^0.30.0: version "0.30.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" @@ -4128,7 +3949,7 @@ functional-red-black-tree@^1.0.1, functional-red-black-tree@~1.0.1: resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= -ganache-core@^2.10.2, ganache-core@^2.7.0: +ganache-core@^2.10.2: version "2.12.1" resolved "https://registry.yarnpkg.com/ganache-core/-/ganache-core-2.12.1.tgz#c21e8f7eca6e15f13756a353928357e0b8960d9e" integrity sha512-gycoVl3TChAbL6ZZQrK1gS2cNMheX+JXVBKTpMAzuLHwb5gE1CB1s6YYN3F7rB86opaEuldCSuTJK1dv4xYRAw== @@ -4183,31 +4004,16 @@ get-own-enumerable-property-symbols@^3.0.0: resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g== -get-proxy@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/get-proxy/-/get-proxy-2.1.0.tgz#349f2b4d91d44c4d4d4e9cba2ad90143fac5ef93" - integrity sha512-zmZIaQTWnNQb4R4fJUEp/FC51eZsc6EkErspy3xtIYStaq8EB/hDIWipxsal+E8rz0qD7f2sL/NA9Xee4RInJw== - dependencies: - npm-conf "^1.1.0" - get-stdin@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== -get-stream@3.0.0, get-stream@^3.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" integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= -get-stream@^2.2.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-2.3.1.tgz#5f38f93f346009666ee0150a054167f91bdd95de" - integrity sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4= - dependencies: - object-assign "^4.0.1" - pinkie-promise "^2.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" @@ -4265,13 +4071,6 @@ glob@^7.1.2, glob@^7.1.3, glob@~7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" -global-dirs@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" - integrity sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU= - dependencies: - ini "^1.3.4" - global@~4.3.0: version "4.3.2" resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f" @@ -4334,30 +4133,7 @@ got@^7.1.0: url-parse-lax "^1.0.0" url-to-options "^1.0.1" -got@^8.3.1: - version "8.3.2" - resolved "https://registry.yarnpkg.com/got/-/got-8.3.2.tgz#1d23f64390e97f776cac52e5b936e5f514d2e937" - integrity sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw== - dependencies: - "@sindresorhus/is" "^0.7.0" - cacheable-request "^2.1.1" - decompress-response "^3.3.0" - duplexer3 "^0.1.4" - get-stream "^3.0.0" - into-stream "^3.1.0" - is-retry-allowed "^1.1.0" - isurl "^1.0.0-alpha5" - lowercase-keys "^1.0.0" - mimic-response "^1.0.0" - p-cancelable "^0.4.0" - p-timeout "^2.0.1" - pify "^3.0.0" - safe-buffer "^5.1.1" - timed-out "^4.0.1" - url-parse-lax "^3.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.6, graceful-fs@^4.1.9: +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9: version "4.2.4" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== @@ -4380,6 +4156,56 @@ har-validator@~5.1.3: ajv "^6.12.3" har-schema "^2.0.0" +hardhat@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.0.0.tgz#d2d5fcbcdbb9b6ec13e7c8e93706ddf0e5ac2a70" + integrity sha512-kwl4fTn5jU4n3rlT1PucKETZ6qWzZiGgcUAqoqLc2ZADbcm1N9KUCbKzleidvgn+gTYcvVkhPTskkU2Yop6Lag== + dependencies: + "@nomiclabs/ethereumjs-vm" "^4.1.1" + "@sentry/node" "^5.18.1" + "@solidity-parser/parser" "^0.7.1" + "@types/bn.js" "^4.11.5" + "@types/lru-cache" "^5.1.0" + abort-controller "^3.0.0" + adm-zip "^0.4.16" + ansi-escapes "^4.3.0" + chalk "^2.4.2" + chokidar "^3.4.0" + ci-info "^2.0.0" + debug "^4.1.1" + enquirer "^2.3.0" + env-paths "^2.2.0" + eth-sig-util "^2.5.2" + ethereum-cryptography "^0.1.2" + ethereumjs-abi "^0.6.8" + ethereumjs-account "^3.0.0" + ethereumjs-block "^2.2.0" + ethereumjs-common "^1.5.0" + ethereumjs-tx "^2.1.1" + ethereumjs-util "^6.1.0" + find-up "^2.1.0" + fp-ts "1.19.3" + fs-extra "^7.0.1" + glob "^7.1.3" + immutable "^4.0.0-rc.12" + io-ts "1.10.4" + lodash "^4.17.11" + merkle-patricia-tree "^3.0.0" + mocha "^7.1.2" + node-fetch "^2.6.0" + qs "^6.7.0" + raw-body "^2.4.1" + resolve "1.17.0" + semver "^6.3.0" + slash "^3.0.0" + solc "0.7.3" + source-map-support "^0.5.13" + stacktrace-parser "^0.1.10" + "true-case-path" "^2.2.1" + tsort "0.0.1" + uuid "^3.3.2" + ws "^7.2.1" + has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" @@ -4509,11 +4335,6 @@ hosted-git-info@^2.1.4, hosted-git-info@^2.6.0: resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== -http-cache-semantics@3.8.1: - version "3.8.1" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" - integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== - 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" @@ -4625,6 +4446,11 @@ immediate@~3.2.3: resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.2.3.tgz#d140fa8f614659bd6541233097ddaac25cdd991c" integrity sha1-0UD6j2FGWb1lQSMwl92qwlzdmRw= +immutable@^4.0.0-rc.12: + version "4.0.0-rc.12" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0-rc.12.tgz#ca59a7e4c19ae8d9bf74a97bdf0f6e2f2a5d0217" + integrity sha512-0M2XxkZLx/mi3t8NVwIm1g8nHoEmM9p9UBl/G9k4+hm0kBgOVdMV/B3CY5dQ8qG8qc80NN4gDV4HQv6FTJ5q7A== + import-fresh@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" @@ -4669,11 +4495,6 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= -ini@^1.3.4: - version "1.3.5" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" - integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== - inquirer@^6.2.2: version "6.5.2" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca" @@ -4693,14 +4514,6 @@ inquirer@^6.2.2: strip-ansi "^5.1.0" through "^2.3.6" -into-stream@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6" - integrity sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY= - dependencies: - from2 "^2.1.1" - p-is-promise "^1.1.0" - invariant@^2.2.2: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" @@ -4881,19 +4694,6 @@ is-hex-prefixed@1.0.0: resolved "https://registry.yarnpkg.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" integrity sha1-fY035q135dEnFIkTxXPggtd39VQ= -is-installed-globally@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.2.0.tgz#8cde07ade508458b51f14bcda315ffaf4898de30" - integrity sha512-g3TzWCnR/eO4Q3abCwgFjOFw7uVOfxG4m8hMr/39Jcf2YvE5mHrFKqpyuraWV4zwx9XhjnVO4nY0ZI4llzl0Pg== - dependencies: - global-dirs "^0.1.1" - is-path-inside "^2.1.0" - -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" - integrity sha1-q5124dtM7VHjXeDHLr7PCfc0zeg= - is-negative-zero@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.0.tgz#9553b121b0fac28869da9ed459e20c7543788461" @@ -4921,14 +4721,7 @@ is-object@^1.0.1: resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" integrity sha1-iVJojF7C/9awPsyF52ngKQMINHA= -is-path-inside@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-2.1.0.tgz#7c9810587d659a40d27bcdb4d5616eab059494b2" - integrity sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg== - dependencies: - path-is-inside "^1.0.2" - -is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: +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" integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= @@ -4959,12 +4752,12 @@ is-regexp@^1.0.0: resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk= -is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0: +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" integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg== -is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0: +is-stream@^1.0.0, is-stream@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= @@ -5200,13 +4993,6 @@ keccak@^3.0.0: node-addon-api "^2.0.0" node-gyp-build "^4.2.0" -keyv@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373" - integrity sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA== - dependencies: - json-buffer "3.0.0" - keyv@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" @@ -5545,11 +5331,6 @@ loose-envify@^1.0.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" -lowercase-keys@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" - integrity sha1-TjNms55/VFfjXxMkvfb4jQv8cwY= - 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" @@ -5589,13 +5370,6 @@ ltgt@~2.1.1: resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.1.3.tgz#10851a06d9964b971178441c23c9e52698eece34" integrity sha1-EIUaBtmWS5cReEQcI8nlJpjuzjQ= -make-dir@^1.0.0, make-dir@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" - integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== - dependencies: - pify "^3.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" @@ -5733,11 +5507,6 @@ mime-db@1.44.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== -mime-db@^1.28.0: - version "1.45.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.45.0.tgz#cceeda21ccd7c3a745eba2decd55d4b73e7879ea" - integrity sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w== - 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" @@ -6029,28 +5798,11 @@ normalize-path@^3.0.0, normalize-path@~3.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== -normalize-url@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-2.0.1.tgz#835a9da1551fa26f70e92329069a23aa6574d7e6" - integrity sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw== - dependencies: - prepend-http "^2.0.0" - query-string "^5.0.1" - sort-keys "^2.0.0" - normalize-url@^4.1.0: version "4.5.0" resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129" integrity sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ== -npm-conf@^1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/npm-conf/-/npm-conf-1.1.3.tgz#256cc47bd0e218c259c4e9550bf413bc2192aff9" - integrity sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw== - dependencies: - config-chain "^1.1.11" - pify "^3.0.0" - npm-run-path@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" @@ -6076,7 +5828,7 @@ oauth-sign@~0.9.0: resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== -object-assign@^4, object-assign@^4.0.0, 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.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" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= @@ -6246,33 +5998,16 @@ p-cancelable@^0.3.0: resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa" integrity sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw== -p-cancelable@^0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0" - integrity sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ== - p-cancelable@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== -p-event@^2.1.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/p-event/-/p-event-2.3.1.tgz#596279ef169ab2c3e0cae88c1cfbb08079993ef6" - integrity sha512-NQCqOFhbpVTMX4qMe8PF8lbGtzZ+LCiN7pcNrb/413Na7+TRoe1xkKUzuWa/YEJdGQ0FvKtj35EEbDoVPO2kbA== - dependencies: - p-timeout "^2.0.1" - p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= -p-is-promise@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" - integrity sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4= - p-limit@^1.1.0: version "1.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" @@ -6322,13 +6057,6 @@ p-timeout@^1.1.1: dependencies: p-finally "^1.0.0" -p-timeout@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038" - integrity sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA== - dependencies: - p-finally "^1.0.0" - p-try@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" @@ -6502,11 +6230,6 @@ pbkdf2@^3.0.17, pbkdf2@^3.0.3, pbkdf2@^3.0.9: 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" - integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= - performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" @@ -6522,11 +6245,6 @@ pify@^2.0.0, pify@^2.3.0: resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= - pinkie-promise@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" @@ -6647,11 +6365,6 @@ promise-to-callback@^1.0.0: is-fn "^1.0.0" set-immediate-shim "^1.0.1" -proto-list@~1.2.1: - version "1.2.4" - resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" - integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk= - proxy-addr@~2.0.5: version "2.0.6" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" @@ -6854,7 +6567,7 @@ readable-stream@^1.0.33: isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.2.2, readable-stream@^2.2.8, readable-stream@^2.2.9, readable-stream@^2.3.0, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: +readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.2.2, readable-stream@^2.2.8, readable-stream@^2.2.9, readable-stream@^2.3.6, readable-stream@~2.3.6: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -7049,14 +6762,14 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@^1.10.0, resolve@~1.17.0: +resolve@1.17.0, resolve@^1.10.0, resolve@~1.17.0: version "1.17.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== dependencies: path-parse "^1.0.6" -responselike@1.0.2, responselike@^1.0.2: +responselike@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= @@ -7192,13 +6905,6 @@ seedrandom@3.0.1: resolved "https://registry.yarnpkg.com/seedrandom/-/seedrandom-3.0.1.tgz#eb3dde015bcf55df05a233514e5df44ef9dce083" integrity sha512-1/02Y/rUeU1CJBAGLebiC5Lbo5FnB22gQbIFFYTLkwvp1xdABZJH1sn4ZT1MzXmPpzv+Rf/Lu2NcsLJiK4rcDg== -seek-bzip@^1.0.5: - version "1.0.6" - resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-1.0.6.tgz#35c4171f55a680916b52a07859ecf3b5857f21c4" - integrity sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ== - dependencies: - commander "^2.8.1" - semaphore@>=1.0.1, semaphore@^1.0.3, semaphore@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/semaphore/-/semaphore-1.1.0.tgz#aaad8b86b20fe8e9b32b16dc2ee682a8cd26a8aa" @@ -7427,13 +7133,14 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" -solc@0.6.8: - version "0.6.8" - resolved "https://registry.yarnpkg.com/solc/-/solc-0.6.8.tgz#accf03634554938e166ba9b9853d17ca5c728131" - integrity sha512-7URBAisWVjO7dwWNpEkQ5dpRSpSF4Wm0aD5EB82D5BQKh+q7jhOxhgkG4K5gax/geM0kPZUAxnaLcgl2ZXBgMQ== +solc@0.7.3: + version "0.7.3" + resolved "https://registry.yarnpkg.com/solc/-/solc-0.7.3.tgz#04646961bd867a744f63d2b4e3c0701ffdc7d78a" + integrity sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA== dependencies: command-exists "^1.2.8" commander "3.0.2" + follow-redirects "^1.12.1" fs-extra "^0.30.0" js-sha3 "0.8.0" memorystream "^0.3.1" @@ -7495,27 +7202,6 @@ solhint@3.2.2: optionalDependencies: prettier "^1.14.3" -sort-keys-length@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/sort-keys-length/-/sort-keys-length-1.0.1.tgz#9cb6f4f4e9e48155a6aa0671edd336ff1479a188" - integrity sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg= - dependencies: - sort-keys "^1.0.0" - -sort-keys@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" - integrity sha1-RBttTTRnmPG05J6JIK37oOVD+a0= - dependencies: - is-plain-obj "^1.0.0" - -sort-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" - integrity sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg= - dependencies: - is-plain-obj "^1.0.0" - 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" @@ -7618,6 +7304,13 @@ sshpk@^1.7.0: safer-buffer "^2.0.2" tweetnacl "~0.14.0" +stacktrace-parser@^0.1.10: + version "0.1.10" + resolved "https://registry.yarnpkg.com/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz#29fb0cae4e0d0b85155879402857a1639eb6051a" + integrity sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg== + dependencies: + type-fest "^0.7.1" + static-extend@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" @@ -7771,13 +7464,6 @@ strip-bom@^2.0.0: dependencies: is-utf8 "^0.2.0" -strip-dirs@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/strip-dirs/-/strip-dirs-2.1.0.tgz#4987736264fc344cf20f6c34aca9d13d1d4ed6c5" - integrity sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g== - dependencies: - is-natural-number "^4.0.1" - strip-final-newline@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" @@ -7800,13 +7486,6 @@ strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -strip-outer@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/strip-outer/-/strip-outer-1.0.1.tgz#b2fd2abf6604b9d1e6013057195df836b8a9d631" - integrity sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg== - dependencies: - escape-string-regexp "^1.0.2" - supports-color@6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a" @@ -7881,19 +7560,6 @@ tape@^4.6.3: 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" - integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== - 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" @@ -7949,11 +7615,6 @@ tmp@0.1.0: dependencies: rimraf "^2.6.3" -to-buffer@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" - integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== - 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" @@ -8009,27 +7670,15 @@ tough-cookie@~2.5.0: psl "^1.1.28" punycode "^2.1.1" -trim-repeated@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/trim-repeated/-/trim-repeated-1.0.0.tgz#e3646a2ea4e891312bf7eace6cfb05380bc01c21" - integrity sha1-42RqLqTokTEr9+rObPsFOAvAHCE= - dependencies: - escape-string-regexp "^1.0.2" - trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= -ts-essentials@^2.0.7: - version "2.0.12" - resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-2.0.12.tgz#c9303f3d74f75fa7528c3d49b80e089ab09d8745" - integrity sha512-3IVX4nI6B5cc31/GFFE+i8ey/N2eA0CZDbo6n0yrz0zDX8ZJ8djmU1p+XRz7G3is0F3bB3pu2pAroFdAWQKU3w== - -ts-interface-checker@^0.1.9: - version "0.1.13" - resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" - integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== +"true-case-path@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-2.2.1.tgz#c5bf04a5bbec3fd118be4084461b3a27c4d796bf" + integrity sha512-0z3j8R7MCjy10kc/g+qg7Ln3alJTodw9aDuVWZa3uiWqfuBMKeAeP2ocWcxoyM3D73yz3Jt/Pu4qPr4wHSdB/Q== tslib@^1.9.0, tslib@^1.9.3: version "1.14.0" @@ -8087,6 +7736,11 @@ type-fest@^0.11.0: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1" integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ== +type-fest@^0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48" + integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg== + type-fest@^0.8.1: version "0.8.1" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" @@ -8144,14 +7798,6 @@ ultron@~1.1.0: resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" integrity sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og== -unbzip2-stream@^1.0.9: - version "1.4.3" - resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7" - integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg== - 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" @@ -8853,11 +8499,3 @@ yargs@^4.7.1: window-size "^0.2.0" y18n "^3.2.1" yargs-parser "^2.4.1" - -yauzl@^2.4.2: - version "2.10.0" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" - integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= - dependencies: - buffer-crc32 "~0.2.3" - fd-slicer "~1.1.0"