// const { expect } = require("chai"); // const hre = require("hardhat"); // const { deployments, ethers } = hre; // const GelatoCoreLib = require("@gelatonetwork/core"); // // #region Contracts ABI and Constants // const InstaIndex = require("../../../../pre-compiles/InstaIndex.json"); // const InstaList = require("../../../../pre-compiles/InstaList.json"); // const InstaAccount = require("../../../../pre-compiles/InstaAccount.json"); // const ConnectGelato = require("../../../../pre-compiles/ConnectGelato.json"); // 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 ConnectGelatoFullDebtBridgeFromMakerABI = require("../artifacts/contracts/contracts/connectors/ConnectGelatoPartialDebtBridgeFromMaker.sol/ConnectGelatoPartialDebtBridgeFromMaker.json") // .abi; // const ConnectGelatoProviderPaymentABI = require("../../../../artifacts/contracts/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 CompoundResolver = require("../../../../pre-compiles/InstaCompoundResolver.json"); // 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 // function wdiv(x, y) { // return x.mul(WAD).add(y.div(2)).div(y); // } // function wmul(x, y) { // return x.mul(y).add(WAD.div(2)).div(WAD); // } // function wCalcCollateralToWithdraw( // minColRatioOnMaker, // minColRatioOnPositionB, // collateralPrice, // pricedCollateral, // daiDebtOnMaker // ) { // //#region CALCULATION REPLICATION // let expectedColToWithdraw = wmul( // wmul(minColRatioOnMaker, minColRatioOnPositionB), // daiDebtOnMaker // ); // doc ref : c_r x comp_r x d_2 // expectedColToWithdraw = expectedColToWithdraw.sub( // wmul(minColRatioOnMaker, pricedCollateral) // ); // doc ref : c_r x comp_r x d_2 - c_r x e_2 // expectedColToWithdraw = wdiv( // expectedColToWithdraw, // minColRatioOnPositionB.sub(minColRatioOnMaker) // ); // doc ref : (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; // } // function wCalcDebtToRepay( // minColRatioOnMaker, // minColRatioOnPositionB, // pricedCollateral, // daiDebtOnMaker // ) { // //#region CALCULATION REPLICATION // let expectedBorToPayBack = wmul( // wmul(minColRatioOnMaker, minColRatioOnPositionB), // daiDebtOnMaker // ); // doc ref : c_r x comp_r x d_2 // expectedBorToPayBack = expectedBorToPayBack.sub( // wmul(minColRatioOnMaker, pricedCollateral) // ); // doc ref : c_r x comp_r x d_2 - c_r x e_2 // expectedBorToPayBack = wdiv( // expectedBorToPayBack, // 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), 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 = 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 (hre.network.name !== "hardhat") { // console.error("Test Suite is meant to be run on hardhat only"); // process.exit(1); // } // // Wallet to use for local testing // let userWallet; // let userAddress; // let gelatoProviderWallet; // let gelatoProviderAddress; // let gelatoExecutorWallet; // let gelatoExecutorAddress; // // Deployed instances // let connectGelato; // let connectMaker; // let connectInstaPool; // let connectCompound; // let instaIndex; // let instaList; // let dssCdpManager; // let getCdps; // let DAI; // let gelatoCore; // let cDaiToken; // let cEthToken; // let instaMaster; // let instaConnectors; // let compoundResolver; // // Contracts to deploy and use for local testing // let conditionMakerVaultUnsafe; // let connectGelatoPartialDebtBridgeFromMaker; // let connectGelatoProviderPayment; // let priceOracleResolver; // let dsaProviderModule; // // Creation during test // let dsa; // // Payload Params for ConnectGelatoPartialDebtBridgeFromMaker and ConditionMakerVaultUnsafe // let vaultId; // // For TaskSpec and for Task // let spells = []; // before(async function () { // // Get Test Wallet for local testnet // [ // userWallet, // gelatoProviderWallet, // gelatoExecutorWallet, // ] = await ethers.getSigners(); // userAddress = await userWallet.getAddress(); // gelatoProviderAddress = await gelatoProviderWallet.getAddress(); // gelatoExecutorAddress = await gelatoExecutorWallet.getAddress(); // instaMaster = await ethers.provider.getSigner( // hre.network.config.InstaMaster // ); // // Hardhat default accounts prefilled with 100 ETH // expect(await userWallet.getBalance()).to.be.gt( // ethers.utils.parseEther("10") // ); // // ===== Get Deployed Contract Instance ================== // instaIndex = await ethers.getContractAt( // InstaIndex.abi, // hre.network.config.InstaIndex // ); // instaList = await ethers.getContractAt( // InstaList.abi, // hre.network.config.InstaList // ); // connectGelato = await ethers.getContractAt( // ConnectGelato.abi, // hre.network.config.ConnectGelato // ); // connectMaker = await ethers.getContractAt( // ConnectMaker.abi, // hre.network.config.ConnectMaker // ); // connectInstaPool = await ethers.getContractAt( // ConnectInstaPool.abi, // hre.network.config.ConnectInstaPool // ); // connectCompound = await ethers.getContractAt( // ConnectCompound.abi, // hre.network.config.ConnectCompound // ); // dssCdpManager = await ethers.getContractAt( // DssCdpManager.abi, // hre.network.config.DssCdpManager // ); // getCdps = await ethers.getContractAt( // GetCdps.abi, // hre.network.config.GetCdps // ); // DAI = await ethers.getContractAt(IERC20.abi, hre.network.config.DAI); // gelatoCore = await ethers.getContractAt( // GelatoCoreLib.GelatoCore.abi, // hre.network.config.GelatoCore // ); // cDaiToken = await ethers.getContractAt( // CTokenInterface.abi, // hre.network.config.CDAI // ); // cEthToken = await ethers.getContractAt( // CTokenInterface.abi, // hre.network.config.CETH // ); // instaConnectors = await ethers.getContractAt( // InstaConnector.abi, // hre.network.config.InstaConnectors // ); // compoundResolver = await ethers.getContractAt( // CompoundResolver.abi, // hre.network.config.CompoundResolver // ); // // instaEvent = await ethers.getContractAt( // // InstaEvent.abi, // // hre.network.config.InstaEvent // // ) // // ===== Deploy Needed Contract ================== // const PriceOracleResolver = await ethers.getContractFactory( // "PriceOracleResolver" // ); // priceOracleResolver = await PriceOracleResolver.deploy(); // await priceOracleResolver.deployed(); // const ConditionMakerVaultUnsafe = await ethers.getContractFactory( // "ConditionMakerVaultUnsafe" // ); // conditionMakerVaultUnsafe = await ConditionMakerVaultUnsafe.deploy(); // await conditionMakerVaultUnsafe.deployed(); // const ConnectGelatoPartialDebtBridgeFromMaker = await ethers.getContractFactory( // "ConnectGelatoPartialDebtBridgeFromMaker" // ); // connectGelatoPartialDebtBridgeFromMaker = await ConnectGelatoPartialDebtBridgeFromMaker.deploy( // (await instaConnectors.connectorLength()).add(1) // ); // await connectGelatoPartialDebtBridgeFromMaker.deployed(); // const ConnectGelatoProviderPayment = await ethers.getContractFactory( // "ConnectGelatoProviderPayment" // ); // connectGelatoProviderPayment = await ConnectGelatoProviderPayment.deploy( // (await instaConnectors.connectorLength()).add(2) // ); // await connectGelatoProviderPayment.deployed(); // const ProviderModuleDsa = await ethers.getContractFactory( // "ProviderModuleDsa" // ); // dsaProviderModule = await ProviderModuleDsa.deploy( // hre.network.config.GelatoCore, // connectGelatoProviderPayment.address // ); // await dsaProviderModule.deployed(); // /////////////////////////////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////////////////////////// // /////////////////////////////// After Contracts Deployement : Setup /////////////////////////// // /////////////////////////////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////////////////////////// // // Gelato Testing environment setup. // // 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 : 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 PriceOracleResolver // // 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 priceOracleResolver.addOracle( // // ORACLE_MAKER_ETH_USD, // // ORACLE_MAKER_ETH_USD_ADDR, // // PRICE_ORACLE_MAKER_PAYLOAD // // ); // //#endregion // //#region Step 2 Enable Debt Bridge Connector and Gelato Provider Payment Connector // // Debt Bridge Connector is used during refinancing of debt // // This Connect help the user to split a position in one protocol. // // to 2 protocol in a safe way. Both debt position will be safe. // // Gelato Provider Payment Connector is used for paying the provider // // for task execution. So when futur task will be executed, through a self financing // // transaction (user will pay during the execution of the task) task will // // be executed. Improvind user experience. // 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(connectGelatoPartialDebtBridgeFromMaker.address); // await instaConnectors // .connect(instaMaster) // .enable(connectGelatoProviderPayment.address); // await hre.network.provider.request({ // method: "hardhat_stopImpersonatingAccount", // params: [await instaMaster.getAddress()], // }); // expect( // await instaConnectors.isConnector([ // connectGelatoPartialDebtBridgeFromMaker.address, // ]) // ).to.be.true; // expect( // await instaConnectors.isConnector([connectGelatoProviderPayment.address]) // ).to.be.true; // //#endregion // //#region Step 3 Executor Staking on Gelato // // For task execution provider will ask a executor to watch the // // blockchain for possible execution autorization given by // // the condition that user choose when submitting the task. // // And if all condition are meet executor will execute the task. // // For safety measure Gelato ask the executor to stake a minimum // // amount. // await gelatoCore.connect(gelatoExecutorWallet).stakeExecutor({ // value: await gelatoCore.minExecutorStake(), // }); // expect( // await gelatoCore.isExecutorMinStaked(gelatoExecutorAddress) // ).to.be.true; // //#endregion // //#region Step 4 Provider put some fund on gelato for paying future tasks executions // // Provider put some funds in gelato system for paying the // // Executor when this one will execute task on behalf of the // // Provider. At each provider's task execution, some funds (approximatively // // the gas cost value) will be transfered to the Executor stake. // const TASK_AUTOMATION_FUNDS = await gelatoCore.minExecProviderFunds( // GAS_LIMIT, // GAS_PRICE_CEIL // ); // await expect( // gelatoCore // .connect(gelatoProviderWallet) // .provideFunds(gelatoProviderAddress, { // value: TASK_AUTOMATION_FUNDS, // }) // ).to.emit(gelatoCore, "LogFundsProvided"); // expect(await gelatoCore.providerFunds(gelatoProviderAddress)).to.be.equal( // TASK_AUTOMATION_FUNDS // ); // //#endregion // //#region Step 5 Provider choose a executor // // Provider choose a executor who will execute futur task // // for the provider, it will be compensated by the provider. // await expect( // gelatoCore // .connect(gelatoProviderWallet) // .providerAssignsExecutor(gelatoExecutorAddress) // ).to.emit(gelatoCore, "LogProviderAssignedExecutor"); // expect( // await gelatoCore.executorByProvider(gelatoProviderAddress) // ).to.be.equal(gelatoExecutorAddress); // //#endregion // //#region Step 6 Provider will add a module // // By adding a module the provider will format future task's // // payload by adding some specificity like his address to the // // Payment connector for receiving payment of User. // await expect( // gelatoCore // .connect(gelatoProviderWallet) // .addProviderModules([dsaProviderModule.address]) // ).to.emit(gelatoCore, "LogProviderModuleAdded"); // expect( // await gelatoCore // .connect(gelatoProviderWallet) // .isModuleProvided(gelatoProviderAddress, dsaProviderModule.address) // ).to.be.true; // //#endregion // //#region Step 7 User create a DeFi Smart Account // // User create a Instadapp DeFi Smart Account // // who give him the possibility to interact // // with a large list of DeFi protocol through one // // Proxy 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) // ); // //#endregion // //#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-A"], // }); // 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( // [hre.network.config.ConnectMaker], // [ // await hre.run("abi-encode-withselector", { // abi: ConnectMaker.abi, // functionname: "deposit", // inputs: [vaultId, MAKER_INITIAL_ETH, 0, 0], // }), // ], // userAddress, // { // value: MAKER_INITIAL_ETH, // } // ); // await dsa.cast( // [hre.network.config.ConnectMaker], // [ // await hre.run("abi-encode-withselector", { // abi: ConnectMaker.abi, // functionname: "borrow", // inputs: [vaultId, MAKER_INITIAL_DEBT, 0, 0], // }), // ], // userAddress // ); // expect(await DAI.balanceOf(dsa.address)).to.be.equal(MAKER_INITIAL_DEBT); // //#endregion // //#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. // // In this case user give authorization to gelato to execute // // task for him if needed. // await dsa.cast( // [hre.network.config.ConnectAuth], // [ // await hre.run("abi-encode-withselector", { // abi: ConnectAuth.abi, // functionname: "add", // inputs: [gelatoCore.address], // }), // ], // userAddress // ); // expect(await dsa.isAuth(gelatoCore.address)).to.be.true; // //#endregion // //#region Step 10 Provider should whitelist task // // By WhiteList task, the provider can constrain the type // // of task the user can submitting. // //#region Actions // const debtBridgeCalculation = new GelatoCoreLib.Action({ // addr: connectGelatoPartialDebtBridgeFromMaker.address, // data: await hre.run("abi-encode-withselector", { // abi: ConnectGelatoFullDebtBridgeFromMakerABI, // functionname: "savePartialRefinanceDataToMemory", // inputs: [ // vaultId, // MIN_COL_RATIO_MAKER, // MIN_COL_RATIO_B, // priceOracleResolver.address, // await hre.run("abi-encode-withselector", { // abi: (await deployments.getArtifcat("PriceOracleResolver")).abi, // functionname: "getMockPrice", // inputs: [userAddress], // }), // 0, // 0, // ], // }), // operation: GelatoCoreLib.Operation.Delegatecall, // }); // spells.push(debtBridgeCalculation); // const flashBorrow = new GelatoCoreLib.Action({ // addr: connectInstaPool.address, // data: await hre.run("abi-encode-withselector", { // abi: ConnectInstaPool.abi, // functionname: "flashBorrow", // inputs: [hre.network.config.DAI, 0, "600", 0], // }), // operation: GelatoCoreLib.Operation.Delegatecall, // }); // spells.push(flashBorrow); // const paybackMaker = new GelatoCoreLib.Action({ // addr: connectMaker.address, // data: await hre.run("abi-encode-withselector", { // abi: ConnectMaker.abi, // functionname: "payback", // inputs: [vaultId, 0, "601", 0], // }), // operation: GelatoCoreLib.Operation.Delegatecall, // }); // spells.push(paybackMaker); // const withdrawMaker = new GelatoCoreLib.Action({ // addr: connectMaker.address, // data: await hre.run("abi-encode-withselector", { // abi: ConnectMaker.abi, // functionname: "withdraw", // inputs: [vaultId, 0, "602", 0], // }), // operation: GelatoCoreLib.Operation.Delegatecall, // }); // spells.push(withdrawMaker); // const depositCompound = new GelatoCoreLib.Action({ // addr: connectCompound.address, // data: await hre.run("abi-encode-withselector", { // abi: ConnectCompound.abi, // functionname: "deposit", // inputs: [ETH, 0, "603", 0], // }), // operation: GelatoCoreLib.Operation.Delegatecall, // }); // spells.push(depositCompound); // const borrowCompound = new GelatoCoreLib.Action({ // addr: connectCompound.address, // data: await hre.run("abi-encode-withselector", { // abi: ConnectCompound.abi, // functionname: "borrow", // inputs: [hre.network.config.DAI, 0, "604", 0], // }), // operation: GelatoCoreLib.Operation.Delegatecall, // }); // spells.push(borrowCompound); // const flashPayBack = new GelatoCoreLib.Action({ // addr: connectInstaPool.address, // data: await hre.run("abi-encode-withselector", { // abi: ConnectInstaPool.abi, // functionname: "flashPayback", // inputs: [hre.network.config.DAI, 0, 0], // }), // operation: GelatoCoreLib.Operation.Delegatecall, // }); // spells.push(flashPayBack); // const payProvider = new GelatoCoreLib.Action({ // addr: connectGelatoProviderPayment.address, // data: await hre.run("abi-encode-withselector", { // abi: ConnectGelatoProviderPaymentABI, // functionname: "payProvider", // inputs: [gelatoProviderAddress, ETH, 0, "605", 0], // }), // operation: GelatoCoreLib.Operation.Delegatecall, // }); // spells.push(payProvider); // const gasPriceCeil = ethers.constants.MaxUint256; // const connectGelatoFullDebtBridgeFromMakerTaskSpec = new GelatoCoreLib.TaskSpec( // { // conditions: [conditionMakerVaultUnsafe.address], // actions: spells, // gasPriceCeil, // } // ); // await expect( // gelatoCore // .connect(gelatoProviderWallet) // .provideTaskSpecs([connectGelatoFullDebtBridgeFromMakerTaskSpec]) // ).to.emit(gelatoCore, "LogTaskSpecProvided"); // expect( // await gelatoCore // .connect(gelatoProviderWallet) // .isTaskSpecProvided( // gelatoProviderAddress, // connectGelatoFullDebtBridgeFromMakerTaskSpec // ) // ).to.be.equal("OK"); // expect( // await gelatoCore // .connect(gelatoProviderWallet) // .taskSpecGasPriceCeil( // gelatoProviderAddress, // await gelatoCore // .connect(gelatoProviderWallet) // .hashTaskSpec(connectGelatoFullDebtBridgeFromMakerTaskSpec) // ) // ).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: (await deployments.getArtifact("PriceOracleResolver")).abi, // functionname: "getMockPrice", // inputs: [userAddress], // }), // MIN_COL_RATIO_MAKER // ), // }); // // ======= GELATO TASK SETUP ====== // const refinanceIfVaultUnsafe = new GelatoCoreLib.Task({ // conditions: [conditionMakerVaultUnsafeObj], // actions: spells, // }); // const gelatoExternalProvider = new GelatoCoreLib.GelatoProvider({ // addr: gelatoProviderAddress, // module: dsaProviderModule.address, // }); // const expiryDate = 0; // await expect( // dsa.cast( // [connectGelato.address], // targets // [ // await hre.run("abi-encode-withselector", { // abi: ConnectGelato.abi, // functionname: "submitTask", // inputs: [ // gelatoExternalProvider, // refinanceIfVaultUnsafe, // expiryDate, // ], // }), // ], // datas // userAddress, // origin // { // gasLimit: 5000000, // } // ) // ).to.emit(gelatoCore, "LogTaskSubmitted"); // const taskReceipt = new GelatoCoreLib.TaskReceipt({ // id: await gelatoCore.currentTaskReceiptId(), // userProxy: dsa.address, // provider: gelatoExternalProvider, // tasks: [refinanceIfVaultUnsafe], // expiryDate, // }); // //#endregion // //#region Step 2 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(GAS_PRICE_CEIL); // // TO DO: base mock price off of real price data // await priceOracleResolver.setMockPrice(ethers.utils.parseUnits("400", 18)); // expect( // await gelatoCore // .connect(gelatoExecutorWallet) // .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(gelatoExecutorWallet) // .canExec(taskReceipt, GAS_LIMIT, gelatoGasPrice) // ).to.be.equal("OK"); // //#endregion // //#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 // // by a debt refinancing in compound. // //#region EXPECTED OUTCOME // const latestPrice = await priceOracleResolver.getMockPrice(userAddress); // const gasFeesPaidFromCol = ethers.utils // .parseUnits(String(1933090 + 19331 * 2), 0) // .mul(gelatoGasPrice); // const debtOnMakerBefore = await connectGelatoPartialDebtBridgeFromMaker.getMakerVaultDebt( // vaultId // ); // const pricedCollateral = wmul( // ( // await connectGelatoPartialDebtBridgeFromMaker.getMakerVaultCollateralBalance( // vaultId // ) // ).sub(gasFeesPaidFromCol), // latestPrice // ); // const expectedColWithdrawAmount = wCalcCollateralToWithdraw( // MIN_COL_RATIO_MAKER, // MIN_COL_RATIO_B, // latestPrice, // pricedCollateral, // debtOnMakerBefore // ); // const expectedBorAmountToPayBack = wCalcDebtToRepay( // MIN_COL_RATIO_MAKER, // MIN_COL_RATIO_B, // pricedCollateral, // debtOnMakerBefore // ); // //console.log(String(wdiv(pricedCollateral.sub(wmul(expectedColWithdrawAmount, latestPrice).add(gasFeesPaidFromCol)),debt.sub(expectedBorAmountToPayBack)))); // //#endregion // const providerBalanceBeforeExecution = await gelatoProviderWallet.getBalance(); // await expect( // gelatoCore.connect(gelatoExecutorWallet).exec(taskReceipt, { // gasPrice: gelatoGasPrice, // Exectutor must use gelatoGasPrice (Chainlink fast gwei) // gasLimit: GAS_LIMIT, // }) // ).to.emit(gelatoCore, "LogExecSuccess"); // // 🚧 For Debugging: // // const txResponse2 = await gelatoCore // // .connect(gelatoProviderWallet) // // .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(await gelatoProviderWallet.getBalance()).to.be.gt( // providerBalanceBeforeExecution // ); // // compound position of DSA on cDai and cEth // 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. // const exchangeRateCethToEth = (await cEthToken.getCash()) // .add(await cEthToken.totalBorrows()) // .sub(await cEthToken.totalReserves()) // .div(await cEthToken.totalSupply()); // // Estimated amount to borrowed token should be equal to the actual one read on compound contracts // expect(expectedBorAmountToPayBack).to.be.equal( // compoundPosition[0].borrowBalanceStoredUser // ); // // 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)); // const debtOnMakerAfter = await connectGelatoPartialDebtBridgeFromMaker.getMakerVaultDebt( // vaultId // ); // const collateralOnMakerAfter = await connectGelatoPartialDebtBridgeFromMaker.getMakerVaultCollateralBalance( // vaultId // ); // in Ether. // // Total Borrowed Amount on both protocol should equal to the initial borrowed amount on maker vault. // expect( // debtOnMakerAfter // .add(compoundPosition[0].borrowBalanceStoredUser) // .sub(MAKER_INITIAL_DEBT) // ).to.be.lte(ethers.utils.parseUnits("1", 0)); // // Total Ether col on Maker and Compound (+ gasFeesPaidFromCol) should equal to the initial col on maker vault // expect( // compoundPosition[1].balanceOfUser // .mul(exchangeRateCethToEth) // .add(gasFeesPaidFromCol) // .add(collateralOnMakerAfter) // .sub(ethers.utils.parseEther("10")) // ).to.be.lt(ethers.utils.parseUnits("1", 12)); // // Check Collaterization Ratio of Maker and Compound // expect( // wdiv( // wmul( // compoundPosition[1].balanceOfUser.mul(exchangeRateCethToEth), // latestPrice // ), // compoundPosition[0].borrowBalanceStoredUser // ).sub(MIN_COL_RATIO_MAKER) // ).to.be.lt(ethers.utils.parseUnits("1", 12)); // expect( // wdiv( // wmul( // collateralOnMakerAfter, // await priceOracleResolver.getMockPrice(userAddress) // ), // debtOnMakerAfter // ).sub(MIN_COL_RATIO_MAKER) // ).to.be.lt(ethers.utils.parseUnits("1", 1)); // // DSA contain 1000 DAI // expect(await DAI.balanceOf(dsa.address)).to.be.equal(MAKER_INITIAL_DEBT); // //#endregion // }); // });