mirror of
https://github.com/Instadapp/Gelato-automations.git
synced 2024-07-29 22:28:07 +00:00
Add new Condition, Liq Pool routing and optional vault creation
This commit is contained in:
parent
49672c1826
commit
de8ad63dda
6
contracts/constants/CDebtBridge.sol
Normal file
6
contracts/constants/CDebtBridge.sol
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: UNLICENSED
|
||||||
|
pragma solidity 0.7.4;
|
||||||
|
|
||||||
|
function GAS_COSTS_FOR_FULL_REFINANCE() pure returns(uint256[4] memory) {
|
||||||
|
return [uint256(2519000), 3140500, 3971000, 4345000];
|
||||||
|
}
|
|
@ -12,3 +12,6 @@ address constant INSTA_POOL_V2 = 0x3150e5A805577366816A1ddc7330c6Ea17070c05;
|
||||||
// Tokens
|
// Tokens
|
||||||
address constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
|
address constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
|
||||||
address constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
|
address constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
|
||||||
|
|
||||||
|
// Insta Pool
|
||||||
|
address constant INSTA_POOL_RESOLVER = 0xa004a5afBa04b74037E9E52bA1f7eb02b5E61509;
|
|
@ -3,7 +3,7 @@ pragma solidity 0.7.4;
|
||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import {GelatoBytes} from "../../lib/GelatoBytes.sol";
|
import {GelatoBytes} from "../../lib/GelatoBytes.sol";
|
||||||
import {sub} from "../../vendor/DSMath.sol";
|
import {sub, wmul} from "../../vendor/DSMath.sol";
|
||||||
import {
|
import {
|
||||||
AccountInterface,
|
AccountInterface,
|
||||||
ConnectorInterface
|
ConnectorInterface
|
||||||
|
@ -39,6 +39,11 @@ import {
|
||||||
_encodeBorrowCompound
|
_encodeBorrowCompound
|
||||||
} from "../../functions/InstaDapp/connectors/FConnectCompound.sol";
|
} from "../../functions/InstaDapp/connectors/FConnectCompound.sol";
|
||||||
import {_getGelatoProviderFees} from "../../functions/gelato/FGelato.sol";
|
import {_getGelatoProviderFees} from "../../functions/gelato/FGelato.sol";
|
||||||
|
import {
|
||||||
|
_getFlashLoanRoute,
|
||||||
|
_getGasCost,
|
||||||
|
_getBorrowAmountWithDelta
|
||||||
|
} from "../../functions/gelato/FGelatoDebtBridge.sol";
|
||||||
|
|
||||||
contract ConnectGelatoDataForFullRefinance is ConnectorInterface {
|
contract ConnectGelatoDataForFullRefinance is ConnectorInterface {
|
||||||
using GelatoBytes for bytes;
|
using GelatoBytes for bytes;
|
||||||
|
@ -67,11 +72,13 @@ contract ConnectGelatoDataForFullRefinance is ConnectorInterface {
|
||||||
|
|
||||||
/// @notice Entry Point for DSA.cast DebtBridge from e.g ETH-A to ETH-B
|
/// @notice Entry Point for DSA.cast DebtBridge from e.g ETH-A to ETH-B
|
||||||
/// @dev payable to be compatible in conjunction with DSA.cast payable target
|
/// @dev payable to be compatible in conjunction with DSA.cast payable target
|
||||||
/// @param _vaultId Id of the unsafe vault of the client.
|
/// @param _vaultAId Id of the unsafe vault of the client of Vault A Collateral.
|
||||||
|
/// @param _vaultBId Id of the vault B Collateral of the client.
|
||||||
/// @param _token vault's col token address .
|
/// @param _token vault's col token address .
|
||||||
/// @param _colType colType of the new vault. example : ETH-B, ETH-A.
|
/// @param _colType colType of the new vault. example : ETH-B, ETH-A.
|
||||||
function getDataAndCastForFromMakerToMaker(
|
function getDataAndCastForFromMakerToMaker(
|
||||||
uint256 _vaultId,
|
uint256 _vaultAId,
|
||||||
|
uint256 _vaultBId,
|
||||||
address _token,
|
address _token,
|
||||||
string calldata _colType
|
string calldata _colType
|
||||||
) external payable {
|
) external payable {
|
||||||
|
@ -79,7 +86,8 @@ contract ConnectGelatoDataForFullRefinance is ConnectorInterface {
|
||||||
address[] memory targets,
|
address[] memory targets,
|
||||||
bytes[] memory datas
|
bytes[] memory datas
|
||||||
) = _execPayloadForFullRefinanceFromMakerToMaker(
|
) = _execPayloadForFullRefinanceFromMakerToMaker(
|
||||||
_vaultId,
|
_vaultAId,
|
||||||
|
_vaultBId,
|
||||||
_token,
|
_token,
|
||||||
_colType
|
_colType
|
||||||
);
|
);
|
||||||
|
@ -124,48 +132,47 @@ contract ConnectGelatoDataForFullRefinance is ConnectorInterface {
|
||||||
/* solhint-disable function-max-lines */
|
/* solhint-disable function-max-lines */
|
||||||
|
|
||||||
function _execPayloadForFullRefinanceFromMakerToMaker(
|
function _execPayloadForFullRefinanceFromMakerToMaker(
|
||||||
uint256 _vaultId,
|
uint256 _vaultAId,
|
||||||
|
uint256 _vaultBId,
|
||||||
address _token,
|
address _token,
|
||||||
string calldata _colType
|
string calldata _colType
|
||||||
) internal view returns (address[] memory targets, bytes[] memory datas) {
|
) internal view returns (address[] memory targets, bytes[] memory datas) {
|
||||||
targets = new address[](1);
|
targets = new address[](1);
|
||||||
targets[0] = INSTA_POOL_V2;
|
targets[0] = INSTA_POOL_V2;
|
||||||
|
|
||||||
uint256 wDaiDebtToMove = _getMakerVaultDebt(_vaultId);
|
uint256 wDaiDebtToMove = _getMakerVaultDebt(_vaultAId);
|
||||||
|
uint256 wDaiToBorrow = _getBorrowAmountWithDelta(wDaiDebtToMove);
|
||||||
uint256 wColToWithdrawFromMaker = _getMakerVaultCollateralBalance(
|
uint256 wColToWithdrawFromMaker = _getMakerVaultCollateralBalance(
|
||||||
_vaultId
|
_vaultAId
|
||||||
);
|
);
|
||||||
uint256 gasFeesPaidFromCol = _getGelatoProviderFees(GAS_COST);
|
uint256 route = _getFlashLoanRoute(DAI, wDaiDebtToMove);
|
||||||
|
uint256 gasCost = _getGasCost(route);
|
||||||
|
uint256 gasFeesPaidFromCol = _getGelatoProviderFees(gasCost);
|
||||||
|
|
||||||
address[] memory _targets = new address[](7);
|
(address[] memory _targets, bytes[] memory _datas) = _vaultBId == 0
|
||||||
_targets[0] = CONNECT_MAKER; // payback
|
? _spellsDebtBridgeWithOpenVaultAction(
|
||||||
_targets[1] = CONNECT_MAKER; // withdraw
|
_vaultAId,
|
||||||
_targets[2] = CONNECT_MAKER; // open ETH-B vault
|
_token,
|
||||||
_targets[3] = CONNECT_MAKER; // deposit
|
_colType,
|
||||||
_targets[4] = CONNECT_MAKER; // borrow
|
wDaiToBorrow,
|
||||||
_targets[5] = _connectGelatoProviderPayment; // payProvider
|
wColToWithdrawFromMaker,
|
||||||
_targets[6] = INSTA_POOL_V2; // flashPayback
|
gasFeesPaidFromCol
|
||||||
|
)
|
||||||
bytes[] memory _datas = new bytes[](7);
|
: _spellsDebtBridge(
|
||||||
_datas[0] = _encodePaybackMakerVault(_vaultId, uint256(-1), 0, 0);
|
_vaultAId,
|
||||||
_datas[1] = _encodedWithdrawMakerVault(_vaultId, uint256(-1), 0, 0);
|
_vaultBId,
|
||||||
_datas[2] = _encodeOpenMakerVault(_colType);
|
_token,
|
||||||
_datas[3] = _encodedDepositMakerVault(
|
wDaiToBorrow,
|
||||||
0,
|
wColToWithdrawFromMaker,
|
||||||
sub(wColToWithdrawFromMaker, gasFeesPaidFromCol),
|
gasFeesPaidFromCol
|
||||||
0,
|
);
|
||||||
0
|
|
||||||
);
|
|
||||||
_datas[4] = _encodeBorrowDaiMakerVault(0, wDaiDebtToMove, 0, 0);
|
|
||||||
_datas[5] = _encodePayGelatoProvider(_token, gasFeesPaidFromCol, 0, 0);
|
|
||||||
_datas[6] = _encodeFlashPayback(DAI, wDaiDebtToMove, 0, 0);
|
|
||||||
|
|
||||||
datas = new bytes[](1);
|
datas = new bytes[](1);
|
||||||
datas[0] = abi.encodeWithSelector(
|
datas[0] = abi.encodeWithSelector(
|
||||||
IConnectInstaPoolV2.flashBorrowAndCast.selector,
|
IConnectInstaPoolV2.flashBorrowAndCast.selector,
|
||||||
DAI,
|
DAI,
|
||||||
wDaiDebtToMove,
|
wDaiToBorrow,
|
||||||
0,
|
route,
|
||||||
abi.encode(_targets, _datas)
|
abi.encode(_targets, _datas)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -181,7 +188,11 @@ contract ConnectGelatoDataForFullRefinance is ConnectorInterface {
|
||||||
uint256 wColToWithdrawFromMaker = _getMakerVaultCollateralBalance(
|
uint256 wColToWithdrawFromMaker = _getMakerVaultCollateralBalance(
|
||||||
_vaultId
|
_vaultId
|
||||||
);
|
);
|
||||||
uint256 gasFeesPaidFromCol = _getGelatoProviderFees(GAS_COST);
|
uint256 route = _getFlashLoanRoute(DAI, wDaiDebtToMove);
|
||||||
|
uint256 gasCost = _getGasCost(route);
|
||||||
|
uint256 gasFeesPaidFromCol = _getGelatoProviderFees(gasCost);
|
||||||
|
|
||||||
|
uint256 wDaiToBorrow = _getBorrowAmountWithDelta(wDaiDebtToMove);
|
||||||
|
|
||||||
address[] memory _targets = new address[](6);
|
address[] memory _targets = new address[](6);
|
||||||
_targets[0] = CONNECT_MAKER; // payback
|
_targets[0] = CONNECT_MAKER; // payback
|
||||||
|
@ -192,7 +203,7 @@ contract ConnectGelatoDataForFullRefinance is ConnectorInterface {
|
||||||
_targets[5] = INSTA_POOL_V2; // flashPayback
|
_targets[5] = INSTA_POOL_V2; // flashPayback
|
||||||
|
|
||||||
bytes[] memory _datas = new bytes[](6);
|
bytes[] memory _datas = new bytes[](6);
|
||||||
_datas[0] = _encodePaybackMakerVault(_vaultId, uint256(-1), 0, 0);
|
_datas[0] = _encodePaybackMakerVault(_vaultId, uint256(-1), 0, 600);
|
||||||
_datas[1] = _encodedWithdrawMakerVault(_vaultId, uint256(-1), 0, 0);
|
_datas[1] = _encodedWithdrawMakerVault(_vaultId, uint256(-1), 0, 0);
|
||||||
_datas[2] = _encodeDepositCompound(
|
_datas[2] = _encodeDepositCompound(
|
||||||
_token,
|
_token,
|
||||||
|
@ -200,19 +211,81 @@ contract ConnectGelatoDataForFullRefinance is ConnectorInterface {
|
||||||
0,
|
0,
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
_datas[3] = _encodeBorrowCompound(DAI, wDaiDebtToMove, 0, 0);
|
_datas[3] = _encodeBorrowCompound(DAI, 0, 600, 0);
|
||||||
_datas[4] = _encodePayGelatoProvider(_token, gasFeesPaidFromCol, 0, 0);
|
_datas[4] = _encodePayGelatoProvider(_token, gasFeesPaidFromCol, 0, 0);
|
||||||
_datas[5] = _encodeFlashPayback(DAI, wDaiDebtToMove, 0, 0);
|
_datas[5] = _encodeFlashPayback(DAI, wDaiToBorrow, 0, 0);
|
||||||
|
|
||||||
datas = new bytes[](1);
|
datas = new bytes[](1);
|
||||||
datas[0] = abi.encodeWithSelector(
|
datas[0] = abi.encodeWithSelector(
|
||||||
IConnectInstaPoolV2.flashBorrowAndCast.selector,
|
IConnectInstaPoolV2.flashBorrowAndCast.selector,
|
||||||
DAI,
|
DAI,
|
||||||
wDaiDebtToMove,
|
wDaiToBorrow,
|
||||||
0,
|
route,
|
||||||
abi.encode(_targets, _datas)
|
abi.encode(_targets, _datas)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _spellsDebtBridgeWithOpenVaultAction(
|
||||||
|
uint256 _vaultAId,
|
||||||
|
address _token,
|
||||||
|
string calldata _colType,
|
||||||
|
uint256 _wDaiToBorrow,
|
||||||
|
uint256 _wColToWithdrawFromMaker,
|
||||||
|
uint256 _gasFeesPaidFromCol
|
||||||
|
) internal view returns (address[] memory targets, bytes[] memory datas) {
|
||||||
|
targets = new address[](7);
|
||||||
|
targets[0] = CONNECT_MAKER; // payback
|
||||||
|
targets[1] = CONNECT_MAKER; // withdraw
|
||||||
|
targets[2] = CONNECT_MAKER; // open ETH-B vault
|
||||||
|
targets[3] = CONNECT_MAKER; // deposit
|
||||||
|
targets[4] = CONNECT_MAKER; // borrow
|
||||||
|
targets[5] = _connectGelatoProviderPayment; // payProvider
|
||||||
|
targets[6] = INSTA_POOL_V2; // flashPayback
|
||||||
|
|
||||||
|
datas = new bytes[](7);
|
||||||
|
datas[0] = _encodePaybackMakerVault(_vaultAId, uint256(-1), 0, 600);
|
||||||
|
datas[1] = _encodedWithdrawMakerVault(_vaultAId, uint256(-1), 0, 0);
|
||||||
|
datas[2] = _encodeOpenMakerVault(_colType);
|
||||||
|
datas[3] = _encodedDepositMakerVault(
|
||||||
|
0,
|
||||||
|
sub(_wColToWithdrawFromMaker, _gasFeesPaidFromCol),
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
datas[4] = _encodeBorrowDaiMakerVault(0, 0, 600, 0);
|
||||||
|
datas[5] = _encodePayGelatoProvider(_token, _gasFeesPaidFromCol, 0, 0);
|
||||||
|
datas[6] = _encodeFlashPayback(DAI, _wDaiToBorrow, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _spellsDebtBridge(
|
||||||
|
uint256 _vaultAId,
|
||||||
|
uint256 _vaultBId,
|
||||||
|
address _token,
|
||||||
|
uint256 _wDaiToBorrow,
|
||||||
|
uint256 _wColToWithdrawFromMaker,
|
||||||
|
uint256 _gasFeesPaidFromCol
|
||||||
|
) internal view returns (address[] memory targets, bytes[] memory datas) {
|
||||||
|
targets = new address[](6);
|
||||||
|
targets[0] = CONNECT_MAKER; // payback
|
||||||
|
targets[1] = CONNECT_MAKER; // withdraw
|
||||||
|
targets[2] = CONNECT_MAKER; // deposit
|
||||||
|
targets[3] = CONNECT_MAKER; // borrow
|
||||||
|
targets[4] = _connectGelatoProviderPayment; // payProvider
|
||||||
|
targets[5] = INSTA_POOL_V2; // flashPayback
|
||||||
|
|
||||||
|
datas = new bytes[](6);
|
||||||
|
datas[0] = _encodePaybackMakerVault(_vaultAId, uint256(-1), 0, 600);
|
||||||
|
datas[1] = _encodedWithdrawMakerVault(_vaultAId, uint256(-1), 0, 0);
|
||||||
|
datas[2] = _encodedDepositMakerVault(
|
||||||
|
_vaultBId,
|
||||||
|
sub(_wColToWithdrawFromMaker, _gasFeesPaidFromCol),
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
datas[3] = _encodeBorrowDaiMakerVault(_vaultBId, 0, 600, 0);
|
||||||
|
datas[4] = _encodePayGelatoProvider(_token, _gasFeesPaidFromCol, 0, 0);
|
||||||
|
datas[5] = _encodeFlashPayback(DAI, _wDaiToBorrow, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/* solhint-enable function-max-lines */
|
/* solhint-enable function-max-lines */
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
// SPDX-License-Identifier: UNLICENSED
|
||||||
|
pragma solidity 0.7.4;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import {
|
||||||
|
GelatoConditionsStandard
|
||||||
|
} from "@gelatonetwork/core/contracts/conditions/GelatoConditionsStandard.sol";
|
||||||
|
import {
|
||||||
|
IGelatoCore
|
||||||
|
} from "@gelatonetwork/core/contracts/gelato_core/interfaces/IGelatoCore.sol";
|
||||||
|
import {GelatoBytes} from "../../../lib/GelatoBytes.sol";
|
||||||
|
import {
|
||||||
|
_getMakerVaultDebt,
|
||||||
|
_getMakerVaultCollateralBalance
|
||||||
|
} from "../../../functions/dapps/FMaker.sol";
|
||||||
|
import {
|
||||||
|
_getFlashLoanRoute,
|
||||||
|
_getGasCost
|
||||||
|
} from "../../../functions/gelato/FGelatoDebtBridge.sol";
|
||||||
|
import {_getGelatoProviderFees} from "../../../functions/gelato/FGelato.sol";
|
||||||
|
import {DAI} from "../../../constants/CInstaDapp.sol";
|
||||||
|
import {wdiv} from "../../../vendor/DSMath.sol";
|
||||||
|
|
||||||
|
/// @title ConditionDebtBridgeIsAffordable
|
||||||
|
/// @notice Condition checking if Debt Refinance is affordable.
|
||||||
|
/// @author Gelato Team
|
||||||
|
contract ConditionDebtBridgeIsAffordable 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.
|
||||||
|
/// @dev WARNING _ratioLimit should be in wad standard.
|
||||||
|
/// @return The encoded payload for your Task's Condition.data field.
|
||||||
|
function getConditionData(uint256 _vaultId, uint256 _ratioLimit)
|
||||||
|
public
|
||||||
|
pure
|
||||||
|
virtual
|
||||||
|
returns (bytes memory)
|
||||||
|
{
|
||||||
|
return abi.encode(_vaultId, _ratioLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @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, uint256 _ratioLimit) = abi.decode(
|
||||||
|
_conditionData,
|
||||||
|
(uint256, uint256)
|
||||||
|
);
|
||||||
|
|
||||||
|
return isAffordable(_vaultID, _ratioLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @notice Specific implementation of this Condition's ok function
|
||||||
|
/// @dev Check if the debt refinancing action is affordable.
|
||||||
|
/// @dev WARNING _ratioLimit should be in wad standard.
|
||||||
|
/// @param _vaultId The id of the Maker vault
|
||||||
|
/// @param _ratioLimit the maximum limit define by the user up on which
|
||||||
|
/// the debt is too expensive for him
|
||||||
|
/// @return OK if the Debt Bridge is affordable, otherwise some error message.
|
||||||
|
function isAffordable(uint256 _vaultId, uint256 _ratioLimit)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (string memory)
|
||||||
|
{
|
||||||
|
uint256 wColToWithdrawFromMaker = _getMakerVaultCollateralBalance(
|
||||||
|
_vaultId
|
||||||
|
);
|
||||||
|
uint256 gasFeesPaidFromCol = _getGelatoProviderFees(
|
||||||
|
_getGasCost(_getFlashLoanRoute(DAI, _getMakerVaultDebt(_vaultId)))
|
||||||
|
);
|
||||||
|
if (wdiv(gasFeesPaidFromCol, wColToWithdrawFromMaker) >= _ratioLimit)
|
||||||
|
return "DebtRefinanceTooExpensive";
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,13 @@
|
||||||
// SPDX-License-Identifier: UNLICENSED
|
// SPDX-License-Identifier: UNLICENSED
|
||||||
pragma solidity 0.7.4;
|
pragma solidity 0.7.4;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import {sub, wmul, wdiv} from "../../vendor/DSMath.sol";
|
import {sub, wmul, wdiv} from "../../vendor/DSMath.sol";
|
||||||
|
import {INSTA_POOL_RESOLVER} from "../../constants/CInstaDapp.sol";
|
||||||
|
import {GAS_COSTS_FOR_FULL_REFINANCE} from "../../constants/CDebtBridge.sol";
|
||||||
|
import {
|
||||||
|
IInstaPoolResolver
|
||||||
|
} from "../../interfaces/InstaDapp/resolvers/IInstaPoolResolver.sol";
|
||||||
|
|
||||||
function _wCalcCollateralToWithdraw(
|
function _wCalcCollateralToWithdraw(
|
||||||
uint256 _wMinColRatioA,
|
uint256 _wMinColRatioA,
|
||||||
|
@ -47,3 +53,29 @@ function _wCalcDebtToRepay(
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _getFlashLoanRoute(address _tokenA, uint256 _wTokenADebtToMove)
|
||||||
|
view
|
||||||
|
returns (uint256)
|
||||||
|
{
|
||||||
|
IInstaPoolResolver.RouteData memory rData = IInstaPoolResolver(
|
||||||
|
INSTA_POOL_RESOLVER
|
||||||
|
)
|
||||||
|
.getTokenLimit(_tokenA);
|
||||||
|
|
||||||
|
if (rData.dydx > _wTokenADebtToMove) return 0;
|
||||||
|
if (rData.maker > _wTokenADebtToMove) return 1;
|
||||||
|
if (rData.compound > _wTokenADebtToMove) return 2;
|
||||||
|
if (rData.aave > _wTokenADebtToMove) return 3;
|
||||||
|
revert(
|
||||||
|
"GelateDebtBridge._getRoute: All route have insufficient liquidties."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _getGasCost(uint256 _route) pure returns (uint256) {
|
||||||
|
return GAS_COSTS_FOR_FULL_REFINANCE()[_route];
|
||||||
|
}
|
||||||
|
|
||||||
|
function _getBorrowAmountWithDelta(uint256 _DebtToMove) pure returns (uint256) {
|
||||||
|
return wmul(_DebtToMove, 1005e15);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
// "SPDX-License-Identifier: UNLICENSED"
|
||||||
|
pragma solidity 0.7.4;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
interface IInstaPoolResolver {
|
||||||
|
struct RouteData {
|
||||||
|
uint256 dydx;
|
||||||
|
uint256 maker;
|
||||||
|
uint256 compound;
|
||||||
|
uint256 aave;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTokenLimit(address token)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (RouteData memory);
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
const {sleep} = require("@gelatonetwork/core");
|
||||||
|
|
||||||
|
module.exports = async (hre) => {
|
||||||
|
if (hre.network.name === "mainnet") {
|
||||||
|
console.log(
|
||||||
|
"Deploying ConditionDebtBridgeIsAffordable to mainnet. Hit ctrl + c to abort"
|
||||||
|
);
|
||||||
|
await sleep(10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
const {deployments} = hre;
|
||||||
|
const {deploy} = deployments;
|
||||||
|
const {deployer} = await hre.getNamedAccounts();
|
||||||
|
|
||||||
|
// the following will only deploy "ConditionMakerVaultUnsafe"
|
||||||
|
// if the contract was never deployed or if the code changed since last deployment
|
||||||
|
await deploy("ConditionDebtBridgeIsAffordable", {
|
||||||
|
from: deployer,
|
||||||
|
gasPrice: hre.network.config.gasPrice,
|
||||||
|
log: hre.network.name === "mainnet" ? true : false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.tags = ["ConditionDebtBridgeIsAffordable"];
|
|
@ -68,6 +68,7 @@ module.exports = {
|
||||||
ConnectInstaPool: "0xCeF5f3c402d4fef76A038e89a4357176963e1464",
|
ConnectInstaPool: "0xCeF5f3c402d4fef76A038e89a4357176963e1464",
|
||||||
MakerResolver: "0x0A7008B38E7015F8C36A49eEbc32513ECA8801E5",
|
MakerResolver: "0x0A7008B38E7015F8C36A49eEbc32513ECA8801E5",
|
||||||
CompoundResolver: "0x1f22D77365d8BFE3b901C33C83C01B584F946617",
|
CompoundResolver: "0x1f22D77365d8BFE3b901C33C83C01B584F946617",
|
||||||
|
InstaPoolResolver: "0xa004a5afBa04b74037E9E52bA1f7eb02b5E61509",
|
||||||
DAI: "0x6b175474e89094c44da98b954eedeac495271d0f",
|
DAI: "0x6b175474e89094c44da98b954eedeac495271d0f",
|
||||||
DAI_UNISWAP: "0x2a1530C4C41db0B0b2bB646CB5Eb1A67b7158667",
|
DAI_UNISWAP: "0x2a1530C4C41db0B0b2bB646CB5Eb1A67b7158667",
|
||||||
CDAI: "0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643",
|
CDAI: "0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643",
|
||||||
|
|
|
@ -5,6 +5,8 @@ const {deployments, ethers} = hre;
|
||||||
const GelatoCoreLib = require("@gelatonetwork/core");
|
const GelatoCoreLib = require("@gelatonetwork/core");
|
||||||
|
|
||||||
const setupFullRefinanceMakerToCompound = require("./helpers/setupFullRefinanceMakerToCompound");
|
const setupFullRefinanceMakerToCompound = require("./helpers/setupFullRefinanceMakerToCompound");
|
||||||
|
const getRoute = require("./helpers/services/getRoute");
|
||||||
|
const getGasCostForFullRefinance = require("./helpers/services/getGasCostForFullRefinance");
|
||||||
|
|
||||||
// This test showcases how to submit a task refinancing a Users debt position from
|
// This test showcases how to submit a task refinancing a Users debt position from
|
||||||
// Maker to Compound using Gelato
|
// Maker to Compound using Gelato
|
||||||
|
@ -90,9 +92,20 @@ describe("Full Debt Bridge refinancing loan from Maker to Compound", function ()
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const conditionDebtBridgeIsAffordableObj = new GelatoCoreLib.Condition({
|
||||||
|
inst: contracts.conditionDebtBridgeIsAffordable.address,
|
||||||
|
data: await contracts.conditionDebtBridgeIsAffordable.getConditionData(
|
||||||
|
vaultId,
|
||||||
|
constants.MAX_FEES_IN_PERCENT
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
// ======= GELATO TASK SETUP ======
|
// ======= GELATO TASK SETUP ======
|
||||||
const refinanceIfVaultUnsafe = new GelatoCoreLib.Task({
|
const refinanceIfVaultUnsafe = new GelatoCoreLib.Task({
|
||||||
conditions: [conditionMakerVaultUnsafeObj],
|
conditions: [
|
||||||
|
conditionMakerVaultUnsafeObj,
|
||||||
|
conditionDebtBridgeIsAffordableObj,
|
||||||
|
],
|
||||||
actions: gelatoDebtBridgeSpells,
|
actions: gelatoDebtBridgeSpells,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -186,7 +199,15 @@ describe("Full Debt Bridge refinancing loan from Maker to Compound", function ()
|
||||||
vaultId
|
vaultId
|
||||||
);
|
);
|
||||||
|
|
||||||
const gasFeesPaidFromCol = ethers.BigNumber.from(1850000).mul(
|
const route = await getRoute(
|
||||||
|
contracts.DAI.address,
|
||||||
|
debtOnMakerBefore,
|
||||||
|
contracts.instaPoolResolver
|
||||||
|
);
|
||||||
|
|
||||||
|
const gasCost = await getGasCostForFullRefinance(route);
|
||||||
|
|
||||||
|
const gasFeesPaidFromCol = ethers.BigNumber.from(gasCost).mul(
|
||||||
gelatoGasPrice
|
gelatoGasPrice
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -248,9 +269,21 @@ describe("Full Debt Bridge refinancing loan from Maker to Compound", function ()
|
||||||
.div(await contracts.cEthToken.totalSupply());
|
.div(await contracts.cEthToken.totalSupply());
|
||||||
|
|
||||||
// Estimated amount to borrowed token should be equal to the actual one read on compound contracts
|
// Estimated amount to borrowed token should be equal to the actual one read on compound contracts
|
||||||
expect(debtOnMakerBefore).to.be.equal(
|
if (route === 1) {
|
||||||
compoundPosition[0].borrowBalanceStoredUser
|
expect(debtOnMakerBefore).to.be.lte(
|
||||||
);
|
compoundPosition[0].borrowBalanceStoredUser
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
expect(debtOnMakerBefore).to.be.equal(
|
||||||
|
compoundPosition[0].borrowBalanceStoredUser
|
||||||
|
);
|
||||||
|
|
||||||
|
// We should not have borrowed DAI on maker
|
||||||
|
const debtOnMakerAfter = await contracts.makerResolver.getMakerVaultDebt(
|
||||||
|
vaultId
|
||||||
|
);
|
||||||
|
expect(debtOnMakerAfter).to.be.equal(ethers.constants.Zero);
|
||||||
|
}
|
||||||
|
|
||||||
// Estimated amount of collateral should be equal to the actual one read on compound contracts
|
// Estimated amount of collateral should be equal to the actual one read on compound contracts
|
||||||
expect(
|
expect(
|
||||||
|
@ -259,15 +292,11 @@ describe("Full Debt Bridge refinancing loan from Maker to Compound", function ()
|
||||||
)
|
)
|
||||||
).to.be.lt(ethers.utils.parseUnits("1", 12));
|
).to.be.lt(ethers.utils.parseUnits("1", 12));
|
||||||
|
|
||||||
const debtOnMakerAfter = await contracts.makerResolver.getMakerVaultDebt(
|
|
||||||
vaultId
|
|
||||||
);
|
|
||||||
const collateralOnMakerAfter = await contracts.makerResolver.getMakerVaultCollateralBalance(
|
const collateralOnMakerAfter = await contracts.makerResolver.getMakerVaultCollateralBalance(
|
||||||
vaultId
|
vaultId
|
||||||
); // in Ether.
|
); // in Ether.
|
||||||
|
|
||||||
// We should not have borrowed DAI on maker or deposited ether on it.
|
// We should not have deposited ether on it.
|
||||||
expect(debtOnMakerAfter).to.be.equal(ethers.constants.Zero);
|
|
||||||
expect(collateralOnMakerAfter).to.be.equal(ethers.constants.Zero);
|
expect(collateralOnMakerAfter).to.be.equal(ethers.constants.Zero);
|
||||||
|
|
||||||
// DSA contain 1000 DAI
|
// DSA contain 1000 DAI
|
||||||
|
|
|
@ -4,10 +4,12 @@ const {deployments, ethers} = hre;
|
||||||
const GelatoCoreLib = require("@gelatonetwork/core");
|
const GelatoCoreLib = require("@gelatonetwork/core");
|
||||||
|
|
||||||
const setupFullRefinanceMakerToMaker = require("./helpers/setupFullRefinanceMakerToMaker");
|
const setupFullRefinanceMakerToMaker = require("./helpers/setupFullRefinanceMakerToMaker");
|
||||||
|
const getRoute = require("./helpers/services/getRoute");
|
||||||
|
const getGasCostForFullRefinance = require("./helpers/services/getGasCostForFullRefinance");
|
||||||
|
|
||||||
// This test showcases how to submit a task refinancing a Users debt position from
|
// This test showcases how to submit a task refinancing a Users debt position from
|
||||||
// Maker to Compound using Gelato
|
// Maker to Compound using Gelato
|
||||||
describe("Full Debt Bridge refinancing loan from ETH-A to ETH-B", function () {
|
describe("Full Debt Bridge refinancing loan from ETH-A to ETH-B with vault creation for ETH-B ", function () {
|
||||||
this.timeout(0);
|
this.timeout(0);
|
||||||
if (hre.network.name !== "hardhat") {
|
if (hre.network.name !== "hardhat") {
|
||||||
console.error("Test Suite is meant to be run on hardhat only");
|
console.error("Test Suite is meant to be run on hardhat only");
|
||||||
|
@ -92,9 +94,20 @@ describe("Full Debt Bridge refinancing loan from ETH-A to ETH-B", function () {
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const conditionDebtBridgeIsAffordableObj = new GelatoCoreLib.Condition({
|
||||||
|
inst: contracts.conditionDebtBridgeIsAffordable.address,
|
||||||
|
data: await contracts.conditionDebtBridgeIsAffordable.getConditionData(
|
||||||
|
vaultAId,
|
||||||
|
constants.MAX_FEES_IN_PERCENT
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
// ======= GELATO TASK SETUP ======
|
// ======= GELATO TASK SETUP ======
|
||||||
const refinanceFromEthAToBIfVaultUnsafe = new GelatoCoreLib.Task({
|
const refinanceFromEthAToBIfVaultUnsafe = new GelatoCoreLib.Task({
|
||||||
conditions: [conditionMakerVaultUnsafeObj],
|
conditions: [
|
||||||
|
conditionMakerVaultUnsafeObj,
|
||||||
|
conditionDebtBridgeIsAffordableObj,
|
||||||
|
],
|
||||||
actions: gelatoDebtBridgeSpells,
|
actions: gelatoDebtBridgeSpells,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -188,7 +201,15 @@ describe("Full Debt Bridge refinancing loan from ETH-A to ETH-B", function () {
|
||||||
vaultAId
|
vaultAId
|
||||||
);
|
);
|
||||||
|
|
||||||
const gasFeesPaidFromCol = ethers.BigNumber.from(1850000).mul(
|
const route = await getRoute(
|
||||||
|
contracts.DAI.address,
|
||||||
|
debtOnMakerBefore,
|
||||||
|
contracts.instaPoolResolver
|
||||||
|
);
|
||||||
|
|
||||||
|
const gasCost = await getGasCostForFullRefinance(route);
|
||||||
|
|
||||||
|
const gasFeesPaidFromCol = ethers.BigNumber.from(gasCost).mul(
|
||||||
gelatoGasPrice
|
gelatoGasPrice
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -250,20 +271,26 @@ describe("Full Debt Bridge refinancing loan from ETH-A to ETH-B", function () {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Estimated amount to borrowed token should be equal to the actual one read on compound contracts
|
// Estimated amount to borrowed token should be equal to the actual one read on compound contracts
|
||||||
expect(debtOnMakerBefore).to.be.equal(debtOnMakerVaultB);
|
if (route === 1) {
|
||||||
|
expect(debtOnMakerBefore).to.be.lte(debtOnMakerVaultB);
|
||||||
|
} else {
|
||||||
|
expect(debtOnMakerBefore).to.be.equal(debtOnMakerVaultB);
|
||||||
|
|
||||||
|
// We should not have borrowed DAI on maker
|
||||||
|
const debtOnMakerOnVaultAAfter = await contracts.makerResolver.getMakerVaultDebt(
|
||||||
|
vaultAId
|
||||||
|
);
|
||||||
|
expect(debtOnMakerOnVaultAAfter).to.be.equal(ethers.constants.Zero);
|
||||||
|
}
|
||||||
|
|
||||||
// Estimated amount of collateral should be equal to the actual one read on compound contracts
|
// Estimated amount of collateral should be equal to the actual one read on compound contracts
|
||||||
expect(pricedCollateral).to.be.equal(pricedCollateralOnVaultB);
|
expect(pricedCollateral).to.be.equal(pricedCollateralOnVaultB);
|
||||||
|
|
||||||
const debtOnMakerOnVaultAAfter = await contracts.makerResolver.getMakerVaultDebt(
|
|
||||||
vaultAId
|
|
||||||
);
|
|
||||||
const collateralOnMakerOnVaultAAfter = await contracts.makerResolver.getMakerVaultCollateralBalance(
|
const collateralOnMakerOnVaultAAfter = await contracts.makerResolver.getMakerVaultCollateralBalance(
|
||||||
vaultAId
|
vaultAId
|
||||||
); // in Ether.
|
); // in Ether.
|
||||||
|
|
||||||
// We should not have borrowed DAI on maker or deposited ether on it.
|
// We should not have deposited ether on it.
|
||||||
expect(debtOnMakerOnVaultAAfter).to.be.equal(ethers.constants.Zero);
|
|
||||||
expect(collateralOnMakerOnVaultAAfter).to.be.equal(ethers.constants.Zero);
|
expect(collateralOnMakerOnVaultAAfter).to.be.equal(ethers.constants.Zero);
|
||||||
|
|
||||||
// DSA has maximum 2 wei DAI in it due to maths inaccuracies
|
// DSA has maximum 2 wei DAI in it due to maths inaccuracies
|
303
test/4_Full-Debt-Bridge-ETHA-ETHB.test.js
Normal file
303
test/4_Full-Debt-Bridge-ETHA-ETHB.test.js
Normal file
|
@ -0,0 +1,303 @@
|
||||||
|
const {expect} = require("chai");
|
||||||
|
const hre = require("hardhat");
|
||||||
|
const {deployments, ethers} = hre;
|
||||||
|
const GelatoCoreLib = require("@gelatonetwork/core");
|
||||||
|
|
||||||
|
const setupFullRefinanceMakerToMakerWithVaultBCreation = require("./helpers/setupFullRefinanceMakerToMakerWithVaultBCreation");
|
||||||
|
const getRoute = require("./helpers/services/getRoute");
|
||||||
|
const getGasCostForFullRefinance = require("./helpers/services/getGasCostForFullRefinance");
|
||||||
|
|
||||||
|
// This test showcases how to submit a task refinancing a Users debt position from
|
||||||
|
// Maker to Compound using Gelato
|
||||||
|
describe("Full Debt Bridge refinancing loan from ETH-A to ETH-B", 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 contracts;
|
||||||
|
let wallets;
|
||||||
|
let constants;
|
||||||
|
let ABI;
|
||||||
|
|
||||||
|
// Payload Params for ConnectGelatoFullDebtBridgeFromMaker and ConditionMakerVaultUnsafe
|
||||||
|
let vaultAId;
|
||||||
|
|
||||||
|
// For TaskSpec and for Task
|
||||||
|
let gelatoDebtBridgeSpells = [];
|
||||||
|
|
||||||
|
// Cross test var
|
||||||
|
let taskReceipt;
|
||||||
|
|
||||||
|
before(async function () {
|
||||||
|
// Reset back to a fresh forked state during runtime
|
||||||
|
await deployments.fixture();
|
||||||
|
|
||||||
|
const result = await setupFullRefinanceMakerToMakerWithVaultBCreation();
|
||||||
|
|
||||||
|
wallets = result.wallets;
|
||||||
|
contracts = result.contracts;
|
||||||
|
vaultAId = result.vaultAId;
|
||||||
|
gelatoDebtBridgeSpells = result.spells;
|
||||||
|
|
||||||
|
ABI = result.ABI;
|
||||||
|
constants = result.constants;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#1: DSA authorizes Gelato to cast spells.", async function () {
|
||||||
|
//#region 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.
|
||||||
|
// In this case user give authorization to gelato to execute
|
||||||
|
// task for him if needed.
|
||||||
|
|
||||||
|
await contracts.dsa.cast(
|
||||||
|
[hre.network.config.ConnectAuth],
|
||||||
|
[
|
||||||
|
await hre.run("abi-encode-withselector", {
|
||||||
|
abi: ABI.ConnectAuthABI,
|
||||||
|
functionname: "add",
|
||||||
|
inputs: [contracts.gelatoCore.address],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
wallets.userAddress
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(await contracts.dsa.isAuth(contracts.gelatoCore.address)).to.be.true;
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#2: User submits automated Debt Bridge task to Gelato via DSA", async function () {
|
||||||
|
//#region 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: contracts.conditionMakerVaultUnsafe.address,
|
||||||
|
data: await contracts.conditionMakerVaultUnsafe.getConditionData(
|
||||||
|
vaultAId,
|
||||||
|
contracts.priceOracleResolver.address,
|
||||||
|
await hre.run("abi-encode-withselector", {
|
||||||
|
abi: (await deployments.getArtifact("PriceOracleResolver")).abi,
|
||||||
|
functionname: "getMockPrice",
|
||||||
|
inputs: [wallets.userAddress],
|
||||||
|
}),
|
||||||
|
constants.MIN_COL_RATIO_MAKER
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
const conditionDebtBridgeIsAffordableObj = new GelatoCoreLib.Condition({
|
||||||
|
inst: contracts.conditionDebtBridgeIsAffordable.address,
|
||||||
|
data: await contracts.conditionDebtBridgeIsAffordable.getConditionData(
|
||||||
|
vaultAId,
|
||||||
|
constants.MAX_FEES_IN_PERCENT
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
// ======= GELATO TASK SETUP ======
|
||||||
|
const refinanceFromEthAToBIfVaultUnsafe = new GelatoCoreLib.Task({
|
||||||
|
conditions: [
|
||||||
|
conditionMakerVaultUnsafeObj,
|
||||||
|
conditionDebtBridgeIsAffordableObj,
|
||||||
|
],
|
||||||
|
actions: gelatoDebtBridgeSpells,
|
||||||
|
});
|
||||||
|
|
||||||
|
const gelatoExternalProvider = new GelatoCoreLib.GelatoProvider({
|
||||||
|
addr: wallets.gelatoProviderAddress, // Gelato Provider Address
|
||||||
|
module: contracts.dsaProviderModule.address, // Gelato DSA module
|
||||||
|
});
|
||||||
|
|
||||||
|
const expiryDate = 0;
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
contracts.dsa.cast(
|
||||||
|
[contracts.connectGelato.address], // targets
|
||||||
|
[
|
||||||
|
await hre.run("abi-encode-withselector", {
|
||||||
|
abi: ABI.ConnectGelatoABI,
|
||||||
|
functionname: "submitTask",
|
||||||
|
inputs: [
|
||||||
|
gelatoExternalProvider,
|
||||||
|
refinanceFromEthAToBIfVaultUnsafe,
|
||||||
|
expiryDate,
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
], // datas
|
||||||
|
wallets.userAddress, // origin
|
||||||
|
{
|
||||||
|
gasLimit: 5000000,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
).to.emit(contracts.gelatoCore, "LogTaskSubmitted");
|
||||||
|
|
||||||
|
taskReceipt = new GelatoCoreLib.TaskReceipt({
|
||||||
|
id: await contracts.gelatoCore.currentTaskReceiptId(),
|
||||||
|
userProxy: contracts.dsa.address,
|
||||||
|
provider: gelatoExternalProvider,
|
||||||
|
tasks: [refinanceFromEthAToBIfVaultUnsafe],
|
||||||
|
expiryDate,
|
||||||
|
});
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
});
|
||||||
|
|
||||||
|
// This test showcases the part which is automatically done by the Gelato Executor Network on mainnet
|
||||||
|
// Bots constatly check whether the submitted task is executable (by calling canExec)
|
||||||
|
// If the task becomes executable (returns "OK"), the "exec" function will be called
|
||||||
|
// which will execute the debt refinancing on behalf of the user
|
||||||
|
it("#3: Auto-refinance from ETH-A to ETH-B, if the Maker vault became unsafe.", async function () {
|
||||||
|
// Steps
|
||||||
|
// Step 1: Market Move against the user (Mock)
|
||||||
|
// Step 2: Executor execute the user's task
|
||||||
|
|
||||||
|
//#region Step 1 Market Move against the user (Mock)
|
||||||
|
|
||||||
|
// Ether market price went from the current price to 250$
|
||||||
|
|
||||||
|
const gelatoGasPrice = await hre.run("fetchGelatoGasPrice");
|
||||||
|
expect(gelatoGasPrice).to.be.lte(constants.GAS_PRICE_CEIL);
|
||||||
|
|
||||||
|
// TO DO: base mock price off of real price data
|
||||||
|
await contracts.priceOracleResolver.setMockPrice(
|
||||||
|
ethers.utils.parseUnits("400", 18)
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await contracts.gelatoCore
|
||||||
|
.connect(wallets.gelatoExecutorWallet)
|
||||||
|
.canExec(taskReceipt, constants.GAS_LIMIT, gelatoGasPrice)
|
||||||
|
).to.be.equal("ConditionNotOk:MakerVaultNotUnsafe");
|
||||||
|
|
||||||
|
// TO DO: base mock price off of real price data
|
||||||
|
await contracts.priceOracleResolver.setMockPrice(
|
||||||
|
ethers.utils.parseUnits("250", 18)
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await contracts.gelatoCore
|
||||||
|
.connect(wallets.gelatoExecutorWallet)
|
||||||
|
.canExec(taskReceipt, constants.GAS_LIMIT, gelatoGasPrice)
|
||||||
|
).to.be.equal("OK");
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region Step 2 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
|
||||||
|
// by a debt refinancing in compound.
|
||||||
|
|
||||||
|
//#region EXPECTED OUTCOME
|
||||||
|
const debtOnMakerBefore = await contracts.makerResolver.getMakerVaultDebt(
|
||||||
|
vaultAId
|
||||||
|
);
|
||||||
|
|
||||||
|
const route = await getRoute(
|
||||||
|
contracts.DAI.address,
|
||||||
|
debtOnMakerBefore,
|
||||||
|
contracts.instaPoolResolver
|
||||||
|
);
|
||||||
|
|
||||||
|
const gasCost = await getGasCostForFullRefinance(route);
|
||||||
|
|
||||||
|
const gasFeesPaidFromCol = ethers.BigNumber.from(gasCost).mul(
|
||||||
|
gelatoGasPrice
|
||||||
|
);
|
||||||
|
|
||||||
|
const pricedCollateral = (
|
||||||
|
await contracts.makerResolver.getMakerVaultCollateralBalance(vaultAId)
|
||||||
|
).sub(gasFeesPaidFromCol);
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
const providerBalanceBeforeExecution = await contracts.gelatoCore.providerFunds(
|
||||||
|
wallets.gelatoProviderAddress
|
||||||
|
);
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
contracts.gelatoCore
|
||||||
|
.connect(wallets.gelatoExecutorWallet)
|
||||||
|
.exec(taskReceipt, {
|
||||||
|
gasPrice: gelatoGasPrice, // Exectutor must use gelatoGasPrice (Chainlink fast gwei)
|
||||||
|
gasLimit: constants.GAS_LIMIT,
|
||||||
|
})
|
||||||
|
).to.emit(contracts.gelatoCore, "LogExecSuccess");
|
||||||
|
|
||||||
|
// 🚧 For Debugging:
|
||||||
|
// const txResponse2 = await contracts.gelatoCore
|
||||||
|
// .connect(wallets.gelatoExecutorWallet)
|
||||||
|
// .exec(taskReceipt, {
|
||||||
|
// gasPrice: gelatoGasPrice,
|
||||||
|
// gasLimit: constants.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);
|
||||||
|
|
||||||
|
const cdps = await contracts.getCdps.getCdpsAsc(
|
||||||
|
contracts.dssCdpManager.address,
|
||||||
|
contracts.dsa.address
|
||||||
|
);
|
||||||
|
let vaultBId = String(cdps.ids[1]);
|
||||||
|
expect(cdps.ids[1].isZero()).to.be.false;
|
||||||
|
|
||||||
|
const debtOnMakerVaultB = await contracts.makerResolver.getMakerVaultDebt(
|
||||||
|
vaultBId
|
||||||
|
);
|
||||||
|
const pricedCollateralOnVaultB = await contracts.makerResolver.getMakerVaultCollateralBalance(
|
||||||
|
vaultBId
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await contracts.gelatoCore.providerFunds(wallets.gelatoProviderAddress)
|
||||||
|
).to.be.gt(
|
||||||
|
providerBalanceBeforeExecution.sub(
|
||||||
|
gasFeesPaidFromCol
|
||||||
|
.mul(await contracts.gelatoCore.totalSuccessShare())
|
||||||
|
.div(100)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Estimated amount to borrowed token should be equal to the actual one read on compound contracts
|
||||||
|
if (route === 1) {
|
||||||
|
expect(debtOnMakerBefore).to.be.lte(debtOnMakerVaultB);
|
||||||
|
} else {
|
||||||
|
expect(debtOnMakerBefore).to.be.equal(debtOnMakerVaultB);
|
||||||
|
|
||||||
|
// We should not have borrowed DAI on maker
|
||||||
|
const debtOnMakerOnVaultAAfter = await contracts.makerResolver.getMakerVaultDebt(
|
||||||
|
vaultAId
|
||||||
|
);
|
||||||
|
expect(debtOnMakerOnVaultAAfter).to.be.equal(ethers.constants.Zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Estimated amount of collateral should be equal to the actual one read on compound contracts
|
||||||
|
expect(pricedCollateral).to.be.equal(pricedCollateralOnVaultB);
|
||||||
|
|
||||||
|
const collateralOnMakerOnVaultAAfter = await contracts.makerResolver.getMakerVaultCollateralBalance(
|
||||||
|
vaultAId
|
||||||
|
); // in Ether.
|
||||||
|
|
||||||
|
// We should not have deposited ether on it.
|
||||||
|
expect(collateralOnMakerOnVaultAAfter).to.be.equal(ethers.constants.Zero);
|
||||||
|
|
||||||
|
// DSA has maximum 2 wei DAI in it due to maths inaccuracies
|
||||||
|
expect(await contracts.DAI.balanceOf(contracts.dsa.address)).to.be.equal(
|
||||||
|
constants.MAKER_INITIAL_DEBT
|
||||||
|
);
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
});
|
||||||
|
});
|
35
test/helpers/services/createVaultForETHB.js
Normal file
35
test/helpers/services/createVaultForETHB.js
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
const {expect} = require("chai");
|
||||||
|
const hre = require("hardhat");
|
||||||
|
|
||||||
|
const ConnectMaker = require("../../../pre-compiles/ConnectMaker.json");
|
||||||
|
|
||||||
|
async function createVaultForETHB(
|
||||||
|
userAddress,
|
||||||
|
DAI,
|
||||||
|
dsa,
|
||||||
|
getCdps,
|
||||||
|
dssCdpManager
|
||||||
|
) {
|
||||||
|
//#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 hre.run("abi-encode-withselector", {
|
||||||
|
abi: ConnectMaker.abi,
|
||||||
|
functionname: "open",
|
||||||
|
inputs: ["ETH-B"],
|
||||||
|
});
|
||||||
|
|
||||||
|
await dsa.cast([hre.network.config.ConnectMaker], [openVault], userAddress);
|
||||||
|
|
||||||
|
const cdps = await getCdps.getCdpsAsc(dssCdpManager.address, dsa.address);
|
||||||
|
let vaultId = String(cdps.ids[1]);
|
||||||
|
expect(cdps.ids[1].isZero()).to.be.false;
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
return vaultId;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = createVaultForETHB;
|
|
@ -2,7 +2,7 @@ const hre = require("hardhat");
|
||||||
const {ethers} = hre;
|
const {ethers} = hre;
|
||||||
|
|
||||||
const ETH = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
|
const ETH = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
|
||||||
const GAS_LIMIT = "4000000";
|
const GAS_LIMIT = "5000000";
|
||||||
const GAS_PRICE_CEIL = ethers.utils.parseUnits("1000", "gwei");
|
const GAS_PRICE_CEIL = ethers.utils.parseUnits("1000", "gwei");
|
||||||
|
|
||||||
const MIN_COL_RATIO_MAKER = ethers.utils.parseUnits("3", 18);
|
const MIN_COL_RATIO_MAKER = ethers.utils.parseUnits("3", 18);
|
||||||
|
@ -11,6 +11,8 @@ const MIN_COL_RATIO_MAKER = ethers.utils.parseUnits("3", 18);
|
||||||
const MAKER_INITIAL_ETH = ethers.utils.parseEther("10");
|
const MAKER_INITIAL_ETH = ethers.utils.parseEther("10");
|
||||||
const MAKER_INITIAL_DEBT = ethers.utils.parseUnits("1000", 18);
|
const MAKER_INITIAL_DEBT = ethers.utils.parseUnits("1000", 18);
|
||||||
|
|
||||||
|
const MAX_FEES_IN_PERCENT = ethers.utils.parseUnits("1", 17);
|
||||||
|
|
||||||
async function getConstants() {
|
async function getConstants() {
|
||||||
return {
|
return {
|
||||||
ETH: ETH,
|
ETH: ETH,
|
||||||
|
@ -19,6 +21,7 @@ async function getConstants() {
|
||||||
GAS_LIMIT: GAS_LIMIT,
|
GAS_LIMIT: GAS_LIMIT,
|
||||||
MAKER_INITIAL_DEBT: MAKER_INITIAL_DEBT,
|
MAKER_INITIAL_DEBT: MAKER_INITIAL_DEBT,
|
||||||
MAKER_INITIAL_ETH: MAKER_INITIAL_ETH,
|
MAKER_INITIAL_ETH: MAKER_INITIAL_ETH,
|
||||||
|
MAX_FEES_IN_PERCENT: MAX_FEES_IN_PERCENT,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ const IERC20 = require("../../../pre-compiles/IERC20.json");
|
||||||
const CTokenInterface = require("../../../pre-compiles/CTokenInterface.json");
|
const CTokenInterface = require("../../../pre-compiles/CTokenInterface.json");
|
||||||
const CompoundResolver = require("../../../pre-compiles/InstaCompoundResolver.json");
|
const CompoundResolver = require("../../../pre-compiles/InstaCompoundResolver.json");
|
||||||
const DsaProviderModuleABI = require("../../../pre-compiles/ProviderModuleDsa_ABI.json");
|
const DsaProviderModuleABI = require("../../../pre-compiles/ProviderModuleDsa_ABI.json");
|
||||||
|
const InstaPoolResolver = require("../../../artifacts/contracts/interfaces/InstaDapp/resolvers/IInstaPoolResolver.sol/IInstaPoolResolver.json");
|
||||||
|
|
||||||
async function getContracts() {
|
async function getContracts() {
|
||||||
const instaMaster = await ethers.provider.getSigner(
|
const instaMaster = await ethers.provider.getSigner(
|
||||||
|
@ -85,12 +86,19 @@ async function getContracts() {
|
||||||
DsaProviderModuleABI,
|
DsaProviderModuleABI,
|
||||||
hre.network.config.ProviderModuleDsa
|
hre.network.config.ProviderModuleDsa
|
||||||
);
|
);
|
||||||
|
const instaPoolResolver = await ethers.getContractAt(
|
||||||
|
InstaPoolResolver.abi,
|
||||||
|
hre.network.config.InstaPoolResolver
|
||||||
|
);
|
||||||
|
|
||||||
// ===== Get deployed contracts ==================
|
// ===== Get deployed contracts ==================
|
||||||
const priceOracleResolver = await ethers.getContract("PriceOracleResolver");
|
const priceOracleResolver = await ethers.getContract("PriceOracleResolver");
|
||||||
const conditionMakerVaultUnsafe = await ethers.getContract(
|
const conditionMakerVaultUnsafe = await ethers.getContract(
|
||||||
"ConditionMakerVaultUnsafe"
|
"ConditionMakerVaultUnsafe"
|
||||||
);
|
);
|
||||||
|
const conditionDebtBridgeIsAffordable = await ethers.getContract(
|
||||||
|
"ConditionDebtBridgeIsAffordable"
|
||||||
|
);
|
||||||
const connectGelatoProviderPayment = await ethers.getContract(
|
const connectGelatoProviderPayment = await ethers.getContract(
|
||||||
"ConnectGelatoProviderPayment"
|
"ConnectGelatoProviderPayment"
|
||||||
);
|
);
|
||||||
|
@ -122,7 +130,9 @@ async function getContracts() {
|
||||||
priceOracleResolver,
|
priceOracleResolver,
|
||||||
dsa: ethers.constants.AddressZero,
|
dsa: ethers.constants.AddressZero,
|
||||||
makerResolver,
|
makerResolver,
|
||||||
|
instaPoolResolver,
|
||||||
dsaProviderModule,
|
dsaProviderModule,
|
||||||
|
conditionDebtBridgeIsAffordable,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
16
test/helpers/services/getGasCostForFullRefinance.js
Normal file
16
test/helpers/services/getGasCostForFullRefinance.js
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
async function getGasCostForFullRefinance(route) {
|
||||||
|
switch (route) {
|
||||||
|
case 0:
|
||||||
|
return 2519000; // 2290000 * 1,1
|
||||||
|
case 1:
|
||||||
|
return 3140500; // 2855000 * 1,1
|
||||||
|
case 2:
|
||||||
|
return 3971000; // 3610000 * 1,1
|
||||||
|
case 3:
|
||||||
|
return 4345000; // 3950000 * 1,1
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = getGasCostForFullRefinance;
|
10
test/helpers/services/getRoute.js
Normal file
10
test/helpers/services/getRoute.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
async function getRoute(token, tokenDebtToMove, instaPoolResolver) {
|
||||||
|
const rData = await instaPoolResolver.getTokenLimit(token);
|
||||||
|
|
||||||
|
if (rData.dydx > tokenDebtToMove) return 0;
|
||||||
|
if (rData.maker > tokenDebtToMove) return 1;
|
||||||
|
if (rData.compound > tokenDebtToMove) return 2;
|
||||||
|
if (rData.aave > tokenDebtToMove) return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = getRoute;
|
|
@ -25,7 +25,7 @@ async function providerWhiteListTaskForMakerETHAToMakerETHB(
|
||||||
abi: (await deployments.getArtifact("ConnectGelatoDataForFullRefinance"))
|
abi: (await deployments.getArtifact("ConnectGelatoDataForFullRefinance"))
|
||||||
.abi,
|
.abi,
|
||||||
functionname: "getDataAndCastForFromMakerToMaker",
|
functionname: "getDataAndCastForFromMakerToMaker",
|
||||||
inputs: [vaultId, constants.ETH, "ETH-B"],
|
inputs: [vaultId, 0, constants.ETH, "ETH-B"],
|
||||||
}),
|
}),
|
||||||
operation: GelatoCoreLib.Operation.Delegatecall,
|
operation: GelatoCoreLib.Operation.Delegatecall,
|
||||||
});
|
});
|
||||||
|
@ -36,7 +36,10 @@ async function providerWhiteListTaskForMakerETHAToMakerETHB(
|
||||||
|
|
||||||
const connectGelatoFullDebtBridgeFromMakerTaskSpec = new GelatoCoreLib.TaskSpec(
|
const connectGelatoFullDebtBridgeFromMakerTaskSpec = new GelatoCoreLib.TaskSpec(
|
||||||
{
|
{
|
||||||
conditions: [contracts.conditionMakerVaultUnsafe.address],
|
conditions: [
|
||||||
|
contracts.conditionMakerVaultUnsafe.address,
|
||||||
|
contracts.conditionDebtBridgeIsAffordable.address,
|
||||||
|
],
|
||||||
actions: spells,
|
actions: spells,
|
||||||
gasPriceCeil,
|
gasPriceCeil,
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
const {expect} = require("chai");
|
||||||
|
const hre = require("hardhat");
|
||||||
|
const {deployments, ethers} = hre;
|
||||||
|
const GelatoCoreLib = require("@gelatonetwork/core");
|
||||||
|
|
||||||
|
// Instadapp UI should do the same implementation for submitting debt bridge task
|
||||||
|
async function providerWhiteListTaskForMakerETHAToMakerETHBWithVaultB(
|
||||||
|
wallets,
|
||||||
|
contracts,
|
||||||
|
constants,
|
||||||
|
vaultAId,
|
||||||
|
vaultBId
|
||||||
|
) {
|
||||||
|
//#region Step 9 Provider should whitelist task
|
||||||
|
|
||||||
|
// By WhiteList task, the provider can constrain the type
|
||||||
|
// of task the user can submitting.
|
||||||
|
|
||||||
|
//#region Actions
|
||||||
|
|
||||||
|
const spells = [];
|
||||||
|
|
||||||
|
const debtBridgeCalculationForFullRefinance = new GelatoCoreLib.Action({
|
||||||
|
addr: contracts.connectGelatoDataForFullRefinance.address,
|
||||||
|
data: await hre.run("abi-encode-withselector", {
|
||||||
|
abi: (await deployments.getArtifact("ConnectGelatoDataForFullRefinance"))
|
||||||
|
.abi,
|
||||||
|
functionname: "getDataAndCastForFromMakerToMaker",
|
||||||
|
inputs: [vaultAId, vaultBId, constants.ETH, "ETH-B"],
|
||||||
|
}),
|
||||||
|
operation: GelatoCoreLib.Operation.Delegatecall,
|
||||||
|
});
|
||||||
|
|
||||||
|
spells.push(debtBridgeCalculationForFullRefinance);
|
||||||
|
|
||||||
|
const gasPriceCeil = ethers.constants.MaxUint256;
|
||||||
|
|
||||||
|
const connectGelatoFullDebtBridgeFromMakerTaskSpec = new GelatoCoreLib.TaskSpec(
|
||||||
|
{
|
||||||
|
conditions: [
|
||||||
|
contracts.conditionMakerVaultUnsafe.address,
|
||||||
|
contracts.conditionDebtBridgeIsAffordable.address,
|
||||||
|
],
|
||||||
|
actions: spells,
|
||||||
|
gasPriceCeil,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
contracts.gelatoCore
|
||||||
|
.connect(wallets.gelatoProviderWallet)
|
||||||
|
.provideTaskSpecs([connectGelatoFullDebtBridgeFromMakerTaskSpec])
|
||||||
|
).to.emit(contracts.gelatoCore, "LogTaskSpecProvided");
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await contracts.gelatoCore
|
||||||
|
.connect(wallets.gelatoProviderWallet)
|
||||||
|
.isTaskSpecProvided(
|
||||||
|
wallets.gelatoProviderAddress,
|
||||||
|
connectGelatoFullDebtBridgeFromMakerTaskSpec
|
||||||
|
)
|
||||||
|
).to.be.equal("OK");
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await contracts.gelatoCore
|
||||||
|
.connect(wallets.gelatoProviderWallet)
|
||||||
|
.taskSpecGasPriceCeil(
|
||||||
|
wallets.gelatoProviderAddress,
|
||||||
|
await contracts.gelatoCore
|
||||||
|
.connect(wallets.gelatoProviderWallet)
|
||||||
|
.hashTaskSpec(connectGelatoFullDebtBridgeFromMakerTaskSpec)
|
||||||
|
)
|
||||||
|
).to.be.equal(gasPriceCeil);
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
return spells;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = providerWhiteListTaskForMakerETHAToMakerETHBWithVaultB;
|
|
@ -36,7 +36,10 @@ async function providerWhiteListTaskForMakerToCompound(
|
||||||
|
|
||||||
const connectGelatoFullDebtBridgeFromMakerTaskSpec = new GelatoCoreLib.TaskSpec(
|
const connectGelatoFullDebtBridgeFromMakerTaskSpec = new GelatoCoreLib.TaskSpec(
|
||||||
{
|
{
|
||||||
conditions: [contracts.conditionMakerVaultUnsafe.address],
|
conditions: [
|
||||||
|
contracts.conditionMakerVaultUnsafe.address,
|
||||||
|
contracts.conditionDebtBridgeIsAffordable.address,
|
||||||
|
],
|
||||||
actions: spells,
|
actions: spells,
|
||||||
gasPriceCeil,
|
gasPriceCeil,
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
const getWallets = require("./services/getWallets");
|
||||||
|
const getContracts = require("./services/getContracts");
|
||||||
|
const getConstants = require("./services/getConstants");
|
||||||
|
const stakeExecutor = require("./services/stakeExecutor");
|
||||||
|
const provideFunds = require("./services/provideFunds");
|
||||||
|
const providerAssignsExecutor = require("./services/providerAssignsExecutor");
|
||||||
|
const addProviderModuleDSA = require("./services/addProviderModuleDSA");
|
||||||
|
const createDSA = require("./services/createDSA");
|
||||||
|
const addETHBGemJoinMapping = require("./services/addETHBGemJoinMapping");
|
||||||
|
const initializeMakerCdp = require("./services/initializeMakerCdp");
|
||||||
|
const createVaultForETHB = require("./services/createVaultForETHB");
|
||||||
|
const providerWhiteListTaskForMakerETHAToMakerETHBWithVaultB = require("./services/providerWhiteListTaskForMakerETHAToMakerETHBWithVaultB");
|
||||||
|
const getABI = require("./services/getABI");
|
||||||
|
|
||||||
|
async function setupFullRefinanceMakerToMakerWithVaultBCreation() {
|
||||||
|
const wallets = await getWallets();
|
||||||
|
const contracts = await getContracts();
|
||||||
|
const constants = await getConstants();
|
||||||
|
|
||||||
|
// Gelato Testing environment setup.
|
||||||
|
await stakeExecutor(wallets.gelatoExecutorWallet, contracts.gelatoCore);
|
||||||
|
await provideFunds(
|
||||||
|
wallets.gelatoProviderWallet,
|
||||||
|
contracts.gelatoCore,
|
||||||
|
constants.GAS_LIMIT,
|
||||||
|
constants.GAS_PRICE_CEIL
|
||||||
|
);
|
||||||
|
await providerAssignsExecutor(
|
||||||
|
wallets.gelatoProviderWallet,
|
||||||
|
wallets.gelatoExecutorAddress,
|
||||||
|
contracts.gelatoCore
|
||||||
|
);
|
||||||
|
await addProviderModuleDSA(
|
||||||
|
wallets.gelatoProviderWallet,
|
||||||
|
contracts.gelatoCore,
|
||||||
|
contracts.dsaProviderModule.address
|
||||||
|
);
|
||||||
|
contracts.dsa = await createDSA(
|
||||||
|
wallets.userAddress,
|
||||||
|
contracts.instaIndex,
|
||||||
|
contracts.instaList
|
||||||
|
);
|
||||||
|
await addETHBGemJoinMapping(
|
||||||
|
wallets.userWallet,
|
||||||
|
contracts.instaMapping,
|
||||||
|
contracts.instaMaster
|
||||||
|
);
|
||||||
|
const vaultAId = await initializeMakerCdp(
|
||||||
|
wallets.userAddress,
|
||||||
|
contracts.DAI,
|
||||||
|
contracts.dsa,
|
||||||
|
contracts.getCdps,
|
||||||
|
contracts.dssCdpManager,
|
||||||
|
constants.MAKER_INITIAL_ETH,
|
||||||
|
constants.MAKER_INITIAL_DEBT
|
||||||
|
);
|
||||||
|
const vaultBId = await createVaultForETHB(
|
||||||
|
wallets.userAddress,
|
||||||
|
contracts.DAI,
|
||||||
|
contracts.dsa,
|
||||||
|
contracts.getCdps,
|
||||||
|
contracts.dssCdpManager
|
||||||
|
);
|
||||||
|
const spells = await providerWhiteListTaskForMakerETHAToMakerETHBWithVaultB(
|
||||||
|
wallets,
|
||||||
|
contracts,
|
||||||
|
constants,
|
||||||
|
vaultAId,
|
||||||
|
vaultBId
|
||||||
|
);
|
||||||
|
|
||||||
|
const ABI = getABI();
|
||||||
|
|
||||||
|
return {
|
||||||
|
wallets,
|
||||||
|
contracts,
|
||||||
|
constants,
|
||||||
|
vaultAId,
|
||||||
|
vaultBId,
|
||||||
|
spells,
|
||||||
|
ABI,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = setupFullRefinanceMakerToMakerWithVaultBCreation;
|
157
test/unit_tests/4_ConditionDebtBridgeIsAffordable.test.js
Normal file
157
test/unit_tests/4_ConditionDebtBridgeIsAffordable.test.js
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
const {expect} = require("chai");
|
||||||
|
const hre = require("hardhat");
|
||||||
|
const {deployments, ethers} = hre;
|
||||||
|
|
||||||
|
// #region Contracts ABI
|
||||||
|
|
||||||
|
const ConnectMaker = require("../../pre-compiles/ConnectMaker.json");
|
||||||
|
const GetCdps = require("../../pre-compiles/GetCdps.json");
|
||||||
|
const DssCdpManager = require("../../pre-compiles/DssCdpManager.json");
|
||||||
|
const InstaList = require("../../pre-compiles/InstaList.json");
|
||||||
|
const InstaAccount = require("../../pre-compiles/InstaAccount.json");
|
||||||
|
const InstaIndex = require("../../pre-compiles/InstaIndex.json");
|
||||||
|
const IERC20 = require("../../pre-compiles/IERC20.json");
|
||||||
|
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
describe("ConditionDebtBridgeIsAffordable 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 userWallet;
|
||||||
|
let userAddress;
|
||||||
|
|
||||||
|
let getCdps;
|
||||||
|
let dssCdpManager;
|
||||||
|
let instaList;
|
||||||
|
let instaIndex;
|
||||||
|
let DAI;
|
||||||
|
|
||||||
|
let conditionDebtBridgeIsAffordable;
|
||||||
|
|
||||||
|
let dsa;
|
||||||
|
let cdpId;
|
||||||
|
|
||||||
|
beforeEach(async function () {
|
||||||
|
// Deploy contract dependencies
|
||||||
|
await deployments.fixture();
|
||||||
|
|
||||||
|
// Get Test Wallet for local testnet
|
||||||
|
[userWallet] = await ethers.getSigners();
|
||||||
|
userAddress = await userWallet.getAddress();
|
||||||
|
|
||||||
|
// Hardhat default accounts prefilled with 100 ETH
|
||||||
|
expect(await userWallet.getBalance()).to.be.gt(
|
||||||
|
ethers.utils.parseEther("10")
|
||||||
|
);
|
||||||
|
|
||||||
|
instaIndex = await ethers.getContractAt(
|
||||||
|
InstaIndex.abi,
|
||||||
|
hre.network.config.InstaIndex
|
||||||
|
);
|
||||||
|
instaList = await ethers.getContractAt(
|
||||||
|
InstaList.abi,
|
||||||
|
hre.network.config.InstaList
|
||||||
|
);
|
||||||
|
getCdps = await ethers.getContractAt(
|
||||||
|
GetCdps.abi,
|
||||||
|
hre.network.config.GetCdps
|
||||||
|
);
|
||||||
|
dssCdpManager = await ethers.getContractAt(
|
||||||
|
DssCdpManager.abi,
|
||||||
|
hre.network.config.DssCdpManager
|
||||||
|
);
|
||||||
|
DAI = await ethers.getContractAt(IERC20.abi, hre.network.config.DAI);
|
||||||
|
|
||||||
|
// ========== Test Setup ============
|
||||||
|
conditionDebtBridgeIsAffordable = await ethers.getContract(
|
||||||
|
"ConditionDebtBridgeIsAffordable"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create DeFi Smart Account
|
||||||
|
|
||||||
|
const dsaAccountCount = await instaList.accounts();
|
||||||
|
|
||||||
|
await expect(instaIndex.build(userAddress, 1, userAddress)).to.emit(
|
||||||
|
instaIndex,
|
||||||
|
"LogAccountCreated"
|
||||||
|
);
|
||||||
|
const dsaID = dsaAccountCount.add(1);
|
||||||
|
await expect(await instaList.accounts()).to.be.equal(dsaID);
|
||||||
|
|
||||||
|
// Instantiate the DSA
|
||||||
|
dsa = await ethers.getContractAt(
|
||||||
|
InstaAccount.abi,
|
||||||
|
await instaList.accountAddr(dsaID)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create/Deposit/Borrow a Vault
|
||||||
|
const openVault = await hre.run("abi-encode-withselector", {
|
||||||
|
abi: ConnectMaker.abi,
|
||||||
|
functionname: "open",
|
||||||
|
inputs: ["ETH-A"],
|
||||||
|
});
|
||||||
|
|
||||||
|
await dsa.cast([hre.network.config.ConnectMaker], [openVault], userAddress);
|
||||||
|
|
||||||
|
let cdps = await getCdps.getCdpsAsc(dssCdpManager.address, dsa.address);
|
||||||
|
cdpId = String(cdps.ids[0]);
|
||||||
|
|
||||||
|
expect(cdps.ids[0].isZero()).to.be.false;
|
||||||
|
|
||||||
|
await dsa.cast(
|
||||||
|
[hre.network.config.ConnectMaker],
|
||||||
|
[
|
||||||
|
await hre.run("abi-encode-withselector", {
|
||||||
|
abi: ConnectMaker.abi,
|
||||||
|
functionname: "deposit",
|
||||||
|
inputs: [cdpId, ethers.utils.parseEther("10"), 0, 0],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
userAddress,
|
||||||
|
{
|
||||||
|
value: ethers.utils.parseEther("10"),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
await dsa.cast(
|
||||||
|
[hre.network.config.ConnectMaker],
|
||||||
|
[
|
||||||
|
await hre.run("abi-encode-withselector", {
|
||||||
|
abi: ConnectMaker.abi,
|
||||||
|
functionname: "borrow",
|
||||||
|
inputs: [cdpId, ethers.utils.parseUnits("1000", 18), 0, 0],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
userAddress
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(await DAI.balanceOf(dsa.address)).to.be.equal(
|
||||||
|
ethers.utils.parseEther("1000")
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#1: ok should return DebtRefinanceTooExpensive when the gas fees exceed a define amount", async function () {
|
||||||
|
const conditionData = await conditionDebtBridgeIsAffordable.getConditionData(
|
||||||
|
cdpId,
|
||||||
|
ethers.utils.parseUnits("5", 15)
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await conditionDebtBridgeIsAffordable.ok(0, conditionData, 0)
|
||||||
|
).to.be.equal("DebtRefinanceTooExpensive");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#2: ok should return OK when the gas fees not exceed a define amount", async function () {
|
||||||
|
const conditionData = await conditionDebtBridgeIsAffordable.getConditionData(
|
||||||
|
cdpId,
|
||||||
|
ethers.utils.parseUnits("10", 15)
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await conditionDebtBridgeIsAffordable.ok(0, conditionData, 0)
|
||||||
|
).to.be.equal("OK");
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user