diff --git a/buidler.config.js b/buidler.config.js index f618ed9..4f58031 100644 --- a/buidler.config.js +++ b/buidler.config.js @@ -33,6 +33,7 @@ module.exports = { ConnectCompound: "0x07F81230d73a78f63F0c2A3403AD281b067d28F8", DAI: "0x6b175474e89094c44da98b954eedeac495271d0f", DAI_UNISWAP: "0x2a1530C4C41db0B0b2bB646CB5Eb1A67b7158667", + CDAI: "0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643", }, }, solc: { diff --git a/contracts/MockCDAI.sol b/contracts/MockCDAI.sol index 9446371..fe20bbc 100644 --- a/contracts/MockCDAI.sol +++ b/contracts/MockCDAI.sol @@ -7,7 +7,10 @@ contract MockCDAI { // CDAI uses supplyRatePerBlock with 10**18 precision // Because MakerDAO dsr is rate per second with 10**27 precision, // we also adopt this for CDAI. - uint256 public supplyRatePerSecond = 1000000000627937192491029810; // per second==2% annually + //uint256 public supplyRatePerSecond = 1000000000627937192491029810; // per second==2% annually + + uint256 public supplyRatePerSecond; + constructor(uint256 _sRPS) public { supplyRatePerSecond = _sRPS; } /// @dev Use this during tests to simulate changing CDAI.supplyRatePerBlock conditions /// @param _rate CDAI.supplyRatePerBlock but in seconds and 10**27 precision diff --git a/contracts/MockDSR.sol b/contracts/MockDSR.sol index 79783cb..21bdecf 100644 --- a/contracts/MockDSR.sol +++ b/contracts/MockDSR.sol @@ -9,10 +9,13 @@ contract MockDSR { // - can be set by Maker governance on the Pot contract in the RatesModule. // - returns annual percentage value as 10**27 [ray] // - e.g. dsr=1000000000627937192491029810 == 2 % annually - uint256 public dsr = 1000000000627937192491029810; // per second==2% annually + /// uint256 public dsr = 1000000000627937192491029810; // per second==2% annually + + uint256 public dsr; + constructor(uint256 _dsr) public { dsr = _dsr; } /// @dev Use this during tests to simulate changing DSR conditions - /// @param _dsr The dsr to set. + /// @param _dsr The dsr to set. function setDSR(uint256 _dsr) external virtual { dsr = _dsr; } diff --git a/test/mv-DAI-DSR-Compound.test.js b/test/mv-DAI-DSR-Compound.test.js index 9d666f1..9cf71c3 100644 --- a/test/mv-DAI-DSR-Compound.test.js +++ b/test/mv-DAI-DSR-Compound.test.js @@ -145,11 +145,12 @@ describe("Move DAI lending from DSR to Compound", function () { // Deploy Mocks for Testing const MockCDAI = await ethers.getContractFactory("MockCDAI"); - mockCDAI = await MockCDAI.deploy(); + mockCDAI = await MockCDAI.deploy(APY_2_PERCENT_IN_SECONDS); await providerModuleDSA.deployed(); const MockDSR = await ethers.getContractFactory("MockDSR"); - mockDSR = await MockDSR.deploy(); + mockDSR = await MockDSR.deploy(APY_2_PERCENT_IN_SECONDS); + await mockDSR.deployed(); // Deploy Gelato Conditions for Testing const ConditionCompareUintsFromTwoSources = await ethers.getContractFactory( @@ -207,7 +208,7 @@ describe("Move DAI lending from DSR to Compound", function () { // ======= Condition setup ====== // We instantiate the Rebalance Condition: // Compound APY needs to be 10000000 per second points higher than DSR - const MIN_SPREAD = 10000000; + const MIN_SPREAD = "10000000"; const rebalanceCondition = new GelatoCoreLib.Condition({ inst: conditionCompareUints.address, data: await conditionCompareUints.getConditionData( @@ -321,6 +322,9 @@ describe("Move DAI lending from DSR to Compound", function () { expect(await gelatoCore.providerFunds(dsa.address)).to.be.gte( TASK_AUTOMATION_FUNDS ); + expect( + await gelatoCore.isProviderLiquid(dsa.address, GAS_LIMIT, GAS_PRICE_CEIL) + ); expect(await gelatoCore.executorByProvider(dsa.address)).to.be.equal( userAddress ); @@ -328,6 +332,79 @@ describe("Move DAI lending from DSR to Compound", function () { await gelatoCore.isModuleProvided(dsa.address, providerModuleDSA.address) ).to.be.true; - // ======= TASK SUBMISSION ========= + // ======= 📣 TASK SUBMISSION 📣 ========= + // In Gelato world our DSA is the User. So we must submit the Task + // to Gelato via our DSA and hence use ConnectGelato again. + const expiryDate = 0; + await expect( + dsa.cast( + [connectGelato.address], // targets + [ + await bre.run("abi-encode-withselector", { + abi: require("../artifacts/ConnectGelato.json").abi, + functionname: "submitTask", + inputs: [ + gelatoSelfProvider, + taskRebalanceDSRToCDAIifBetter, + expiryDate, + ], + }), + ], // datas + userAddress, // origin + { + gasLimit: 5000000, + } + ) + ).to.emit(gelatoCore, "LogTaskSubmitted"); + + // Task Receipt: a successfully submitted Task in Gelato + // is wrapped in a TaskReceipt. For testing we instantiate the TaskReceipt + // for our to be submitted Task. + const taskReceiptId = await gelatoCore.currentTaskReceiptId(); + const taskReceipt = new GelatoCoreLib.TaskReceipt({ + id: taskReceiptId, + userProxy: dsa.address, + provider: gelatoSelfProvider, + tasks: [taskRebalanceDSRToCDAIifBetter], + expiryDate, + }); + + // ======= 📣 TASK EXECUTION 📣 ========= + // This stuff is normally automated by the Gelato Network and Dapp Developers + // and their Users don't have to take care of it. However, for local testing + // we simulate the Gelato Execution logic. + + // Let's first check if our Task is executable. Since both MockDSR and MockCDAI + // start with a normalized per second rate of APY_2_PERCENT_IN_SECONDS + // (1000000000627937192491029810 in 10**27 precision) in both of them + expect( + await gelatoCore.canExec(taskReceipt, GAS_LIMIT, GAS_PRICE_CEIL) + ).to.be.equal("ConditionNotOk:ANotGreaterOrEqualToBbyMinspread"); + + // We defined a MIN_SPREAD of 10000000 points in the per second rate + // for our ConditionCompareUintsFromTwoSources. So we now + // set the CDAI.supplyRatePerSecond to be 10000000 higher than MockDSR.dsr + // and expect it to mean that our Task becomes executable. + await mockCDAI.setSupplyRatePerSecond( + (await mockDSR.dsr()).add(MIN_SPREAD) + ); + expect( + await gelatoCore.canExec(taskReceipt, GAS_LIMIT, GAS_PRICE_CEIL) + ).to.be.equal("OK"); + + // To verify whether the execution of DSR=>CDAI has been successful in this Testing + // we look at changes in the CDAI balance of the DSA + const cDAI = await ethers.getContractAt( + IERC20.abi, + bre.network.config.CDAI + ); + const dsaCDAIBefore = await cDAI.balanceOf(dsa.address); + + // For testing we now simulate automatic Task Execution ❗ + await expect(gelatoCore.exec(taskReceipt)).to.emit("LogExecSuccess"); + + // Since the Execution was successful, we now expect our DSA to hold more + // CDAI then before. This concludes our testing. + expect(await cDAI.balanceOf(dsa.address)).to.be.gt(dsaCDAIBefore); }); });