mirror of
https://github.com/Instadapp/Gelato-automations.git
synced 2024-07-29 22:28:07 +00:00
chore: code cleanup
This commit is contained in:
parent
52405cfb8f
commit
d17a2acd97
1
.eslintignore
Normal file
1
.eslintignore
Normal file
|
@ -0,0 +1 @@
|
|||
cache/
|
|
@ -286,8 +286,8 @@ contract ConnectGelatoDebtBridgeFromMaker is MakerResolver {
|
|||
// @param _setId Id for loading from instaMemory.
|
||||
function savePartialRefinanceDataToMemory(
|
||||
uint256 _vaultId,
|
||||
uint256 _wMinColRatioMaker, // should be in ray because maker use ray standard
|
||||
uint256 _wMinColRatioB, // should be in wad because compound use wad standard
|
||||
uint256 _wMinColRatioMaker,
|
||||
uint256 _wMinColRatioB,
|
||||
address _priceOracle,
|
||||
bytes calldata _oraclePayload,
|
||||
uint256, /*_getId,*/
|
||||
|
@ -333,7 +333,7 @@ contract ConnectGelatoDebtBridgeFromMaker is MakerResolver {
|
|||
uint256 gasFeesPaidFromCol = _getGelatoProviderFees();
|
||||
|
||||
_setInstaMemoryUints(
|
||||
_add(wDaiDebtToMove, 1e18),
|
||||
_add(wDaiDebtToMove, 1), // 1 wei DAI buffer: MakerResolver debt inaccuracy
|
||||
_sub(wColToWithdrawFromMaker, gasFeesPaidFromCol), // _wColToDepositInB
|
||||
wDaiDebtToMove,
|
||||
gasFeesPaidFromCol
|
||||
|
@ -490,8 +490,8 @@ contract ConnectGelatoDebtBridgeFromMaker is MakerResolver {
|
|||
// For full refinance we do NOT need to store exact values: uint(-1) functionality
|
||||
// setUint(601, wDaiDebtToMove); // for partialRefinancing: payback maker
|
||||
// setUint(602, wColToWithdrawFromMaker); // for partialRefinancing: withdraw maker
|
||||
setUint(603, _wColToDepositInB); // deposit compound
|
||||
setUint(604, _wDaiDebtToMove); // borrow compound
|
||||
setUint(603, _wColToDepositInB); // deposit B
|
||||
setUint(604, _wDaiDebtToMove); // borrow B
|
||||
setUint(605, _gasFeesPaidFromCol); // pay the provider
|
||||
}
|
||||
|
||||
|
|
|
@ -27,9 +27,7 @@ contract ProviderModuleDSA is GelatoProviderModuleStandard {
|
|||
|
||||
// TO DO: remove `public` after hardhat file import bugfix
|
||||
// https://github.com/nomiclabs/hardhat/issues/916
|
||||
constructor(address _gelatoCore, address _connectGelatoProviderPayment)
|
||||
public
|
||||
{
|
||||
constructor(address _gelatoCore, address _connectGelatoProviderPayment) {
|
||||
gelatoCore = _gelatoCore;
|
||||
connectGelatoProviderPayment = _connectGelatoProviderPayment;
|
||||
}
|
||||
|
|
|
@ -167,16 +167,17 @@ task(
|
|||
}
|
||||
});
|
||||
|
||||
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({
|
||||
task(
|
||||
"hardhatReset",
|
||||
"Reset back to a fresh forked state during runtime"
|
||||
).setAction(async (_, hre) => {
|
||||
await hre.network.provider.request({
|
||||
method: "hardhat_reset",
|
||||
params: [
|
||||
{
|
||||
forking: {
|
||||
jsonRpcUrl: `https://eth-mainnet.alchemyapi.io/v2/${ALCHEMY_ID}`,
|
||||
blockNumber: 11104384,
|
||||
jsonRpcUrl: hre.network.config.forking.url,
|
||||
blockNumber: hre.network.config.forking.blockNumber,
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
|
@ -21,16 +21,16 @@
|
|||
"@nomiclabs/hardhat-waffle": "2.0.0",
|
||||
"chai": "4.2.0",
|
||||
"dotenv": "8.2.0",
|
||||
"eslint": "7.12.0",
|
||||
"eslint": "7.12.1",
|
||||
"eslint-config-prettier": "6.14.0",
|
||||
"ethereum-waffle": "3.1.2",
|
||||
"ethers": "5.0.19",
|
||||
"hardhat": "2.0.1",
|
||||
"hardhat": "2.0.2",
|
||||
"husky": ">=4",
|
||||
"lint-staged": "10.4.2",
|
||||
"lint-staged": "10.5.0",
|
||||
"prettier": "2.1.2",
|
||||
"prettier-plugin-solidity": "1.0.0-alpha.59",
|
||||
"solhint": "3.2.2",
|
||||
"solhint": "3.3.0",
|
||||
"solhint-plugin-prettier": "0.0.5"
|
||||
},
|
||||
"dependencies": {},
|
||||
|
|
|
@ -16,7 +16,7 @@ describe("Full Debt Bridge refinancing loan from Maker to Compound", function ()
|
|||
}
|
||||
|
||||
let contracts;
|
||||
let address;
|
||||
let wallets;
|
||||
let constants;
|
||||
let ABI;
|
||||
|
||||
|
@ -24,7 +24,7 @@ describe("Full Debt Bridge refinancing loan from Maker to Compound", function ()
|
|||
let vaultId;
|
||||
|
||||
// For TaskSpec and for Task
|
||||
let spells = [];
|
||||
let gelatoDebtBridgeSpells = [];
|
||||
|
||||
// Cross test var
|
||||
let taskReceipt;
|
||||
|
@ -32,10 +32,10 @@ describe("Full Debt Bridge refinancing loan from Maker to Compound", function ()
|
|||
before(async function () {
|
||||
const result = await helper.makerToCompoundTestSetup();
|
||||
|
||||
address = result.address;
|
||||
wallets = result.wallets;
|
||||
contracts = result.contracts;
|
||||
vaultId = result.vaultId;
|
||||
spells = result.spells;
|
||||
gelatoDebtBridgeSpells = result.spells;
|
||||
|
||||
ABI = await helper.getABI();
|
||||
constants = await helper.getConstants();
|
||||
|
@ -58,7 +58,7 @@ describe("Full Debt Bridge refinancing loan from Maker to Compound", function ()
|
|||
inputs: [contracts.gelatoCore.address],
|
||||
}),
|
||||
],
|
||||
address.userAddress
|
||||
wallets.userAddress
|
||||
);
|
||||
|
||||
expect(await contracts.dsa.isAuth(contracts.gelatoCore.address)).to.be.true;
|
||||
|
@ -84,20 +84,20 @@ describe("Full Debt Bridge refinancing loan from Maker to Compound", function ()
|
|||
await hre.run("abi-encode-withselector", {
|
||||
abi: ABI.PriceOracleResolverABI,
|
||||
functionname: "getMockPrice",
|
||||
inputs: [address.userAddress],
|
||||
inputs: [wallets.userAddress],
|
||||
}),
|
||||
constants.MIN_COL_RATIO_MAKER
|
||||
),
|
||||
});
|
||||
|
||||
// ======= GELATO TASK SETUP ======
|
||||
const refinanceIfCompoundBorrowIsBetter = new GelatoCoreLib.Task({
|
||||
const refinanceIfVaultUnsafe = new GelatoCoreLib.Task({
|
||||
conditions: [conditionMakerVaultUnsafeObj],
|
||||
actions: spells,
|
||||
actions: gelatoDebtBridgeSpells,
|
||||
});
|
||||
|
||||
const gelatoExternalProvider = new GelatoCoreLib.GelatoProvider({
|
||||
addr: address.providerAddress, // Gelato Provider Address
|
||||
addr: wallets.providerAddress, // Gelato Provider Address
|
||||
module: contracts.dsaProviderModule.address, // Gelato DSA module
|
||||
});
|
||||
|
||||
|
@ -112,12 +112,12 @@ describe("Full Debt Bridge refinancing loan from Maker to Compound", function ()
|
|||
functionname: "submitTask",
|
||||
inputs: [
|
||||
gelatoExternalProvider,
|
||||
refinanceIfCompoundBorrowIsBetter,
|
||||
refinanceIfVaultUnsafe,
|
||||
expiryDate,
|
||||
],
|
||||
}),
|
||||
], // datas
|
||||
address.userAddress, // origin
|
||||
wallets.userAddress, // origin
|
||||
{
|
||||
gasLimit: 5000000,
|
||||
}
|
||||
|
@ -128,7 +128,7 @@ describe("Full Debt Bridge refinancing loan from Maker to Compound", function ()
|
|||
id: await contracts.gelatoCore.currentTaskReceiptId(),
|
||||
userProxy: contracts.dsa.address,
|
||||
provider: gelatoExternalProvider,
|
||||
tasks: [refinanceIfCompoundBorrowIsBetter],
|
||||
tasks: [refinanceIfVaultUnsafe],
|
||||
expiryDate,
|
||||
});
|
||||
|
||||
|
@ -158,7 +158,7 @@ describe("Full Debt Bridge refinancing loan from Maker to Compound", function ()
|
|||
|
||||
expect(
|
||||
await contracts.gelatoCore
|
||||
.connect(address.executorWallet)
|
||||
.connect(wallets.executorWallet)
|
||||
.canExec(taskReceipt, constants.GAS_LIMIT, gelatoGasPrice)
|
||||
).to.be.equal("ConditionNotOk:MakerVaultNotUnsafe");
|
||||
|
||||
|
@ -169,7 +169,7 @@ describe("Full Debt Bridge refinancing loan from Maker to Compound", function ()
|
|||
|
||||
expect(
|
||||
await contracts.gelatoCore
|
||||
.connect(address.executorWallet)
|
||||
.connect(wallets.executorWallet)
|
||||
.canExec(taskReceipt, constants.GAS_LIMIT, gelatoGasPrice)
|
||||
).to.be.equal("OK");
|
||||
|
||||
|
@ -196,10 +196,10 @@ describe("Full Debt Bridge refinancing loan from Maker to Compound", function ()
|
|||
).sub(gasFeesPaidFromCol);
|
||||
|
||||
//#endregion
|
||||
const providerBalanceBeforeExecution = await address.providerWallet.getBalance();
|
||||
const providerBalanceBeforeExecution = await wallets.providerWallet.getBalance();
|
||||
|
||||
await expect(
|
||||
contracts.gelatoCore.connect(address.executorWallet).exec(taskReceipt, {
|
||||
contracts.gelatoCore.connect(wallets.executorWallet).exec(taskReceipt, {
|
||||
gasPrice: gelatoGasPrice, // Exectutor must use gelatoGasPrice (Chainlink fast gwei)
|
||||
gasLimit: constants.GAS_LIMIT,
|
||||
})
|
||||
|
@ -220,7 +220,7 @@ describe("Full Debt Bridge refinancing loan from Maker to Compound", function ()
|
|||
// }
|
||||
// await GelatoCoreLib.sleep(10000);
|
||||
|
||||
expect(await address.providerWallet.getBalance()).to.be.gt(
|
||||
expect(await wallets.providerWallet.getBalance()).to.be.gt(
|
||||
providerBalanceBeforeExecution
|
||||
);
|
||||
|
||||
|
@ -266,7 +266,7 @@ describe("Full Debt Bridge refinancing loan from Maker to Compound", function ()
|
|||
(await contracts.daiToken.balanceOf(contracts.dsa.address)).sub(
|
||||
constants.MAKER_INITIAL_DEBT
|
||||
)
|
||||
).to.be.lt(ethers.utils.parseUnits("2", 0));
|
||||
).to.be.lte(ethers.utils.parseUnits("1", 0));
|
||||
|
||||
//#endregion
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
const {expect} = require("chai");
|
||||
const hre = require("hardhat");
|
||||
const {ethers, network} = hre;
|
||||
const {ethers} = hre;
|
||||
const GelatoCoreLib = require("@gelatonetwork/core");
|
||||
|
||||
const Helper = require("./helpers/Full-Refinance-External-Provider.helper");
|
||||
|
@ -16,7 +16,7 @@ describe("Full Debt Bridge refinancing loan from ETH-A to ETH-B", function () {
|
|||
}
|
||||
|
||||
let contracts;
|
||||
let address;
|
||||
let wallets;
|
||||
let constants;
|
||||
let ABI;
|
||||
|
||||
|
@ -24,26 +24,26 @@ describe("Full Debt Bridge refinancing loan from ETH-A to ETH-B", function () {
|
|||
let vaultAId;
|
||||
|
||||
// For TaskSpec and for Task
|
||||
let spells = [];
|
||||
let gelatoDebtBridgeSpells = [];
|
||||
|
||||
// Cross test var
|
||||
let taskReceipt;
|
||||
|
||||
before(async function () {
|
||||
// Reset back to a fresh forked state during runtime
|
||||
await hre.run("hardhatReset", {provider: network.provider});
|
||||
await hre.run("hardhatReset");
|
||||
const result = await helper.makerETHAToMakerETHBSetup();
|
||||
|
||||
address = result.address;
|
||||
wallets = result.wallets;
|
||||
contracts = result.contracts;
|
||||
vaultAId = result.vaultAId;
|
||||
spells = result.spells;
|
||||
gelatoDebtBridgeSpells = result.spells;
|
||||
|
||||
ABI = await helper.getABI();
|
||||
constants = await helper.getConstants();
|
||||
});
|
||||
|
||||
it("#1: DSA give Authorization to Gelato to execute action his behalf.", async function () {
|
||||
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
|
||||
|
@ -60,7 +60,7 @@ describe("Full Debt Bridge refinancing loan from ETH-A to ETH-B", function () {
|
|||
inputs: [contracts.gelatoCore.address],
|
||||
}),
|
||||
],
|
||||
address.userAddress
|
||||
wallets.userAddress
|
||||
);
|
||||
|
||||
expect(await contracts.dsa.isAuth(contracts.gelatoCore.address)).to.be.true;
|
||||
|
@ -68,7 +68,7 @@ describe("Full Debt Bridge refinancing loan from ETH-A to ETH-B", function () {
|
|||
//#endregion
|
||||
});
|
||||
|
||||
it("#2: User submits Debt refinancing task if market move to Gelato via DSA", async function () {
|
||||
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.
|
||||
|
@ -86,20 +86,20 @@ describe("Full Debt Bridge refinancing loan from ETH-A to ETH-B", function () {
|
|||
await hre.run("abi-encode-withselector", {
|
||||
abi: ABI.PriceOracleResolverABI,
|
||||
functionname: "getMockPrice",
|
||||
inputs: [address.userAddress],
|
||||
inputs: [wallets.userAddress],
|
||||
}),
|
||||
constants.MIN_COL_RATIO_MAKER
|
||||
),
|
||||
});
|
||||
|
||||
// ======= GELATO TASK SETUP ======
|
||||
const refinanceIfCompoundBorrowIsBetter = new GelatoCoreLib.Task({
|
||||
const refinanceFromEthAToBIfVaultUnsafe = new GelatoCoreLib.Task({
|
||||
conditions: [conditionMakerVaultUnsafeObj],
|
||||
actions: spells,
|
||||
actions: gelatoDebtBridgeSpells,
|
||||
});
|
||||
|
||||
const gelatoExternalProvider = new GelatoCoreLib.GelatoProvider({
|
||||
addr: address.providerAddress, // Gelato Provider Address
|
||||
addr: wallets.providerAddress, // Gelato Provider Address
|
||||
module: contracts.dsaProviderModule.address, // Gelato DSA module
|
||||
});
|
||||
|
||||
|
@ -114,12 +114,12 @@ describe("Full Debt Bridge refinancing loan from ETH-A to ETH-B", function () {
|
|||
functionname: "submitTask",
|
||||
inputs: [
|
||||
gelatoExternalProvider,
|
||||
refinanceIfCompoundBorrowIsBetter,
|
||||
refinanceFromEthAToBIfVaultUnsafe,
|
||||
expiryDate,
|
||||
],
|
||||
}),
|
||||
], // datas
|
||||
address.userAddress, // origin
|
||||
wallets.userAddress, // origin
|
||||
{
|
||||
gasLimit: 5000000,
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ describe("Full Debt Bridge refinancing loan from ETH-A to ETH-B", function () {
|
|||
id: await contracts.gelatoCore.currentTaskReceiptId(),
|
||||
userProxy: contracts.dsa.address,
|
||||
provider: gelatoExternalProvider,
|
||||
tasks: [refinanceIfCompoundBorrowIsBetter],
|
||||
tasks: [refinanceFromEthAToBIfVaultUnsafe],
|
||||
expiryDate,
|
||||
});
|
||||
|
||||
|
@ -141,7 +141,7 @@ describe("Full Debt Bridge refinancing loan from ETH-A to ETH-B", function () {
|
|||
// 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 () {
|
||||
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
|
||||
|
@ -160,7 +160,7 @@ describe("Full Debt Bridge refinancing loan from ETH-A to ETH-B", function () {
|
|||
|
||||
expect(
|
||||
await contracts.gelatoCore
|
||||
.connect(address.executorWallet)
|
||||
.connect(wallets.executorWallet)
|
||||
.canExec(taskReceipt, constants.GAS_LIMIT, gelatoGasPrice)
|
||||
).to.be.equal("ConditionNotOk:MakerVaultNotUnsafe");
|
||||
|
||||
|
@ -171,7 +171,7 @@ describe("Full Debt Bridge refinancing loan from ETH-A to ETH-B", function () {
|
|||
|
||||
expect(
|
||||
await contracts.gelatoCore
|
||||
.connect(address.executorWallet)
|
||||
.connect(wallets.executorWallet)
|
||||
.canExec(taskReceipt, constants.GAS_LIMIT, gelatoGasPrice)
|
||||
).to.be.equal("OK");
|
||||
|
||||
|
@ -198,10 +198,10 @@ describe("Full Debt Bridge refinancing loan from ETH-A to ETH-B", function () {
|
|||
).sub(gasFeesPaidFromCol);
|
||||
|
||||
//#endregion
|
||||
const providerBalanceBeforeExecution = await address.providerWallet.getBalance();
|
||||
const providerBalanceBeforeExecution = await wallets.providerWallet.getBalance();
|
||||
|
||||
await expect(
|
||||
contracts.gelatoCore.connect(address.executorWallet).exec(taskReceipt, {
|
||||
contracts.gelatoCore.connect(wallets.executorWallet).exec(taskReceipt, {
|
||||
gasPrice: gelatoGasPrice, // Exectutor must use gelatoGasPrice (Chainlink fast gwei)
|
||||
gasLimit: constants.GAS_LIMIT,
|
||||
})
|
||||
|
@ -232,21 +232,21 @@ describe("Full Debt Bridge refinancing loan from ETH-A to ETH-B", function () {
|
|||
const debtOnMakerVaultB = await contracts.connectGelatoDebtBridgeFromMaker.getMakerVaultDebt(
|
||||
vaultBId
|
||||
);
|
||||
const pricedCollateralonVaultB = await contracts.connectGelatoDebtBridgeFromMaker.getMakerVaultCollateralBalance(
|
||||
const pricedCollateralOnVaultB = await contracts.connectGelatoDebtBridgeFromMaker.getMakerVaultCollateralBalance(
|
||||
vaultBId
|
||||
);
|
||||
|
||||
expect(await address.providerWallet.getBalance()).to.be.gt(
|
||||
expect(await wallets.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)
|
||||
expect(debtOnMakerBefore.sub(debtOnMakerVaultB)).to.be.lte(
|
||||
ethers.utils.parseUnits("1", 0)
|
||||
);
|
||||
|
||||
// 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.connectGelatoDebtBridgeFromMaker.getMakerVaultDebt(
|
||||
vaultAId
|
||||
|
@ -259,12 +259,12 @@ describe("Full Debt Bridge refinancing loan from ETH-A to ETH-B", function () {
|
|||
expect(debtOnMakerOnVaultAAfter).to.be.equal(ethers.constants.Zero);
|
||||
expect(collateralOnMakerOnVaultAAfter).to.be.equal(ethers.constants.Zero);
|
||||
|
||||
// DSA contain 1000 DAI
|
||||
// DSA has maximum 2 wei DAI in it due to maths inaccuracies
|
||||
expect(
|
||||
(await contracts.daiToken.balanceOf(contracts.dsa.address)).sub(
|
||||
constants.MAKER_INITIAL_DEBT
|
||||
)
|
||||
).to.be.lt(ethers.utils.parseUnits("2", 0));
|
||||
).to.be.lte(ethers.utils.parseUnits("1", 0));
|
||||
|
||||
//#endregion
|
||||
});
|
||||
|
|
|
@ -39,7 +39,7 @@ const MAKER_INITIAL_DEBT = ethers.utils.parseUnits("1000", 18);
|
|||
// #endregion
|
||||
|
||||
class Helper {
|
||||
async address() {
|
||||
async getWallets() {
|
||||
let userWallet;
|
||||
let userAddress;
|
||||
let providerWallet;
|
||||
|
@ -52,7 +52,7 @@ class Helper {
|
|||
providerAddress = await providerWallet.getAddress();
|
||||
executorAddress = await executorWallet.getAddress();
|
||||
|
||||
// Hardhat default accounts prefilled with 100 ETH
|
||||
// Hardhat default wallets prefilled with 100 ETH
|
||||
expect(await userWallet.getBalance()).to.be.gt(
|
||||
ethers.utils.parseEther("10")
|
||||
);
|
||||
|
@ -67,7 +67,7 @@ class Helper {
|
|||
};
|
||||
}
|
||||
|
||||
async contracts() {
|
||||
async getContracts() {
|
||||
// Deployed instances
|
||||
let connectGelato;
|
||||
let connectMaker;
|
||||
|
@ -221,61 +221,61 @@ class Helper {
|
|||
}
|
||||
|
||||
async makerToCompoundTestSetup() {
|
||||
let address = await this.address();
|
||||
let contracts = await this.contracts();
|
||||
const wallets = await this.getWallets();
|
||||
const contracts = await this.getContracts();
|
||||
let vaultId;
|
||||
|
||||
// Gelato Testing environment setup.
|
||||
await this.enableGelatoConnectorsForFromMaker(address, contracts);
|
||||
await this.executorDoStaking(address, contracts);
|
||||
await this.providerDoFunding(address, contracts);
|
||||
await this.providerChooseExecutor(address, contracts);
|
||||
await this.providerAddCustomModuleForPayment(address, contracts);
|
||||
await this.userCreateADSA(address, contracts);
|
||||
vaultId = await this.userOpenDepositBorrowOnMakerVault(address, contracts);
|
||||
let spells = await this.providerWhiteListTaskForMakerToCompound(
|
||||
address,
|
||||
await this.enableGelatoConnectorsForFromMaker(wallets, contracts);
|
||||
await this.executorDoStaking(wallets, contracts);
|
||||
await this.providerDoFunding(wallets, contracts);
|
||||
await this.providerChooseExecutor(wallets, contracts);
|
||||
await this.providerAddCustomModuleForPayment(wallets, contracts);
|
||||
await this.userCreateADSA(wallets, contracts);
|
||||
vaultId = await this.userOpenDepositBorrowOnMakerVault(wallets, contracts);
|
||||
const spells = await this.providerWhiteListTaskForMakerToCompound(
|
||||
wallets,
|
||||
contracts,
|
||||
vaultId
|
||||
);
|
||||
|
||||
return {
|
||||
address: address,
|
||||
contracts: contracts,
|
||||
vaultId: vaultId,
|
||||
spells: spells,
|
||||
wallets,
|
||||
contracts,
|
||||
vaultId,
|
||||
spells,
|
||||
};
|
||||
}
|
||||
|
||||
async makerETHAToMakerETHBSetup() {
|
||||
let address = await this.address();
|
||||
let contracts = await this.contracts();
|
||||
const wallets = await this.getWallets();
|
||||
const contracts = await this.getContracts();
|
||||
let vaultAId;
|
||||
|
||||
// Gelato Testing environment setup.
|
||||
await this.enableGelatoConnectorsForFromMaker(address, contracts);
|
||||
await this.executorDoStaking(address, contracts);
|
||||
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,
|
||||
await this.enableGelatoConnectorsForFromMaker(wallets, contracts);
|
||||
await this.executorDoStaking(wallets, contracts);
|
||||
await this.providerDoFunding(wallets, contracts);
|
||||
await this.providerChooseExecutor(wallets, contracts);
|
||||
await this.providerAddCustomModuleForPayment(wallets, contracts);
|
||||
await this.userCreateADSA(wallets, contracts);
|
||||
await this.masterAddETHBOnGemJoinMapping(wallets, contracts);
|
||||
vaultAId = await this.userOpenDepositBorrowOnMakerVault(wallets, contracts);
|
||||
const spells = await this.providerWhiteListTaskForMakerETHAToMakerETHB(
|
||||
wallets,
|
||||
contracts,
|
||||
vaultAId
|
||||
);
|
||||
|
||||
return {
|
||||
address: address,
|
||||
contracts: contracts,
|
||||
vaultAId: vaultAId,
|
||||
spells: spells,
|
||||
wallets,
|
||||
contracts,
|
||||
vaultAId,
|
||||
spells,
|
||||
};
|
||||
}
|
||||
|
||||
async enableGelatoConnectorsForFromMaker(address, contracts) {
|
||||
async enableGelatoConnectorsForFromMaker(wallets, contracts) {
|
||||
//#region Enable Debt Bridge Connector and Gelato Provider Payment Connector
|
||||
|
||||
// Debt Bridge Connector is used during refinancing of debt
|
||||
|
@ -287,7 +287,7 @@ class Helper {
|
|||
// transaction (user will pay during the execution of the task) task will
|
||||
// be executed. Improvind user experience.
|
||||
|
||||
await address.userWallet.sendTransaction({
|
||||
await wallets.userWallet.sendTransaction({
|
||||
to: hre.network.config.InstaMaster,
|
||||
value: ethers.utils.parseEther("0.1"),
|
||||
});
|
||||
|
@ -324,7 +324,7 @@ class Helper {
|
|||
//#endregion
|
||||
}
|
||||
|
||||
async executorDoStaking(address, contracts) {
|
||||
async executorDoStaking(wallets, contracts) {
|
||||
//#region Executor Staking on Gelato
|
||||
|
||||
// For task execution provider will ask a executor to watch the
|
||||
|
@ -334,18 +334,18 @@ class Helper {
|
|||
// For safety measure Gelato ask the executor to stake a minimum
|
||||
// amount.
|
||||
|
||||
await contracts.gelatoCore.connect(address.executorWallet).stakeExecutor({
|
||||
await contracts.gelatoCore.connect(wallets.executorWallet).stakeExecutor({
|
||||
value: await contracts.gelatoCore.minExecutorStake(),
|
||||
});
|
||||
|
||||
expect(
|
||||
await contracts.gelatoCore.isExecutorMinStaked(address.executorAddress)
|
||||
await contracts.gelatoCore.isExecutorMinStaked(wallets.executorAddress)
|
||||
).to.be.true;
|
||||
|
||||
//#endregion
|
||||
}
|
||||
|
||||
async providerDoFunding(address, contracts) {
|
||||
async providerDoFunding(wallets, contracts) {
|
||||
//#region Provider put some fund on gelato for paying future tasks executions
|
||||
|
||||
// Provider put some funds in gelato system for paying the
|
||||
|
@ -360,20 +360,20 @@ class Helper {
|
|||
|
||||
await expect(
|
||||
contracts.gelatoCore
|
||||
.connect(address.providerWallet)
|
||||
.provideFunds(address.providerAddress, {
|
||||
.connect(wallets.providerWallet)
|
||||
.provideFunds(wallets.providerAddress, {
|
||||
value: TASK_AUTOMATION_FUNDS,
|
||||
})
|
||||
).to.emit(contracts.gelatoCore, "LogFundsProvided");
|
||||
|
||||
expect(
|
||||
await contracts.gelatoCore.providerFunds(address.providerAddress)
|
||||
await contracts.gelatoCore.providerFunds(wallets.providerAddress)
|
||||
).to.be.equal(TASK_AUTOMATION_FUNDS);
|
||||
|
||||
//#endregion
|
||||
}
|
||||
|
||||
async providerChooseExecutor(address, contracts) {
|
||||
async providerChooseExecutor(wallets, contracts) {
|
||||
//#region Provider choose a executor
|
||||
|
||||
// Provider choose a executor who will execute futur task
|
||||
|
@ -381,18 +381,18 @@ class Helper {
|
|||
|
||||
await expect(
|
||||
contracts.gelatoCore
|
||||
.connect(address.providerWallet)
|
||||
.providerAssignsExecutor(address.executorAddress)
|
||||
.connect(wallets.providerWallet)
|
||||
.providerAssignsExecutor(wallets.executorAddress)
|
||||
).to.emit(contracts.gelatoCore, "LogProviderAssignedExecutor");
|
||||
|
||||
expect(
|
||||
await contracts.gelatoCore.executorByProvider(address.providerAddress)
|
||||
).to.be.equal(address.executorAddress);
|
||||
await contracts.gelatoCore.executorByProvider(wallets.providerAddress)
|
||||
).to.be.equal(wallets.executorAddress);
|
||||
|
||||
//#endregion
|
||||
}
|
||||
|
||||
async providerAddCustomModuleForPayment(address, contracts) {
|
||||
async providerAddCustomModuleForPayment(wallets, contracts) {
|
||||
//#region Provider will add a module
|
||||
|
||||
// By adding a module the provider will format future task's
|
||||
|
@ -401,15 +401,15 @@ class Helper {
|
|||
|
||||
await expect(
|
||||
contracts.gelatoCore
|
||||
.connect(address.providerWallet)
|
||||
.connect(wallets.providerWallet)
|
||||
.addProviderModules([contracts.dsaProviderModule.address])
|
||||
).to.emit(contracts.gelatoCore, "LogProviderModuleAdded");
|
||||
|
||||
expect(
|
||||
await contracts.gelatoCore
|
||||
.connect(address.providerWallet)
|
||||
.connect(wallets.providerWallet)
|
||||
.isModuleProvided(
|
||||
address.providerAddress,
|
||||
wallets.providerAddress,
|
||||
contracts.dsaProviderModule.address
|
||||
)
|
||||
).to.be.true;
|
||||
|
@ -417,7 +417,7 @@ class Helper {
|
|||
//#endregion
|
||||
}
|
||||
|
||||
async userCreateADSA(address, contracts) {
|
||||
async userCreateADSA(wallets, contracts) {
|
||||
//#region User create a DeFi Smart Account
|
||||
|
||||
// User create a Instadapp DeFi Smart Account
|
||||
|
@ -428,7 +428,7 @@ class Helper {
|
|||
const dsaAccountCount = await contracts.instaList.accounts();
|
||||
|
||||
await expect(
|
||||
contracts.instaIndex.build(address.userAddress, 1, address.userAddress)
|
||||
contracts.instaIndex.build(wallets.userAddress, 1, wallets.userAddress)
|
||||
).to.emit(contracts.instaIndex, "LogAccountCreated");
|
||||
const dsaID = dsaAccountCount.add(1);
|
||||
await expect(await contracts.instaList.accounts()).to.be.equal(dsaID);
|
||||
|
@ -444,7 +444,7 @@ class Helper {
|
|||
//#endregion
|
||||
}
|
||||
|
||||
async userOpenDepositBorrowOnMakerVault(address, contracts) {
|
||||
async userOpenDepositBorrowOnMakerVault(wallets, contracts) {
|
||||
//#region Step 8 User open a Vault, put some ether on it and borrow some dai
|
||||
|
||||
// User open a maker vault
|
||||
|
@ -460,7 +460,7 @@ class Helper {
|
|||
await dsa.cast(
|
||||
[hre.network.config.ConnectMaker],
|
||||
[openVault],
|
||||
address.userAddress
|
||||
wallets.userAddress
|
||||
);
|
||||
|
||||
const cdps = await contracts.getCdps.getCdpsAsc(
|
||||
|
@ -479,7 +479,7 @@ class Helper {
|
|||
inputs: [vaultId, MAKER_INITIAL_ETH, 0, 0],
|
||||
}),
|
||||
],
|
||||
address.userAddress,
|
||||
wallets.userAddress,
|
||||
{
|
||||
value: MAKER_INITIAL_ETH,
|
||||
}
|
||||
|
@ -494,7 +494,7 @@ class Helper {
|
|||
inputs: [vaultId, MAKER_INITIAL_DEBT, 0, 0],
|
||||
}),
|
||||
],
|
||||
address.userAddress
|
||||
wallets.userAddress
|
||||
);
|
||||
|
||||
expect(await contracts.daiToken.balanceOf(dsa.address)).to.be.equal(
|
||||
|
@ -506,8 +506,8 @@ class Helper {
|
|||
return vaultId;
|
||||
}
|
||||
|
||||
async masterAddETHBOnGemJoinMapping(address, contracts) {
|
||||
await address.userWallet.sendTransaction({
|
||||
async masterAddETHBOnGemJoinMapping(wallets, contracts) {
|
||||
await wallets.userWallet.sendTransaction({
|
||||
to: hre.network.config.InstaMaster,
|
||||
value: ethers.utils.parseEther("0.1"),
|
||||
});
|
||||
|
@ -526,7 +526,7 @@ class Helper {
|
|||
}
|
||||
|
||||
// Instadapp UI should do the same implementation for submitting debt bridge task
|
||||
async providerWhiteListTaskForMakerToCompound(address, contracts, vaultId) {
|
||||
async providerWhiteListTaskForMakerToCompound(wallets, contracts, vaultId) {
|
||||
//#region Step 9 Provider should whitelist task
|
||||
|
||||
// By WhiteList task, the provider can constrain the type
|
||||
|
@ -625,7 +625,7 @@ class Helper {
|
|||
data: await hre.run("abi-encode-withselector", {
|
||||
abi: ConnectGelatoProviderPaymentABI,
|
||||
functionname: "payProvider",
|
||||
inputs: [address.providerAddress, ETH, 0, "605", 0],
|
||||
inputs: [wallets.providerAddress, ETH, 0, "605", 0],
|
||||
}),
|
||||
operation: GelatoCoreLib.Operation.Delegatecall,
|
||||
});
|
||||
|
@ -644,26 +644,26 @@ class Helper {
|
|||
|
||||
await expect(
|
||||
contracts.gelatoCore
|
||||
.connect(address.providerWallet)
|
||||
.connect(wallets.providerWallet)
|
||||
.provideTaskSpecs([connectGelatoDebtBridgeFromMakerTaskSpec])
|
||||
).to.emit(contracts.gelatoCore, "LogTaskSpecProvided");
|
||||
|
||||
expect(
|
||||
await contracts.gelatoCore
|
||||
.connect(address.providerWallet)
|
||||
.connect(wallets.providerWallet)
|
||||
.isTaskSpecProvided(
|
||||
address.providerAddress,
|
||||
wallets.providerAddress,
|
||||
connectGelatoDebtBridgeFromMakerTaskSpec
|
||||
)
|
||||
).to.be.equal("OK");
|
||||
|
||||
expect(
|
||||
await contracts.gelatoCore
|
||||
.connect(address.providerWallet)
|
||||
.connect(wallets.providerWallet)
|
||||
.taskSpecGasPriceCeil(
|
||||
address.providerAddress,
|
||||
wallets.providerAddress,
|
||||
await contracts.gelatoCore
|
||||
.connect(address.providerWallet)
|
||||
.connect(wallets.providerWallet)
|
||||
.hashTaskSpec(connectGelatoDebtBridgeFromMakerTaskSpec)
|
||||
)
|
||||
).to.be.equal(gasPriceCeil);
|
||||
|
@ -675,7 +675,7 @@ class Helper {
|
|||
|
||||
// Instadapp UI should do the same implementation for submitting debt bridge task
|
||||
async providerWhiteListTaskForMakerETHAToMakerETHB(
|
||||
address,
|
||||
wallets,
|
||||
contracts,
|
||||
vaultId
|
||||
) {
|
||||
|
@ -686,7 +686,7 @@ class Helper {
|
|||
|
||||
//#region Actions
|
||||
|
||||
let spells = [];
|
||||
const spells = [];
|
||||
|
||||
const debtBridgeCalculationForFullRefinance = new GelatoCoreLib.Action({
|
||||
addr: contracts.connectGelatoDebtBridgeFromMaker.address,
|
||||
|
@ -789,7 +789,7 @@ class Helper {
|
|||
data: await hre.run("abi-encode-withselector", {
|
||||
abi: ConnectGelatoProviderPaymentABI,
|
||||
functionname: "payProvider",
|
||||
inputs: [address.providerAddress, ETH, 0, "605", 0],
|
||||
inputs: [wallets.providerAddress, ETH, 0, "605", 0],
|
||||
}),
|
||||
operation: GelatoCoreLib.Operation.Delegatecall,
|
||||
});
|
||||
|
@ -808,26 +808,26 @@ class Helper {
|
|||
|
||||
await expect(
|
||||
contracts.gelatoCore
|
||||
.connect(address.providerWallet)
|
||||
.connect(wallets.providerWallet)
|
||||
.provideTaskSpecs([connectGelatoDebtBridgeFromMakerTaskSpec])
|
||||
).to.emit(contracts.gelatoCore, "LogTaskSpecProvided");
|
||||
|
||||
expect(
|
||||
await contracts.gelatoCore
|
||||
.connect(address.providerWallet)
|
||||
.connect(wallets.providerWallet)
|
||||
.isTaskSpecProvided(
|
||||
address.providerAddress,
|
||||
wallets.providerAddress,
|
||||
connectGelatoDebtBridgeFromMakerTaskSpec
|
||||
)
|
||||
).to.be.equal("OK");
|
||||
|
||||
expect(
|
||||
await contracts.gelatoCore
|
||||
.connect(address.providerWallet)
|
||||
.connect(wallets.providerWallet)
|
||||
.taskSpecGasPriceCeil(
|
||||
address.providerAddress,
|
||||
wallets.providerAddress,
|
||||
await contracts.gelatoCore
|
||||
.connect(address.providerWallet)
|
||||
.connect(wallets.providerWallet)
|
||||
.hashTaskSpec(connectGelatoDebtBridgeFromMakerTaskSpec)
|
||||
)
|
||||
).to.be.equal(gasPriceCeil);
|
||||
|
|
|
@ -716,7 +716,7 @@ describe("Debt Bridge with External Provider", function () {
|
|||
});
|
||||
|
||||
// ======= GELATO TASK SETUP ======
|
||||
const refinanceIfCompoundBorrowIsBetter = new GelatoCoreLib.Task({
|
||||
const refinanceIfVaultUnsafe = new GelatoCoreLib.Task({
|
||||
conditions: [conditionMakerVaultUnsafeObj],
|
||||
actions: spells,
|
||||
});
|
||||
|
@ -737,7 +737,7 @@ describe("Debt Bridge with External Provider", function () {
|
|||
functionname: "submitTask",
|
||||
inputs: [
|
||||
gelatoExternalProvider,
|
||||
refinanceIfCompoundBorrowIsBetter,
|
||||
refinanceIfVaultUnsafe,
|
||||
expiryDate,
|
||||
],
|
||||
}),
|
||||
|
@ -753,7 +753,7 @@ describe("Debt Bridge with External Provider", function () {
|
|||
id: await gelatoCore.currentTaskReceiptId(),
|
||||
userProxy: dsa.address,
|
||||
provider: gelatoExternalProvider,
|
||||
tasks: [refinanceIfCompoundBorrowIsBetter],
|
||||
tasks: [refinanceIfVaultUnsafe],
|
||||
expiryDate,
|
||||
});
|
||||
|
||||
|
|
42
yarn.lock
42
yarn.lock
|
@ -39,10 +39,10 @@
|
|||
resolved "https://registry.yarnpkg.com/@ensdomains/resolver/-/resolver-0.2.4.tgz#c10fe28bf5efbf49bff4666d909aed0265efbc89"
|
||||
integrity sha512-bvaTH34PMCbv6anRa9I/0zjLJgY4EuznbEMgbV77JBCQ9KNC46rzi0avuxpOfu+xDjPEtSFGqVEOr5GlUSGudA==
|
||||
|
||||
"@eslint/eslintrc@^0.2.0":
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.2.0.tgz#bc7e3c4304d4c8720968ccaee793087dfb5fe6b4"
|
||||
integrity sha512-+cIGPCBdLCzqxdtwppswP+zTsH9BOIGzAeKfBIbtb4gW/giMlfMwP0HUSFfhzh20f9u8uZ8hOp62+4GPquTbwQ==
|
||||
"@eslint/eslintrc@^0.2.1":
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.2.1.tgz#f72069c330461a06684d119384435e12a5d76e3c"
|
||||
integrity sha512-XRUeBZ5zBWLYgSANMpThFddrZZkEbGHgUdt5UJjZfnlN9BGCiUBrf+nvbRupSjMvqzwnQN0qwCmOxITt1cfywA==
|
||||
dependencies:
|
||||
ajv "^6.12.4"
|
||||
debug "^4.1.1"
|
||||
|
@ -2890,13 +2890,13 @@ eslint-visitor-keys@^2.0.0:
|
|||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8"
|
||||
integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==
|
||||
|
||||
eslint@7.12.0:
|
||||
version "7.12.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.12.0.tgz#7b6a85f87a9adc239e979bb721cde5ce0dc27da6"
|
||||
integrity sha512-n5pEU27DRxCSlOhJ2rO57GDLcNsxO0LPpAbpFdh7xmcDmjmlGUfoyrsB3I7yYdQXO5N3gkSTiDrPSPNFiiirXA==
|
||||
eslint@7.12.1:
|
||||
version "7.12.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.12.1.tgz#bd9a81fa67a6cfd51656cdb88812ce49ccec5801"
|
||||
integrity sha512-HlMTEdr/LicJfN08LB3nM1rRYliDXOmfoO4vj39xN6BLpFzF00hbwBoqHk8UcJ2M/3nlARZWy/mslvGEuZFvsg==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.0.0"
|
||||
"@eslint/eslintrc" "^0.2.0"
|
||||
"@eslint/eslintrc" "^0.2.1"
|
||||
ajv "^6.10.0"
|
||||
chalk "^4.0.0"
|
||||
cross-spawn "^7.0.2"
|
||||
|
@ -4161,10 +4161,10 @@ har-validator@~5.1.3:
|
|||
ajv "^6.12.3"
|
||||
har-schema "^2.0.0"
|
||||
|
||||
hardhat@2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.0.1.tgz#2e7d1815654406199b88b31da9c2d2763e8f5577"
|
||||
integrity sha512-9g67OkehLgHLgfqqbdR+FANshTUvFM3yuJr06ZScNErsvrdiLHpQ/Jbkd6rRiXjYovN/SMu4YZrhNEm62b7boA==
|
||||
hardhat@2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.0.2.tgz#30c3c5a49f950aad2e39c479208b4132052dc735"
|
||||
integrity sha512-P8SMYsWeC0OakmHUAgL9STalidQ1bAHFHFroPyvnfljei7EPHaIQpS6QursoZ+KVNkPTnKC+9m1Lky8nnKIjuw==
|
||||
dependencies:
|
||||
"@nomiclabs/ethereumjs-vm" "^4.1.1"
|
||||
"@sentry/node" "^5.18.1"
|
||||
|
@ -5211,10 +5211,10 @@ lines-and-columns@^1.1.6:
|
|||
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"
|
||||
integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=
|
||||
|
||||
lint-staged@10.4.2:
|
||||
version "10.4.2"
|
||||
resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-10.4.2.tgz#9fee4635c4b5ddb845746f237c6d43494ccd21c1"
|
||||
integrity sha512-OLCA9K1hS+Sl179SO6kX0JtnsaKj/MZalEhUj5yAgXsb63qPI/Gfn6Ua1KuZdbfkZNEu3/n5C/obYCu70IMt9g==
|
||||
lint-staged@10.5.0:
|
||||
version "10.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-10.5.0.tgz#c923c2447a84c595874f3de696778736227e7a7a"
|
||||
integrity sha512-gjC9+HGkBubOF+Yyoj9pd52Qfm/kYB+dRX1UOgWjHKvSDYl+VHkZXlBMlqSZa2cH3Kp5/uNL480sV6e2dTgXSg==
|
||||
dependencies:
|
||||
chalk "^4.1.0"
|
||||
cli-truncate "^2.1.0"
|
||||
|
@ -7185,10 +7185,10 @@ solhint-plugin-prettier@0.0.5:
|
|||
dependencies:
|
||||
prettier-linter-helpers "^1.0.0"
|
||||
|
||||
solhint@3.2.2:
|
||||
version "3.2.2"
|
||||
resolved "https://registry.yarnpkg.com/solhint/-/solhint-3.2.2.tgz#7857dc2d8bf53a3d61b6d218e213db5dff71a8d7"
|
||||
integrity sha512-cd9AQhmbsIp6YhMc4ezSawx9VQEASEvl4iThGSRFFozmTRM7c0lSxYrcrSk04jHMuw0g3IdnbxwmQV6hpxNhqA==
|
||||
solhint@3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/solhint/-/solhint-3.3.0.tgz#4c7786480d25986ad25f0199fff334c07189a9a4"
|
||||
integrity sha512-vnTGzsX2UzxbsIgH5ib2CXorbGywi1vjOOMPXrlyufhg3oRS7IL6cj7oriYMk6fZiml3GvvA/xo1HdaWKhWJEQ==
|
||||
dependencies:
|
||||
"@solidity-parser/parser" "^0.8.1"
|
||||
ajv "^6.6.1"
|
||||
|
|
Loading…
Reference in New Issue
Block a user