Add Term Ok for checking ownership of vault

This commit is contained in:
Shivva 2020-11-24 08:50:34 +01:00 committed by Luis Schliesske
parent 22c4a0268f
commit 5b055edca7
10 changed files with 339 additions and 88 deletions

View File

@ -0,0 +1,192 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.7.4;
pragma experimental ABIEncoderV2;
import {GelatoBytes} from "../../lib/GelatoBytes.sol";
import {sub} from "../../vendor/DSMath.sol";
import {
AccountInterface,
ConnectorInterface
} from "../../interfaces/InstaDapp/IInstaDapp.sol";
import {
IConnectInstaPoolV2
} from "../../interfaces/InstaDapp/connectors/IConnectInstaPoolV2.sol";
import {IMcdManager} from "../../interfaces/dapps/Maker/IMcdManager.sol";
import {
DAI,
CONNECT_MAKER,
CONNECT_COMPOUND,
INSTA_POOL_V2
} from "../../constants/CInstaDapp.sol";
import {MCD_MANAGER} from "../../constants/CMaker.sol";
import {
_getMakerVaultDebt,
_getMakerVaultCollateralBalance
} from "../../functions/dapps/FMaker.sol";
import {
_encodeFlashPayback
} from "../../functions/InstaDapp/connectors/FInstaPoolV2.sol";
import {
_encodePaybackMakerVault,
_encodedWithdrawMakerVault,
_encodeOpenMakerVault,
_encodedDepositMakerVault,
_encodeBorrowMakerVault
} from "../../functions/InstaDapp/connectors/FConnectMaker.sol";
import {
_encodePayGelatoProvider
} from "../../functions/InstaDapp/connectors/FConnectGelatoProviderPayment.sol";
import {
_encodeDepositCompound,
_encodeBorrowCompound
} from "../../functions/InstaDapp/connectors/FConnectCompound.sol";
import {_getGelatoProviderFees} from "../../functions/gelato/FGelato.sol";
import {
_getFlashLoanRoute,
_getGasCostMakerToMaker,
_getGasCostMakerToCompound,
_getRealisedDebt
} from "../../functions/gelato/FGelatoDebtBridge.sol";
import {
DataFlow
} from "@gelatonetwork/core/contracts/gelato_core/interfaces/IGelatoCore.sol";
import {
IGelatoAction
} from "@gelatonetwork/core/contracts/actions/IGelatoAction.sol";
contract ConnectGelatoDataFullMakerToCompound is
ConnectorInterface,
IGelatoAction
{
using GelatoBytes for bytes;
string public constant OK = "OK";
// solhint-disable const-name-snakecase
string public constant override name =
"ConnectGelatoDataFullRefinanceMaker-v1.0";
uint256 internal immutable _id;
address internal immutable _connectGelatoProviderPayment;
constructor(uint256 id, address connectGelatoProviderPayment) {
_id = id;
_connectGelatoProviderPayment = connectGelatoProviderPayment;
}
/// @dev Connector Details
function connectorID()
external
view
override
returns (uint256 _type, uint256 id)
{
(_type, id) = (1, _id); // Should put specific value.
}
// ====== ACTION TERMS CHECK ==========
// Overriding IGelatoAction's function (optional)
function termsOk(
uint256, // taskReceipId
address _dsa,
bytes calldata _actionData,
DataFlow, // DataFlow
uint256, // value
uint256 // cycleId
) public view virtual override returns (string memory) {
(uint256 vaultId, ) = abi.decode(_actionData[4:], (uint256, address));
IMcdManager managerContract = IMcdManager(MCD_MANAGER);
if (vaultId == 0)
return "ConnectGelatoDataFullETHAToETHB : Vault Id is not valid";
if (managerContract.owns(vaultId) != _dsa)
return "ConnectGelatoDataFullETHAToETHB : Vault not owns by dsa";
return OK;
}
/// @notice Entry Point for DSA.cast DebtBridge from Maker to Compound
/// @dev payable to be compatible in conjunction with DSA.cast payable target
/// @param _vaultId Id of the unsafe vault of the client.
/// @param _colToken vault's col token address .
function getDataAndCastMakerToCompound(uint256 _vaultId, address _colToken)
external
payable
{
(address[] memory targets, bytes[] memory datas) =
_dataMakerToCompound(_vaultId, _colToken);
_cast(targets, datas);
}
function _cast(address[] memory targets, bytes[] memory datas) internal {
// Instapool V2 / FlashLoan call
bytes memory castData =
abi.encodeWithSelector(
AccountInterface.cast.selector,
targets,
datas,
msg.sender // msg.sender == GelatoCore
);
(bool success, bytes memory returndata) =
address(this).delegatecall(castData);
if (!success) {
returndata.revertWithError(
"ConnectGelatoDataFullRefinanceMaker._cast:"
);
}
}
/* solhint-disable function-max-lines */
function _dataMakerToCompound(uint256 _vaultId, address _colToken)
internal
view
returns (address[] memory targets, bytes[] memory datas)
{
targets = new address[](1);
targets[0] = INSTA_POOL_V2;
uint256 wDaiToBorrow = _getRealisedDebt(_getMakerVaultDebt(_vaultId));
uint256 wColToWithdrawFromMaker =
_getMakerVaultCollateralBalance(_vaultId);
uint256 route = _getFlashLoanRoute(DAI, wDaiToBorrow);
uint256 gasCost = _getGasCostMakerToCompound(route);
uint256 gasFeesPaidFromCol = _getGelatoProviderFees(gasCost);
address[] memory _targets = new address[](6);
_targets[0] = CONNECT_MAKER; // payback
_targets[1] = CONNECT_MAKER; // withdraw
_targets[2] = CONNECT_COMPOUND; // deposit
_targets[3] = CONNECT_COMPOUND; // borrow
_targets[4] = _connectGelatoProviderPayment; // payProvider
_targets[5] = INSTA_POOL_V2; // flashPayback
bytes[] memory _datas = new bytes[](6);
_datas[0] = _encodePaybackMakerVault(_vaultId, uint256(-1), 0, 600);
_datas[1] = _encodedWithdrawMakerVault(_vaultId, uint256(-1), 0, 0);
_datas[2] = _encodeDepositCompound(
_colToken,
sub(wColToWithdrawFromMaker, gasFeesPaidFromCol),
0,
0
);
_datas[3] = _encodeBorrowCompound(DAI, 0, 600, 0);
_datas[4] = _encodePayGelatoProvider(
_colToken,
gasFeesPaidFromCol,
0,
0
);
_datas[5] = _encodeFlashPayback(DAI, wDaiToBorrow, 0, 0);
datas = new bytes[](1);
datas[0] = abi.encodeWithSelector(
IConnectInstaPoolV2.flashBorrowAndCast.selector,
DAI,
wDaiToBorrow,
route,
abi.encode(_targets, _datas)
);
}
/* solhint-enable function-max-lines */
}

