mirror of
https://github.com/Instadapp/Gelato-automations.git
synced 2024-07-29 22:28:07 +00:00
Test ETH-A to ETH-B Debt bridge case
This commit is contained in:
parent
952f79124e
commit
52405cfb8f
|
@ -36,6 +36,7 @@ module.exports = {
|
||||||
InstaList: "0x4c8a1BEb8a87765788946D6B19C6C6355194AbEb",
|
InstaList: "0x4c8a1BEb8a87765788946D6B19C6C6355194AbEb",
|
||||||
InstaConnectors: "0xD6A602C01a023B98Ecfb29Df02FBA380d3B21E0c",
|
InstaConnectors: "0xD6A602C01a023B98Ecfb29Df02FBA380d3B21E0c",
|
||||||
InstaAccount: "0x939Daad09fC4A9B8f8A9352A485DAb2df4F4B3F8",
|
InstaAccount: "0x939Daad09fC4A9B8f8A9352A485DAb2df4F4B3F8",
|
||||||
|
InstaMapping: "0xe81F70Cc7C0D46e12d70efc60607F16bbD617E88",
|
||||||
ConnectAuth: "0xd1aFf9f2aCf800C876c409100D6F39AEa93Fc3D9",
|
ConnectAuth: "0xd1aFf9f2aCf800C876c409100D6F39AEa93Fc3D9",
|
||||||
ConnectBasic: "0x6a31c5982C5Bc5533432913cf06a66b6D3333a95",
|
ConnectBasic: "0x6a31c5982C5Bc5533432913cf06a66b6D3333a95",
|
||||||
ConnectGelato: "0x37A7009d424951dd5D5F155fA588D9a03C455163",
|
ConnectGelato: "0x37A7009d424951dd5D5F155fA588D9a03C455163",
|
||||||
|
@ -165,3 +166,19 @@ task(
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
task("hardhatReset", "Reset back to a fresh forked state during runtime")
|
||||||
|
.addPositionalParam("provider", "Network Provider", undefined, types.json)
|
||||||
|
.setAction(async (taskArgs) => {
|
||||||
|
await taskArgs.provider.request({
|
||||||
|
method: "hardhat_reset",
|
||||||
|
params: [
|
||||||
|
{
|
||||||
|
forking: {
|
||||||
|
jsonRpcUrl: `https://eth-mainnet.alchemyapi.io/v2/${ALCHEMY_ID}`,
|
||||||
|
blockNumber: 11104384,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
96
pre-compiles/InstaMapping.json
Normal file
96
pre-compiles/InstaMapping.json
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
{
|
||||||
|
"contractName": "ConnectAuth",
|
||||||
|
"abi": [
|
||||||
|
{"inputs": [], "stateMutability": "nonpayable", "type": "constructor"},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"internalType": "address[]",
|
||||||
|
"name": "cTokens",
|
||||||
|
"type": "address[]"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "LogAddCTokenMapping",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"internalType": "address[]",
|
||||||
|
"name": "gemJoin",
|
||||||
|
"type": "address[]"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "LogAddGemJoinMapping",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{"internalType": "address[]", "name": "cTkn", "type": "address[]"}
|
||||||
|
],
|
||||||
|
"name": "addCtknMapping",
|
||||||
|
"outputs": [],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{"internalType": "address[]", "name": "gemJoins", "type": "address[]"}
|
||||||
|
],
|
||||||
|
"name": "addGemJoinMapping",
|
||||||
|
"outputs": [],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [{"internalType": "address", "name": "", "type": "address"}],
|
||||||
|
"name": "cTokenMapping",
|
||||||
|
"outputs": [{"internalType": "address", "name": "", "type": "address"}],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "connectors",
|
||||||
|
"outputs": [{"internalType": "address", "name": "", "type": "address"}],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [{"internalType": "bytes32", "name": "", "type": "bytes32"}],
|
||||||
|
"name": "gemJoinMapping",
|
||||||
|
"outputs": [{"internalType": "address", "name": "", "type": "address"}],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "instaIndex",
|
||||||
|
"outputs": [{"internalType": "address", "name": "", "type": "address"}],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "name",
|
||||||
|
"outputs": [{"internalType": "string", "name": "", "type": "string"}],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "version",
|
||||||
|
"outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"bytecode": "0x",
|
||||||
|
"deployedBytecode": "0x",
|
||||||
|
"linkReferences": {},
|
||||||
|
"deployedLinkReferences": {}
|
||||||
|
}
|
|
@ -30,7 +30,7 @@ describe("Full Debt Bridge refinancing loan from Maker to Compound", function ()
|
||||||
let taskReceipt;
|
let taskReceipt;
|
||||||
|
|
||||||
before(async function () {
|
before(async function () {
|
||||||
const result = await helper.setup();
|
const result = await helper.makerToCompoundTestSetup();
|
||||||
|
|
||||||
address = result.address;
|
address = result.address;
|
||||||
contracts = result.contracts;
|
contracts = result.contracts;
|
||||||
|
@ -207,10 +207,10 @@ describe("Full Debt Bridge refinancing loan from Maker to Compound", function ()
|
||||||
|
|
||||||
// 🚧 For Debugging:
|
// 🚧 For Debugging:
|
||||||
// const txResponse2 = await gelatoCore
|
// const txResponse2 = await gelatoCore
|
||||||
// .connect(providerWallet)
|
// .connect(address.executorWallet)
|
||||||
// .exec(taskReceipt, {
|
// .exec(taskReceipt, {
|
||||||
// gasPrice: gelatoGasPrice,
|
// gasPrice: gelatoGasPrice,
|
||||||
// gasLimit: GAS_LIMIT,
|
// gasLimit: constants.GAS_LIMIT,
|
||||||
// });
|
// });
|
||||||
// const {blockHash} = await txResponse2.wait();
|
// const {blockHash} = await txResponse2.wait();
|
||||||
// const logs = await ethers.provider.getLogs({blockHash});
|
// const logs = await ethers.provider.getLogs({blockHash});
|
||||||
|
|
271
test/3_Full-Debt-Bridge-ETHA-ETHB.test.js
Normal file
271
test/3_Full-Debt-Bridge-ETHA-ETHB.test.js
Normal file
|
@ -0,0 +1,271 @@
|
||||||
|
const {expect} = require("chai");
|
||||||
|
const hre = require("hardhat");
|
||||||
|
const {ethers, network} = hre;
|
||||||
|
const GelatoCoreLib = require("@gelatonetwork/core");
|
||||||
|
|
||||||
|
const Helper = require("./helpers/Full-Refinance-External-Provider.helper");
|
||||||
|
const helper = new Helper();
|
||||||
|
|
||||||
|
// 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 address;
|
||||||
|
let constants;
|
||||||
|
let ABI;
|
||||||
|
|
||||||
|
// Payload Params for ConnectGelatoDebtBridgeFromMaker and ConditionMakerVaultUnsafe
|
||||||
|
let vaultAId;
|
||||||
|
|
||||||
|
// For TaskSpec and for Task
|
||||||
|
let spells = [];
|
||||||
|
|
||||||
|
// Cross test var
|
||||||
|
let taskReceipt;
|
||||||
|
|
||||||
|
before(async function () {
|
||||||
|
// Reset back to a fresh forked state during runtime
|
||||||
|
await hre.run("hardhatReset", {provider: network.provider});
|
||||||
|
const result = await helper.makerETHAToMakerETHBSetup();
|
||||||
|
|
||||||
|
address = result.address;
|
||||||
|
contracts = result.contracts;
|
||||||
|
vaultAId = result.vaultAId;
|
||||||
|
spells = result.spells;
|
||||||
|
|
||||||
|
ABI = await helper.getABI();
|
||||||
|
constants = await helper.getConstants();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#1: DSA give Authorization to Gelato to execute action his behalf.", 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],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
address.userAddress
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(await contracts.dsa.isAuth(contracts.gelatoCore.address)).to.be.true;
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#2: User submits Debt refinancing task if market move 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: ABI.PriceOracleResolverABI,
|
||||||
|
functionname: "getMockPrice",
|
||||||
|
inputs: [address.userAddress],
|
||||||
|
}),
|
||||||
|
constants.MIN_COL_RATIO_MAKER
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
// ======= GELATO TASK SETUP ======
|
||||||
|
const refinanceIfCompoundBorrowIsBetter = new GelatoCoreLib.Task({
|
||||||
|
conditions: [conditionMakerVaultUnsafeObj],
|
||||||
|
actions: spells,
|
||||||
|
});
|
||||||
|
|
||||||
|
const gelatoExternalProvider = new GelatoCoreLib.GelatoProvider({
|
||||||
|
addr: address.providerAddress, // 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,
|
||||||
|
refinanceIfCompoundBorrowIsBetter,
|
||||||
|
expiryDate,
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
], // datas
|
||||||
|
address.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: [refinanceIfCompoundBorrowIsBetter],
|
||||||
|
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: Use ETH-A to ETH-B refinancing if the maker vault become unsafe after a market move.", 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(address.executorWallet)
|
||||||
|
.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(address.executorWallet)
|
||||||
|
.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 gasFeesPaidFromCol = ethers.utils
|
||||||
|
.parseUnits(String(1933090 + 19331 * 2), 0)
|
||||||
|
.mul(gelatoGasPrice);
|
||||||
|
const debtOnMakerBefore = await contracts.connectGelatoDebtBridgeFromMaker.getMakerVaultDebt(
|
||||||
|
vaultAId
|
||||||
|
);
|
||||||
|
const pricedCollateral = (
|
||||||
|
await contracts.connectGelatoDebtBridgeFromMaker.getMakerVaultCollateralBalance(
|
||||||
|
vaultAId
|
||||||
|
)
|
||||||
|
).sub(gasFeesPaidFromCol);
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
const providerBalanceBeforeExecution = await address.providerWallet.getBalance();
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
contracts.gelatoCore.connect(address.executorWallet).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(address.executorWallet)
|
||||||
|
// .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.connectGelatoDebtBridgeFromMaker.getMakerVaultDebt(
|
||||||
|
vaultBId
|
||||||
|
);
|
||||||
|
const pricedCollateralonVaultB = await contracts.connectGelatoDebtBridgeFromMaker.getMakerVaultCollateralBalance(
|
||||||
|
vaultBId
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(await address.providerWallet.getBalance()).to.be.gt(
|
||||||
|
providerBalanceBeforeExecution
|
||||||
|
);
|
||||||
|
|
||||||
|
// Estimated amount to borrowed token should be equal to the actual one read on compound contracts
|
||||||
|
expect(debtOnMakerBefore.sub(debtOnMakerVaultB)).to.be.lt(
|
||||||
|
ethers.utils.parseUnits("2", 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Estimated amount of collateral should be equal to the actual one read on compound contracts
|
||||||
|
expect(pricedCollateral).to.be.equal(pricedCollateralonVaultB);
|
||||||
|
|
||||||
|
const debtOnMakerOnVaultAAfter = await contracts.connectGelatoDebtBridgeFromMaker.getMakerVaultDebt(
|
||||||
|
vaultAId
|
||||||
|
);
|
||||||
|
const collateralOnMakerOnVaultAAfter = await contracts.connectGelatoDebtBridgeFromMaker.getMakerVaultCollateralBalance(
|
||||||
|
vaultAId
|
||||||
|
); // in Ether.
|
||||||
|
|
||||||
|
// We should not have borrowed DAI on maker or deposited ether on it.
|
||||||
|
expect(debtOnMakerOnVaultAAfter).to.be.equal(ethers.constants.Zero);
|
||||||
|
expect(collateralOnMakerOnVaultAAfter).to.be.equal(ethers.constants.Zero);
|
||||||
|
|
||||||
|
// DSA contain 1000 DAI
|
||||||
|
expect(
|
||||||
|
(await contracts.daiToken.balanceOf(contracts.dsa.address)).sub(
|
||||||
|
constants.MAKER_INITIAL_DEBT
|
||||||
|
)
|
||||||
|
).to.be.lt(ethers.utils.parseUnits("2", 0));
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
});
|
||||||
|
});
|
|
@ -13,6 +13,7 @@ const ConnectInstaPool = require("../../pre-compiles/ConnectInstaPool.json");
|
||||||
const ConnectAuth = require("../../pre-compiles/ConnectAuth.json");
|
const ConnectAuth = require("../../pre-compiles/ConnectAuth.json");
|
||||||
|
|
||||||
const InstaConnector = require("../../pre-compiles/InstaConnectors.json");
|
const InstaConnector = require("../../pre-compiles/InstaConnectors.json");
|
||||||
|
const InstaMapping = require("../../pre-compiles/InstaMapping.json");
|
||||||
const DssCdpManager = require("../../pre-compiles/DssCdpManager.json");
|
const DssCdpManager = require("../../pre-compiles/DssCdpManager.json");
|
||||||
const GetCdps = require("../../pre-compiles/GetCdps.json");
|
const GetCdps = require("../../pre-compiles/GetCdps.json");
|
||||||
const IERC20 = require("../../pre-compiles/IERC20.json");
|
const IERC20 = require("../../pre-compiles/IERC20.json");
|
||||||
|
@ -81,6 +82,7 @@ class Helper {
|
||||||
let cDaiToken;
|
let cDaiToken;
|
||||||
let cEthToken;
|
let cEthToken;
|
||||||
let instaMaster;
|
let instaMaster;
|
||||||
|
let instaMapping;
|
||||||
let instaConnectors;
|
let instaConnectors;
|
||||||
let compoundResolver;
|
let compoundResolver;
|
||||||
// Contracts to deploy and use for local testing
|
// Contracts to deploy and use for local testing
|
||||||
|
@ -99,6 +101,10 @@ class Helper {
|
||||||
InstaIndex.abi,
|
InstaIndex.abi,
|
||||||
hre.network.config.InstaIndex
|
hre.network.config.InstaIndex
|
||||||
);
|
);
|
||||||
|
instaMapping = await ethers.getContractAt(
|
||||||
|
InstaMapping.abi,
|
||||||
|
hre.network.config.InstaMapping
|
||||||
|
);
|
||||||
instaList = await ethers.getContractAt(
|
instaList = await ethers.getContractAt(
|
||||||
InstaList.abi,
|
InstaList.abi,
|
||||||
hre.network.config.InstaList
|
hre.network.config.InstaList
|
||||||
|
@ -195,6 +201,7 @@ class Helper {
|
||||||
connectCompound: connectCompound,
|
connectCompound: connectCompound,
|
||||||
instaIndex: instaIndex,
|
instaIndex: instaIndex,
|
||||||
instaList: instaList,
|
instaList: instaList,
|
||||||
|
instaMapping: instaMapping,
|
||||||
dssCdpManager: dssCdpManager,
|
dssCdpManager: dssCdpManager,
|
||||||
getCdps: getCdps,
|
getCdps: getCdps,
|
||||||
daiToken: daiToken,
|
daiToken: daiToken,
|
||||||
|
@ -213,44 +220,63 @@ class Helper {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async setup() {
|
async makerToCompoundTestSetup() {
|
||||||
let address = await this.address();
|
let address = await this.address();
|
||||||
let contracts = await this.contracts();
|
let contracts = await this.contracts();
|
||||||
let dsa;
|
|
||||||
let vaultId;
|
let vaultId;
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/////////////////////////////////////////////// Setup ///////////////////////////////////////////
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Gelato Testing environment setup.
|
// Gelato Testing environment setup.
|
||||||
// Step 1 : Add EUR/USD Maker Medianizer in the PriceOracleResolver
|
await this.enableGelatoConnectorsForFromMaker(address, contracts);
|
||||||
// Step 2 : Enable Debt Bridge Connector and Gelato Provider Payment Connector
|
await this.executorDoStaking(address, contracts);
|
||||||
// Step 3 : Executor Staking on Gelato
|
await this.providerDoFunding(address, contracts);
|
||||||
// Step 4 : Provider put some fund on gelato for paying future tasks executions
|
await this.providerChooseExecutor(address, contracts);
|
||||||
// Step 5 : Provider choose a executor
|
await this.providerAddCustomModuleForPayment(address, contracts);
|
||||||
// Step 6 : Provider will add a module
|
await this.userCreateADSA(address, contracts);
|
||||||
// Step 7 : User create a DeFi Smart Account
|
vaultId = await this.userOpenDepositBorrowOnMakerVault(address, contracts);
|
||||||
// Step 8 : User open a Vault, put some ether on it and borrow some dai
|
let spells = await this.providerWhiteListTaskForMakerToCompound(
|
||||||
// Step 9 : Provider should whitelist task
|
address,
|
||||||
|
contracts,
|
||||||
|
vaultId
|
||||||
|
);
|
||||||
|
|
||||||
//#region Step 1 Add EUR/USD Maker Medianizer in the PriceOracleResolver
|
return {
|
||||||
|
address: address,
|
||||||
|
contracts: contracts,
|
||||||
|
vaultId: vaultId,
|
||||||
|
spells: spells,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// PriceOracleResolver is a price feeder aggregator
|
async makerETHAToMakerETHBSetup() {
|
||||||
// You will be able to query price from multiple source through this aggregator
|
let address = await this.address();
|
||||||
// For the demo we add the ETH/USD Medianizer to the aggregator
|
let contracts = await this.contracts();
|
||||||
// MakerDAO price oracle are called Medianizer
|
let vaultAId;
|
||||||
|
|
||||||
// await priceOracleResolver.addOracle(
|
// Gelato Testing environment setup.
|
||||||
// ORACLE_MAKER_ETH_USD,
|
await this.enableGelatoConnectorsForFromMaker(address, contracts);
|
||||||
// ORACLE_MAKER_ETH_USD_ADDR,
|
await this.executorDoStaking(address, contracts);
|
||||||
// PRICE_ORACLE_MAKER_PAYLOAD
|
await this.providerDoFunding(address, contracts);
|
||||||
// );
|
await this.providerChooseExecutor(address, contracts);
|
||||||
|
await this.providerAddCustomModuleForPayment(address, contracts);
|
||||||
|
await this.userCreateADSA(address, contracts);
|
||||||
|
await this.masterAddETHBOnGemJoinMapping(address, contracts);
|
||||||
|
vaultAId = await this.userOpenDepositBorrowOnMakerVault(address, contracts);
|
||||||
|
let spells = await this.providerWhiteListTaskForMakerETHAToMakerETHB(
|
||||||
|
address,
|
||||||
|
contracts,
|
||||||
|
vaultAId
|
||||||
|
);
|
||||||
|
|
||||||
//#endregion
|
return {
|
||||||
|
address: address,
|
||||||
|
contracts: contracts,
|
||||||
|
vaultAId: vaultAId,
|
||||||
|
spells: spells,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
//#region Step 2 Enable Debt Bridge Connector and Gelato Provider Payment Connector
|
async enableGelatoConnectorsForFromMaker(address, contracts) {
|
||||||
|
//#region Enable Debt Bridge Connector and Gelato Provider Payment Connector
|
||||||
|
|
||||||
// Debt Bridge Connector is used during refinancing of debt
|
// Debt Bridge Connector is used during refinancing of debt
|
||||||
// This Connect help the user to split a position in one protocol.
|
// This Connect help the user to split a position in one protocol.
|
||||||
|
@ -296,8 +322,10 @@ class Helper {
|
||||||
).to.be.true;
|
).to.be.true;
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
}
|
||||||
|
|
||||||
//#region Step 3 Executor Staking on Gelato
|
async executorDoStaking(address, contracts) {
|
||||||
|
//#region Executor Staking on Gelato
|
||||||
|
|
||||||
// For task execution provider will ask a executor to watch the
|
// For task execution provider will ask a executor to watch the
|
||||||
// blockchain for possible execution autorization given by
|
// blockchain for possible execution autorization given by
|
||||||
|
@ -315,8 +343,10 @@ class Helper {
|
||||||
).to.be.true;
|
).to.be.true;
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
}
|
||||||
|
|
||||||
//#region Step 4 Provider put some fund on gelato for paying future tasks executions
|
async providerDoFunding(address, contracts) {
|
||||||
|
//#region Provider put some fund on gelato for paying future tasks executions
|
||||||
|
|
||||||
// Provider put some funds in gelato system for paying the
|
// Provider put some funds in gelato system for paying the
|
||||||
// Executor when this one will execute task on behalf of the
|
// Executor when this one will execute task on behalf of the
|
||||||
|
@ -341,8 +371,10 @@ class Helper {
|
||||||
).to.be.equal(TASK_AUTOMATION_FUNDS);
|
).to.be.equal(TASK_AUTOMATION_FUNDS);
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
}
|
||||||
|
|
||||||
//#region Step 5 Provider choose a executor
|
async providerChooseExecutor(address, contracts) {
|
||||||
|
//#region Provider choose a executor
|
||||||
|
|
||||||
// Provider choose a executor who will execute futur task
|
// Provider choose a executor who will execute futur task
|
||||||
// for the provider, it will be compensated by the provider.
|
// for the provider, it will be compensated by the provider.
|
||||||
|
@ -358,8 +390,10 @@ class Helper {
|
||||||
).to.be.equal(address.executorAddress);
|
).to.be.equal(address.executorAddress);
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
}
|
||||||
|
|
||||||
//#region Step 6 Provider will add a module
|
async providerAddCustomModuleForPayment(address, contracts) {
|
||||||
|
//#region Provider will add a module
|
||||||
|
|
||||||
// By adding a module the provider will format future task's
|
// By adding a module the provider will format future task's
|
||||||
// payload by adding some specificity like his address to the
|
// payload by adding some specificity like his address to the
|
||||||
|
@ -381,8 +415,10 @@ class Helper {
|
||||||
).to.be.true;
|
).to.be.true;
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
}
|
||||||
|
|
||||||
//#region Step 7 User create a DeFi Smart Account
|
async userCreateADSA(address, contracts) {
|
||||||
|
//#region User create a DeFi Smart Account
|
||||||
|
|
||||||
// User create a Instadapp DeFi Smart Account
|
// User create a Instadapp DeFi Smart Account
|
||||||
// who give him the possibility to interact
|
// who give him the possibility to interact
|
||||||
|
@ -398,7 +434,7 @@ class Helper {
|
||||||
await expect(await contracts.instaList.accounts()).to.be.equal(dsaID);
|
await expect(await contracts.instaList.accounts()).to.be.equal(dsaID);
|
||||||
|
|
||||||
// Instantiate the DSA
|
// Instantiate the DSA
|
||||||
dsa = await ethers.getContractAt(
|
const dsa = await ethers.getContractAt(
|
||||||
InstaAccount.abi,
|
InstaAccount.abi,
|
||||||
await contracts.instaList.accountAddr(dsaID)
|
await contracts.instaList.accountAddr(dsaID)
|
||||||
);
|
);
|
||||||
|
@ -406,13 +442,15 @@ class Helper {
|
||||||
contracts.dsa = dsa;
|
contracts.dsa = dsa;
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
async userOpenDepositBorrowOnMakerVault(address, contracts) {
|
||||||
//#region Step 8 User open a Vault, put some ether on it and borrow some dai
|
//#region Step 8 User open a Vault, put some ether on it and borrow some dai
|
||||||
|
|
||||||
// User open a maker vault
|
// User open a maker vault
|
||||||
// He deposit 10 Eth on it
|
// He deposit 10 Eth on it
|
||||||
// He borrow a 1000 DAI
|
// He borrow a 1000 DAI
|
||||||
|
const dsa = contracts.dsa;
|
||||||
const openVault = await hre.run("abi-encode-withselector", {
|
const openVault = await hre.run("abi-encode-withselector", {
|
||||||
abi: ConnectMaker.abi,
|
abi: ConnectMaker.abi,
|
||||||
functionname: "open",
|
functionname: "open",
|
||||||
|
@ -429,7 +467,7 @@ class Helper {
|
||||||
contracts.dssCdpManager.address,
|
contracts.dssCdpManager.address,
|
||||||
dsa.address
|
dsa.address
|
||||||
);
|
);
|
||||||
vaultId = String(cdps.ids[0]);
|
let vaultId = String(cdps.ids[0]);
|
||||||
expect(cdps.ids[0].isZero()).to.be.false;
|
expect(cdps.ids[0].isZero()).to.be.false;
|
||||||
|
|
||||||
await dsa.cast(
|
await dsa.cast(
|
||||||
|
@ -465,6 +503,30 @@ class Helper {
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
return vaultId;
|
||||||
|
}
|
||||||
|
|
||||||
|
async masterAddETHBOnGemJoinMapping(address, contracts) {
|
||||||
|
await address.userWallet.sendTransaction({
|
||||||
|
to: hre.network.config.InstaMaster,
|
||||||
|
value: ethers.utils.parseEther("0.1"),
|
||||||
|
});
|
||||||
|
|
||||||
|
await hre.network.provider.request({
|
||||||
|
method: "hardhat_impersonateAccount",
|
||||||
|
params: [await contracts.instaMaster.getAddress()],
|
||||||
|
});
|
||||||
|
|
||||||
|
const ethBGemJoin = "0x08638eF1A205bE6762A8b935F5da9b700Cf7322c";
|
||||||
|
await expect(
|
||||||
|
contracts.instaMapping
|
||||||
|
.connect(contracts.instaMaster)
|
||||||
|
.addGemJoinMapping([ethBGemJoin])
|
||||||
|
).to.emit(contracts.instaMapping, "LogAddGemJoinMapping");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instadapp UI should do the same implementation for submitting debt bridge task
|
||||||
|
async providerWhiteListTaskForMakerToCompound(address, contracts, vaultId) {
|
||||||
//#region Step 9 Provider should whitelist task
|
//#region Step 9 Provider should whitelist task
|
||||||
|
|
||||||
// By WhiteList task, the provider can constrain the type
|
// By WhiteList task, the provider can constrain the type
|
||||||
|
@ -608,13 +670,171 @@ class Helper {
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
return spells;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instadapp UI should do the same implementation for submitting debt bridge task
|
||||||
|
async providerWhiteListTaskForMakerETHAToMakerETHB(
|
||||||
|
address,
|
||||||
|
contracts,
|
||||||
|
vaultId
|
||||||
|
) {
|
||||||
|
//#region Step 9 Provider should whitelist task
|
||||||
|
|
||||||
|
// By WhiteList task, the provider can constrain the type
|
||||||
|
// of task the user can submitting.
|
||||||
|
|
||||||
|
//#region Actions
|
||||||
|
|
||||||
|
let spells = [];
|
||||||
|
|
||||||
|
const debtBridgeCalculationForFullRefinance = new GelatoCoreLib.Action({
|
||||||
|
addr: contracts.connectGelatoDebtBridgeFromMaker.address,
|
||||||
|
data: await hre.run("abi-encode-withselector", {
|
||||||
|
abi: ConnectGelatoDebtBridgeFromMakerABI,
|
||||||
|
functionname: "saveFullRefinanceDataToMemory",
|
||||||
|
inputs: [vaultId, 0, 0],
|
||||||
|
}),
|
||||||
|
operation: GelatoCoreLib.Operation.Delegatecall,
|
||||||
|
});
|
||||||
|
|
||||||
|
spells.push(debtBridgeCalculationForFullRefinance);
|
||||||
|
|
||||||
|
const flashBorrow = new GelatoCoreLib.Action({
|
||||||
|
addr: contracts.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: contracts.connectMaker.address,
|
||||||
|
data: await hre.run("abi-encode-withselector", {
|
||||||
|
abi: ConnectMaker.abi,
|
||||||
|
functionname: "payback",
|
||||||
|
inputs: [vaultId, ethers.constants.MaxUint256, 0, 0],
|
||||||
|
}),
|
||||||
|
operation: GelatoCoreLib.Operation.Delegatecall,
|
||||||
|
});
|
||||||
|
|
||||||
|
spells.push(paybackMaker);
|
||||||
|
|
||||||
|
const withdrawMaker = new GelatoCoreLib.Action({
|
||||||
|
addr: contracts.connectMaker.address,
|
||||||
|
data: await hre.run("abi-encode-withselector", {
|
||||||
|
abi: ConnectMaker.abi,
|
||||||
|
functionname: "withdraw",
|
||||||
|
inputs: [vaultId, ethers.constants.MaxUint256, 0, 0],
|
||||||
|
}),
|
||||||
|
operation: GelatoCoreLib.Operation.Delegatecall,
|
||||||
|
});
|
||||||
|
|
||||||
|
spells.push(withdrawMaker);
|
||||||
|
|
||||||
|
const openVaultB = new GelatoCoreLib.Action({
|
||||||
|
addr: contracts.connectMaker.address,
|
||||||
|
data: await hre.run("abi-encode-withselector", {
|
||||||
|
abi: ConnectMaker.abi,
|
||||||
|
functionname: "open",
|
||||||
|
inputs: ["ETH-B"],
|
||||||
|
}),
|
||||||
|
operation: GelatoCoreLib.Operation.Delegatecall,
|
||||||
|
});
|
||||||
|
|
||||||
|
spells.push(openVaultB);
|
||||||
|
|
||||||
|
const depositMakerOnVaultB = new GelatoCoreLib.Action({
|
||||||
|
addr: contracts.connectMaker.address,
|
||||||
|
data: await hre.run("abi-encode-withselector", {
|
||||||
|
abi: ConnectMaker.abi,
|
||||||
|
functionname: "deposit",
|
||||||
|
inputs: [0, 0, "603", 0],
|
||||||
|
}),
|
||||||
|
operation: GelatoCoreLib.Operation.Delegatecall,
|
||||||
|
});
|
||||||
|
|
||||||
|
spells.push(depositMakerOnVaultB);
|
||||||
|
|
||||||
|
const borrowOnVaultB = new GelatoCoreLib.Action({
|
||||||
|
addr: contracts.connectMaker.address,
|
||||||
|
data: await hre.run("abi-encode-withselector", {
|
||||||
|
abi: ConnectMaker.abi,
|
||||||
|
functionname: "borrow",
|
||||||
|
inputs: [0, 0, "604", 0],
|
||||||
|
}),
|
||||||
|
operation: GelatoCoreLib.Operation.Delegatecall,
|
||||||
|
});
|
||||||
|
|
||||||
|
spells.push(borrowOnVaultB);
|
||||||
|
|
||||||
|
const flashPayBack = new GelatoCoreLib.Action({
|
||||||
|
addr: contracts.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: contracts.connectGelatoProviderPayment.address,
|
||||||
|
data: await hre.run("abi-encode-withselector", {
|
||||||
|
abi: ConnectGelatoProviderPaymentABI,
|
||||||
|
functionname: "payProvider",
|
||||||
|
inputs: [address.providerAddress, ETH, 0, "605", 0],
|
||||||
|
}),
|
||||||
|
operation: GelatoCoreLib.Operation.Delegatecall,
|
||||||
|
});
|
||||||
|
|
||||||
|
spells.push(payProvider);
|
||||||
|
|
||||||
|
const gasPriceCeil = ethers.constants.MaxUint256;
|
||||||
|
|
||||||
|
const connectGelatoDebtBridgeFromMakerTaskSpec = new GelatoCoreLib.TaskSpec(
|
||||||
|
{
|
||||||
|
conditions: [contracts.conditionMakerVaultUnsafe.address],
|
||||||
|
actions: spells,
|
||||||
|
gasPriceCeil,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
contracts.gelatoCore
|
||||||
|
.connect(address.providerWallet)
|
||||||
|
.provideTaskSpecs([connectGelatoDebtBridgeFromMakerTaskSpec])
|
||||||
|
).to.emit(contracts.gelatoCore, "LogTaskSpecProvided");
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await contracts.gelatoCore
|
||||||
|
.connect(address.providerWallet)
|
||||||
|
.isTaskSpecProvided(
|
||||||
|
address.providerAddress,
|
||||||
|
connectGelatoDebtBridgeFromMakerTaskSpec
|
||||||
|
)
|
||||||
|
).to.be.equal("OK");
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await contracts.gelatoCore
|
||||||
|
.connect(address.providerWallet)
|
||||||
|
.taskSpecGasPriceCeil(
|
||||||
|
address.providerAddress,
|
||||||
|
await contracts.gelatoCore
|
||||||
|
.connect(address.providerWallet)
|
||||||
|
.hashTaskSpec(connectGelatoDebtBridgeFromMakerTaskSpec)
|
||||||
|
)
|
||||||
|
).to.be.equal(gasPriceCeil);
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
return {
|
|
||||||
address: address,
|
return spells;
|
||||||
contracts: contracts,
|
|
||||||
vaultId: vaultId,
|
|
||||||
spells: spells,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getABI() {
|
async getABI() {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user