View File

@ -11,12 +11,14 @@ import {
import {
IConnectInstaPoolV2
} from "../../interfaces/InstaDapp/connectors/IConnectInstaPoolV2.sol";
import {IMcdManager} from "../../interfaces/dapps/Maker/IMcdManager.sol";
import {
DAI,
CONNECT_MAKER,
CONNECT_COMPOUND,
INSTA_POOL_V2
} from "../../constants/CInstaDapp.sol";
import {MCD_MANAGER} from "../../constants/CMaker.sol";
import {
_getMakerVaultDebt,
_getMakerVaultCollateralBalance
@ -45,9 +47,19 @@ import {
_getGasCostMakerToCompound,
_getRealisedDebt
} from "../../functions/gelato/FGelatoDebtBridge.sol";
import {
DataFlow
} from "@gelatonetwork/core/contracts/gelato_core/interfaces/IGelatoCore.sol";
import {
IGelatoAction
} from "@gelatonetwork/core/contracts/actions/IGelatoAction.sol";
contract ConnectGelatoDataFullRefinanceMaker is ConnectorInterface {
contract ConnectGelatoDataFullMakerToMaker is
ConnectorInterface,
IGelatoAction
{
using GelatoBytes for bytes;
string public constant OK = "OK";
// solhint-disable const-name-snakecase
string public constant override name =
@ -70,6 +82,30 @@ contract ConnectGelatoDataFullRefinanceMaker is ConnectorInterface {
(_type, id) = (1, _id); // Should put specific value.
}
// ====== ACTION TERMS CHECK ==========
// Overriding IGelatoAction's function (optional)
function termsOk(
uint256, // taskReceipId
address _dsa,
bytes calldata _actionData,
DataFlow,
uint256, // value
uint256 // cycleId
) public view virtual override returns (string memory) {
(uint256 vaultAId, uint256 vaultBId, , ) =
abi.decode(_actionData[4:], (uint256, uint256, address, string));
IMcdManager managerContract = IMcdManager(MCD_MANAGER);
if (vaultAId == 0)
return "ConnectGelatoDataFullETHAToETHB : Vault A Id is not valid";
if (managerContract.owns(vaultAId) != _dsa)
return "ConnectGelatoDataFullETHAToETHB : Vault A not owns by dsa";
if (vaultBId != 0 && managerContract.owns(vaultBId) != _dsa)
return "ConnectGelatoDataFullETHAToETHB : Vault B not owns by dsa";
return OK;
}
/// @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
/// @param _vaultAId Id of the unsafe vault of the client of Vault A Collateral.
@ -88,20 +124,6 @@ contract ConnectGelatoDataFullRefinanceMaker is ConnectorInterface {
_cast(targets, datas);
}
/// @notice Entry Point for DSA.cast DebtBridge from Maker to Compound
/// @dev payable to be compatible in conjunction with DSA.cast payable target
/// @param _vaultId Id of the unsafe vault of the client.
/// @param _colToken vault's col token address .
function getDataAndCastMakerToCompound(uint256 _vaultId, address _colToken)
external
payable
{
(address[] memory targets, bytes[] memory datas) =
_dataMakerToCompound(_vaultId, _colToken);
_cast(targets, datas);
}
function _cast(address[] memory targets, bytes[] memory datas) internal {
// Instapool V2 / FlashLoan call
bytes memory castData =
@ -240,56 +262,5 @@ contract ConnectGelatoDataFullRefinanceMaker is ConnectorInterface {
datas[5] = _encodeFlashPayback(DAI, _wDaiToBorrow, 0, 0);
}
function _dataMakerToCompound(uint256 _vaultId, address _colToken)
internal
view
returns (address[] memory targets, bytes[] memory datas)
{
targets = new address[](1);
targets[0] = INSTA_POOL_V2;
uint256 wDaiToBorrow = _getRealisedDebt(_getMakerVaultDebt(_vaultId));
uint256 wColToWithdrawFromMaker =
_getMakerVaultCollateralBalance(_vaultId);
uint256 route = _getFlashLoanRoute(DAI, wDaiToBorrow);
uint256 gasCost = _getGasCostMakerToCompound(route);
uint256 gasFeesPaidFromCol = _getGelatoProviderFees(gasCost);
address[] memory _targets = new address[](6);
_targets[0] = CONNECT_MAKER; // payback
_targets[1] = CONNECT_MAKER; // withdraw
_targets[2] = CONNECT_COMPOUND; // deposit
_targets[3] = CONNECT_COMPOUND; // borrow
_targets[4] = _connectGelatoProviderPayment; // payProvider
_targets[5] = INSTA_POOL_V2; // flashPayback
bytes[] memory _datas = new bytes[](6);
_datas[0] = _encodePaybackMakerVault(_vaultId, uint256(-1), 0, 600);
_datas[1] = _encodedWithdrawMakerVault(_vaultId, uint256(-1), 0, 0);
_datas[2] = _encodeDepositCompound(
_colToken,
sub(wColToWithdrawFromMaker, gasFeesPaidFromCol),
0,
0
);
_datas[3] = _encodeBorrowCompound(DAI, 0, 600, 0);
_datas[4] = _encodePayGelatoProvider(
_colToken,
gasFeesPaidFromCol,
0,
0
);
_datas[5] = _encodeFlashPayback(DAI, wDaiToBorrow, 0, 0);
datas = new bytes[](1);
datas[0] = abi.encodeWithSelector(
IConnectInstaPoolV2.flashBorrowAndCast.selector,
DAI,
wDaiToBorrow,
route,
abi.encode(_targets, _datas)
);
}
/* solhint-enable function-max-lines */
}

View File

@ -7,4 +7,6 @@ interface IMcdManager {
function urns(uint256) external view returns (address);
function vat() external view returns (address);
function owns(uint256) external view returns (address);
}

View File

@ -6,7 +6,7 @@ const InstaConnector = require("../../pre-compiles/InstaConnectors.json");
module.exports = async (hre) => {
if (hre.network.name === "mainnet") {
console.log(
"Deploying ConnectGelatoDataFullRefinanceMaker to mainnet. Hit ctrl + c to abort"
"Deploying ConnectGelatoDataFullMakerToCompound to mainnet. Hit ctrl + c to abort"
);
console.log("❗ CONNECTOR DEPLOYMENT: VERIFY & HARDCODE CONNECTOR ID");
await sleep(6000);
@ -39,7 +39,7 @@ module.exports = async (hre) => {
const connectorLength = await instaConnectors.connectorLength();
const connectorId = connectorLength.add(1);
await deploy("ConnectGelatoDataFullRefinanceMaker", {
await deploy("ConnectGelatoDataFullMakerToCompound", {
from: deployer,
args: [
connectorId,
@ -50,7 +50,7 @@ module.exports = async (hre) => {
await instaConnectors
.connect(instaMaster)
.enable(
(await ethers.getContract("ConnectGelatoDataFullRefinanceMaker"))
(await ethers.getContract("ConnectGelatoDataFullMakerToCompound"))
.address
);
@ -59,12 +59,12 @@ module.exports = async (hre) => {
params: [await instaMaster.getAddress()],
});
} else {
// the following will only deploy "ConnectGelatoDataFullRefinanceMaker"
// the following will only deploy "ConnectGelatoDataFullMakerToCompound"
// if the contract was never deployed or if the code changed since last deployment
await deploy("ConnectGelatoDataFullRefinanceMaker", {
await deploy("ConnectGelatoDataFullMakerToCompound", {
from: deployer,
args: [
parseInt(process.env.ConnectGelatoDataFullRefinanceMakerId),
parseInt(process.env.ConnectGelatoDataFullMakerToCompoundId),
(await deployments.get("ConnectGelatoProviderPayment")).address,
],
gasPrice: hre.network.config.gasPrice,
@ -76,8 +76,8 @@ module.exports = async (hre) => {
module.exports.skip = async (hre) => {
if (hre.network.name === "mainnet") return true;
if (hre.network.name !== "hardhat")
return process.env.ConnectGelatoDataFullRefinanceMakerId === undefined;
return process.env.ConnectGelatoDataFullMakerToCompoundId === undefined;
return false;
};
module.exports.dependencies = ["ConnectGelatoProviderPayment"];
module.exports.tags = ["ConnectGelatoDataFullRefinanceMaker"];
module.exports.tags = ["ConnectGelatoDataFullMakerToCompound"];

View File

@ -0,0 +1,82 @@
const hre = require("hardhat");
const { ethers } = hre;
const { sleep } = require("@gelatonetwork/core");
const InstaConnector = require("../../pre-compiles/InstaConnectors.json");
module.exports = async (hre) => {
if (hre.network.name === "mainnet") {
console.log(
"Deploying ConnectGelatoDataFullMakerToMaker to mainnet. Hit ctrl + c to abort"
);
console.log("❗ CONNECTOR DEPLOYMENT: VERIFY & HARDCODE CONNECTOR ID");
await sleep(6000);
}
const { deployments } = hre;
const { deploy } = deployments;
const { deployer } = await hre.getNamedAccounts();
if (hre.network.name === "hardhat") {
const deployerWallet = await ethers.provider.getSigner(deployer);
const instaMaster = await ethers.provider.getSigner(
hre.network.config.InstaMaster
);
await deployerWallet.sendTransaction({
to: await instaMaster.getAddress(),
value: ethers.utils.parseEther("0.1"),
});
await hre.network.provider.request({
method: "hardhat_impersonateAccount",
params: [await instaMaster.getAddress()],
});
const instaConnectors = await hre.ethers.getContractAt(
InstaConnector.abi,
hre.network.config.InstaConnectors
);
const connectorLength = await instaConnectors.connectorLength();
const connectorId = connectorLength.add(1);
await deploy("ConnectGelatoDataFullMakerToMaker", {
from: deployer,
args: [
connectorId,
(await deployments.get("ConnectGelatoProviderPayment")).address,
],
});
await instaConnectors
.connect(instaMaster)
.enable(
(await ethers.getContract("ConnectGelatoDataFullMakerToMaker")).address
);
await hre.network.provider.request({
method: "hardhat_stopImpersonatingAccount",
params: [await instaMaster.getAddress()],
});
} else {
// the following will only deploy "ConnectGelatoDataFullMakerToMaker"
// if the contract was never deployed or if the code changed since last deployment
await deploy("ConnectGelatoDataFullMakerToMaker", {
from: deployer,
args: [
parseInt(process.env.ConnectGelatoDataFullMakerToMakerId),
(await deployments.get("ConnectGelatoProviderPayment")).address,
],
gasPrice: hre.network.config.gasPrice,
log: true,
});
}
};
module.exports.skip = async (hre) => {
if (hre.network.name === "mainnet") return true;
if (hre.network.name !== "hardhat")
return process.env.ConnectGelatoDataFullMakerToMakerId === undefined;
return false;
};
module.exports.dependencies = ["ConnectGelatoProviderPayment"];
module.exports.tags = ["ConnectGelatoDataFullMakerToMaker"];

View File

@ -103,8 +103,11 @@ module.exports = async function () {
"ConnectGelatoProviderPayment"
);
const makerResolver = await ethers.getContract("MakerResolver");
const connectGelatoDataFullRefinanceMaker = await ethers.getContract(
"ConnectGelatoDataFullRefinanceMaker"
const connectGelatoDataFullMakerToMaker = await ethers.getContract(
"ConnectGelatoDataFullMakerToMaker"
);
const connectGelatoDataFullMakerToCompound = await ethers.getContract(
"ConnectGelatoDataFullMakerToCompound"
);
const mockDebtBridgeETHBExecutor = await ethers.getContract(
"MockDebtBridgeETHBExecutor"
@ -122,7 +125,8 @@ module.exports = async function () {
connectMaker,
connectInstaPool,
connectCompound,
connectGelatoDataFullRefinanceMaker,
connectGelatoDataFullMakerToMaker,
connectGelatoDataFullMakerToCompound,
instaIndex,
instaList,
instaMapping,

View File

@ -15,11 +15,10 @@ module.exports = async function (wallets, contracts, constants, vaultId) {
const spells = [];
const debtBridgeCalculationForFullRefinance = new GelatoCoreLib.Action({
addr: contracts.connectGelatoDataFullRefinanceMaker.address,
addr: contracts.connectGelatoDataFullMakerToMaker.address,
data: await hre.run("abi-encode-withselector", {
abi: (
await deployments.getArtifact("ConnectGelatoDataFullRefinanceMaker")
).abi,
abi: (await deployments.getArtifact("ConnectGelatoDataFullMakerToMaker"))
.abi,
functionname: "getDataAndCastMakerToMaker",
inputs: [vaultId, 0, constants.ETH, "ETH-B"],
}),

View File

@ -21,15 +21,15 @@ module.exports = async function (
const spells = [];
const debtBridgeCalculationForFullRefinance = new GelatoCoreLib.Action({
addr: contracts.connectGelatoDataFullRefinanceMaker.address,
addr: contracts.connectGelatoDataFullMakerToMaker.address,
data: await hre.run("abi-encode-withselector", {
abi: (
await deployments.getArtifact("ConnectGelatoDataFullRefinanceMaker")
).abi,
abi: (await deployments.getArtifact("ConnectGelatoDataFullMakerToMaker"))
.abi,
functionname: "getDataAndCastMakerToMaker",
inputs: [vaultAId, vaultBId, constants.ETH, "ETH-B"],
}),
operation: GelatoCoreLib.Operation.Delegatecall,
termsOkCheck: true,
});
spells.push(debtBridgeCalculationForFullRefinance);

View File

@ -15,15 +15,16 @@ module.exports = async function (wallets, contracts, constants, vaultId) {
const spells = [];
const debtBridgeCalculationForFullRefinance = new GelatoCoreLib.Action({
addr: contracts.connectGelatoDataFullRefinanceMaker.address,
addr: contracts.connectGelatoDataFullMakerToCompound.address,
data: await hre.run("abi-encode-withselector", {
abi: (
await deployments.getArtifact("ConnectGelatoDataFullRefinanceMaker")
await deployments.getArtifact("ConnectGelatoDataFullMakerToCompound")
).abi,
functionname: "getDataAndCastMakerToCompound",
inputs: [vaultId, constants.ETH],
}),
operation: GelatoCoreLib.Operation.Delegatecall,
termsOkCheck: true,
});
spells.push(debtBridgeCalculationForFullRefinance);

View File

@ -143,7 +143,7 @@ describe("ConditionDestVaultWillBeSafe Unit Test", function () {
amountToBorrow = ethers.utils.parseUnits("100", 18);
});
it("#1: ok should return DebtBridgeNotAffordable when the gas fees exceed a define amount", async function () {
it("#1: ok should return Ok when the gas fees didn't exceed a user define amount", async function () {
const conditionData = await conditionDestVaultWillBeSafe.getConditionData(
cdpId,
0,