mirror of
https://github.com/Instadapp/Gelato-automations.git
synced 2024-07-29 22:28:07 +00:00
Unit testing new smart contract.
This commit is contained in:
parent
e6a37987b8
commit
d04f327159
|
@ -25,6 +25,7 @@ module.exports = {
|
||||||
unlocked_accounts: [INSTA_MASTER],
|
unlocked_accounts: [INSTA_MASTER],
|
||||||
// Custom
|
// Custom
|
||||||
GelatoCore: "0x1d681d76ce96E4d70a88A00EBbcfc1E47808d0b8",
|
GelatoCore: "0x1d681d76ce96E4d70a88A00EBbcfc1E47808d0b8",
|
||||||
|
GelatoGasPriceOracle: "0x169E633A2D1E6c10dD91238Ba11c4A708dfEF37C",
|
||||||
InstaMaster: INSTA_MASTER,
|
InstaMaster: INSTA_MASTER,
|
||||||
InstaIndex: "0x2971AdFa57b20E5a416aE5a708A8655A9c74f723",
|
InstaIndex: "0x2971AdFa57b20E5a416aE5a708A8655A9c74f723",
|
||||||
InstaList: "0x4c8a1BEb8a87765788946D6B19C6C6355194AbEb",
|
InstaList: "0x4c8a1BEb8a87765788946D6B19C6C6355194AbEb",
|
||||||
|
@ -37,9 +38,11 @@ module.exports = {
|
||||||
ConnectCompound: "0x07F81230d73a78f63F0c2A3403AD281b067d28F8",
|
ConnectCompound: "0x07F81230d73a78f63F0c2A3403AD281b067d28F8",
|
||||||
ConnectInstaPool: "0xCeF5f3c402d4fef76A038e89a4357176963e1464",
|
ConnectInstaPool: "0xCeF5f3c402d4fef76A038e89a4357176963e1464",
|
||||||
MakerResolver: "0x0A7008B38E7015F8C36A49eEbc32513ECA8801E5",
|
MakerResolver: "0x0A7008B38E7015F8C36A49eEbc32513ECA8801E5",
|
||||||
|
CompoundResolver: "0x1f22D77365d8BFE3b901C33C83C01B584F946617",
|
||||||
DAI: "0x6b175474e89094c44da98b954eedeac495271d0f",
|
DAI: "0x6b175474e89094c44da98b954eedeac495271d0f",
|
||||||
DAI_UNISWAP: "0x2a1530C4C41db0B0b2bB646CB5Eb1A67b7158667",
|
DAI_UNISWAP: "0x2a1530C4C41db0B0b2bB646CB5Eb1A67b7158667",
|
||||||
CDAI: "0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643",
|
CDAI: "0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643",
|
||||||
|
CETH: "0x4ddc2d193948926d02f9b1fe9e1daa0718270ed5",
|
||||||
DssCdpManager: "0x5ef30b9986345249bc32d8928B7ee64DE9435E39",
|
DssCdpManager: "0x5ef30b9986345249bc32d8928B7ee64DE9435E39",
|
||||||
GetCdps: "0x36a724Bd100c39f0Ea4D3A20F7097eE01A8Ff573",
|
GetCdps: "0x36a724Bd100c39f0Ea4D3A20F7097eE01A8Ff573",
|
||||||
ProviderModuleDSA: "0x0C25452d20cdFeEd2983fa9b9b9Cf4E81D6f2fE2",
|
ProviderModuleDSA: "0x0C25452d20cdFeEd2983fa9b9b9Cf4E81D6f2fE2",
|
||||||
|
|
|
@ -293,7 +293,7 @@ contract ConnectGelatoDebtBridge is ConnectGelatoDebtBridgeResolver {
|
||||||
// Constant name must be in capitalized SNAKE_CASE
|
// Constant name must be in capitalized SNAKE_CASE
|
||||||
// solhint-disable-next-line
|
// solhint-disable-next-line
|
||||||
string public constant override name = "GelatoDebtBridge-v1.0";
|
string public constant override name = "GelatoDebtBridge-v1.0";
|
||||||
uint256 public constant GASLIMIT = 2000000; // To Define
|
uint256 public constant GASLIMIT = 1933090 + (19331 * 2); // 1933080 + ~2% (Estimated Value)
|
||||||
address public immutable oracleAggregator;
|
address public immutable oracleAggregator;
|
||||||
|
|
||||||
constructor(uint256 _iD, address _oracleAggregator) public {
|
constructor(uint256 _iD, address _oracleAggregator) public {
|
||||||
|
@ -315,7 +315,7 @@ contract ConnectGelatoDebtBridge is ConnectGelatoDebtBridgeResolver {
|
||||||
string memory _pair,
|
string memory _pair,
|
||||||
uint256 _getID,
|
uint256 _getID,
|
||||||
uint256 _setID
|
uint256 _setID
|
||||||
) external {
|
) external payable {
|
||||||
(
|
(
|
||||||
uint256 paybackAmount,
|
uint256 paybackAmount,
|
||||||
uint256 collateralToWithdraw,
|
uint256 collateralToWithdraw,
|
||||||
|
|
|
@ -59,7 +59,7 @@ contract ConnectGelatoProviderPayment is ConnectGelatoProviderPaymentHelper {
|
||||||
uint256 _amt,
|
uint256 _amt,
|
||||||
uint256 _getID,
|
uint256 _getID,
|
||||||
uint256 _setID
|
uint256 _setID
|
||||||
) public {
|
) public payable {
|
||||||
// Desable linter for too long require statement
|
// Desable linter for too long require statement
|
||||||
// solhint-disable-next-line
|
// solhint-disable-next-line
|
||||||
require(
|
require(
|
||||||
|
|
37
contracts/Mocks/ConnectGelatoDebtBridgeMock.sol
Normal file
37
contracts/Mocks/ConnectGelatoDebtBridgeMock.sol
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
pragma solidity 0.6.12;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import "../ConnectGelatoDEbtBridge.sol";
|
||||||
|
|
||||||
|
contract ConnectGelatoDebtBridgeMock is ConnectGelatoDebtBridge {
|
||||||
|
constructor(uint256 _iD, address _oracleAggregator)
|
||||||
|
public
|
||||||
|
ConnectGelatoDebtBridge(_iD, _oracleAggregator)
|
||||||
|
{}
|
||||||
|
|
||||||
|
function wcollateralToWithdraw(
|
||||||
|
uint256 _p1LiqRatio,
|
||||||
|
uint256 _p2LiqRatio,
|
||||||
|
uint256 _col,
|
||||||
|
uint256 _bor,
|
||||||
|
uint256 _colPrice
|
||||||
|
) public pure returns (uint256) {
|
||||||
|
return
|
||||||
|
_wcollateralToWithdraw(
|
||||||
|
_p1LiqRatio,
|
||||||
|
_p2LiqRatio,
|
||||||
|
_col,
|
||||||
|
_bor,
|
||||||
|
_colPrice
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function wborrowedTokenToPayback(
|
||||||
|
uint256 _p1LiqRatio,
|
||||||
|
uint256 _p2LiqRatio,
|
||||||
|
uint256 _col,
|
||||||
|
uint256 _bor
|
||||||
|
) public pure returns (uint256) {
|
||||||
|
return _wborrowedTokenToPayback(_p1LiqRatio, _p2LiqRatio, _col, _bor);
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,9 +10,9 @@ interface IMakerPriceFeed {
|
||||||
}
|
}
|
||||||
|
|
||||||
contract OracleAggregatorStorage {
|
contract OracleAggregatorStorage {
|
||||||
mapping(string => address) internal _makerOracle;
|
mapping(string => address) public makerOracle;
|
||||||
mapping(string => address) internal _compoundOracle;
|
mapping(string => address) public compoundOracle;
|
||||||
mapping(string => address) internal _chainlinkOracle;
|
mapping(string => address) public chainlinkOracle;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0x729D19f657BD0614b4985Cf1D82531c67569197B for ETH/USD medianizer it return value in wad standard.
|
// 0x729D19f657BD0614b4985Cf1D82531c67569197B for ETH/USD medianizer it return value in wad standard.
|
||||||
|
@ -37,10 +37,10 @@ contract OracleAggregator is OracleAggregatorStorage, Ownable, DSMath {
|
||||||
// Desable linter for too long require statement
|
// Desable linter for too long require statement
|
||||||
// solhint-disable-next-line
|
// solhint-disable-next-line
|
||||||
require(
|
require(
|
||||||
_makerOracle[_pair] == address(0x0),
|
makerOracle[_pair] == address(0x0),
|
||||||
"OracleAggregator.Maker: Oracle already set."
|
"OracleAggregator.Maker: Oracle already set."
|
||||||
);
|
);
|
||||||
_makerOracle[_pair] = _oracleAddress;
|
makerOracle[_pair] = _oracleAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMakerTokenPrice(string memory _pair)
|
function getMakerTokenPrice(string memory _pair)
|
||||||
|
@ -48,9 +48,15 @@ contract OracleAggregator is OracleAggregatorStorage, Ownable, DSMath {
|
||||||
view
|
view
|
||||||
returns (uint256)
|
returns (uint256)
|
||||||
{
|
{
|
||||||
|
// Desable linter for too long require statement
|
||||||
|
// solhint-disable-next-line
|
||||||
|
require(
|
||||||
|
makerOracle[_pair] != address(0x0),
|
||||||
|
"OracleAggregator.getMakerTokenPrice: CurrencyPairNotSupported."
|
||||||
|
);
|
||||||
if (mockMode) {
|
if (mockMode) {
|
||||||
return mockValue;
|
return mockValue;
|
||||||
}
|
}
|
||||||
return uint256(IMakerPriceFeed(_makerOracle[_pair]).read());
|
return uint256(IMakerPriceFeed(makerOracle[_pair]).read());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,26 +3,7 @@
|
||||||
"abi": [
|
"abi": [
|
||||||
{
|
{
|
||||||
"inputs": [],
|
"inputs": [],
|
||||||
"name": "_acceptAdmin",
|
"name": "accrueInterest",
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address payable",
|
|
||||||
"name": "newPendingAdmin",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "_setPendingAdmin",
|
|
||||||
"outputs": [
|
"outputs": [
|
||||||
{
|
{
|
||||||
"internalType": "uint256",
|
"internalType": "uint256",
|
||||||
|
@ -285,6 +266,19 @@
|
||||||
"stateMutability": "view",
|
"stateMutability": "view",
|
||||||
"type": "function"
|
"type": "function"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "totalBorrows",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"inputs": [],
|
"inputs": [],
|
||||||
"name": "totalBorrowsCurrent",
|
"name": "totalBorrowsCurrent",
|
||||||
|
@ -298,6 +292,32 @@
|
||||||
"stateMutability": "nonpayable",
|
"stateMutability": "nonpayable",
|
||||||
"type": "function"
|
"type": "function"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "totalReserves",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "totalSupply",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"inputs": [
|
"inputs": [
|
||||||
{
|
{
|
||||||
|
|
22
pre-compiles/GelatoGasPriceOracle.json
Normal file
22
pre-compiles/GelatoGasPriceOracle.json
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"contractName": "GelatoGasPriceOracle",
|
||||||
|
"abi": [
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "latestAnswer",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "int256",
|
||||||
|
"name": "",
|
||||||
|
"type": "int256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"bytecode": "0x",
|
||||||
|
"deployedBytecode": "0x",
|
||||||
|
"linkReferences": {},
|
||||||
|
"deployedLinkReferences": {}
|
||||||
|
}
|
260
pre-compiles/InstaCompoundResolver.json
Normal file
260
pre-compiles/InstaCompoundResolver.json
Normal file
File diff suppressed because one or more lines are too long
|
@ -21,13 +21,86 @@ 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");
|
||||||
const CTokenInterface = require("../pre-compiles/CTokenInterface.json");
|
const CTokenInterface = require("../pre-compiles/CTokenInterface.json");
|
||||||
|
const GelatoGasPriceOracle = require("../pre-compiles/GelatoGasPriceOracle.json");
|
||||||
|
const CompoundResolver = require("../pre-compiles/InstaCompoundResolver.json");
|
||||||
|
|
||||||
const ETH = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
|
const ETH = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
|
||||||
const GAS_LIMIT = "4000000";
|
const GAS_LIMIT = "4000000";
|
||||||
const GAS_PRICE_CEIL = ethers.utils.parseUnits("1000", "gwei");
|
const GAS_PRICE_CEIL = ethers.utils.parseUnits("1000", "gwei");
|
||||||
|
const WAD = ethers.utils.parseUnits("1", 18);
|
||||||
|
|
||||||
// #endregion
|
// #endregion
|
||||||
|
|
||||||
|
//#region Mock Math Function
|
||||||
|
|
||||||
|
let wdiv = (x, y) => {
|
||||||
|
return x.mul(WAD).add(y.div(2)).div(y);
|
||||||
|
};
|
||||||
|
|
||||||
|
let wmul = (x, y) => {
|
||||||
|
return x.mul(y).add(WAD.div(2)).div(WAD);
|
||||||
|
};
|
||||||
|
|
||||||
|
let wcollateralToWithdraw = (
|
||||||
|
wantedLiquidationRatioOnProtocol1,
|
||||||
|
wantedLiquidationRatioOnProtocol2,
|
||||||
|
collateral,
|
||||||
|
borrowedToken,
|
||||||
|
collateralPrice
|
||||||
|
) => {
|
||||||
|
//#region CALCULATION REPLICATION
|
||||||
|
|
||||||
|
let expectedColToWithdraw = wmul(
|
||||||
|
wmul(wantedLiquidationRatioOnProtocol1, wantedLiquidationRatioOnProtocol2),
|
||||||
|
borrowedToken
|
||||||
|
); // doc ref : c_r x comp_r x d_2
|
||||||
|
expectedColToWithdraw = expectedColToWithdraw.sub(
|
||||||
|
wmul(wantedLiquidationRatioOnProtocol1, collateral)
|
||||||
|
); // doc ref : c_r x comp_r x d_2 - c_r x e_2
|
||||||
|
expectedColToWithdraw = wdiv(
|
||||||
|
expectedColToWithdraw,
|
||||||
|
wantedLiquidationRatioOnProtocol2.sub(wantedLiquidationRatioOnProtocol1)
|
||||||
|
); // doc ref : (c_r x comp_r x d_2 - c_r x e_2)/ (comp_r - c_r)
|
||||||
|
expectedColToWithdraw = collateral.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;
|
||||||
|
};
|
||||||
|
|
||||||
|
let wborrowedTokenToPayback = (
|
||||||
|
wantedLiquidationRatioOnProtocol1,
|
||||||
|
wantedLiquidationRatioOnProtocol2,
|
||||||
|
collateral,
|
||||||
|
borrowedToken
|
||||||
|
) => {
|
||||||
|
//#region CALCULATION REPLICATION
|
||||||
|
|
||||||
|
let expectedBorToPayBack = wmul(
|
||||||
|
wmul(wantedLiquidationRatioOnProtocol1, wantedLiquidationRatioOnProtocol2),
|
||||||
|
borrowedToken
|
||||||
|
); // doc ref : c_r x comp_r x d_2
|
||||||
|
expectedBorToPayBack = expectedBorToPayBack.sub(
|
||||||
|
wmul(wantedLiquidationRatioOnProtocol1, collateral)
|
||||||
|
); // doc ref : c_r x comp_r x d_2 - c_r x e_2
|
||||||
|
expectedBorToPayBack = wdiv(
|
||||||
|
expectedBorToPayBack,
|
||||||
|
wantedLiquidationRatioOnProtocol2.sub(wantedLiquidationRatioOnProtocol1)
|
||||||
|
); // 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), wantedLiquidationRatioOnProtocol1),
|
||||||
|
expectedBorToPayBack
|
||||||
|
); // doc ref : (1/c_r)((c_r x comp_r x d_2 - c_r x e_2)/ (comp_r - c_r))
|
||||||
|
expectedBorToPayBack = borrowedToken.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 () {
|
describe("Debt Bridge with External Provider", function () {
|
||||||
this.timeout(0);
|
this.timeout(0);
|
||||||
if (bre.network.name !== "ganache") {
|
if (bre.network.name !== "ganache") {
|
||||||
|
@ -53,8 +126,11 @@ describe("Debt Bridge with External Provider", function () {
|
||||||
let daiToken;
|
let daiToken;
|
||||||
let gelatoCore;
|
let gelatoCore;
|
||||||
let cDaiToken;
|
let cDaiToken;
|
||||||
|
let cEthToken;
|
||||||
let instaMaster;
|
let instaMaster;
|
||||||
let instaConnectors;
|
let instaConnectors;
|
||||||
|
let gelatoGasPriceOracle;
|
||||||
|
let compoundResolver;
|
||||||
|
|
||||||
// Contracts to deploy and use for local testing
|
// Contracts to deploy and use for local testing
|
||||||
let conditionMakerVaultIsSafe;
|
let conditionMakerVaultIsSafe;
|
||||||
|
@ -126,10 +202,22 @@ describe("Debt Bridge with External Provider", function () {
|
||||||
CTokenInterface.abi,
|
CTokenInterface.abi,
|
||||||
bre.network.config.CDAI
|
bre.network.config.CDAI
|
||||||
);
|
);
|
||||||
|
cEthToken = await ethers.getContractAt(
|
||||||
|
CTokenInterface.abi,
|
||||||
|
bre.network.config.CETH
|
||||||
|
);
|
||||||
instaConnectors = await ethers.getContractAt(
|
instaConnectors = await ethers.getContractAt(
|
||||||
InstaConnector.abi,
|
InstaConnector.abi,
|
||||||
bre.network.config.InstaConnectors
|
bre.network.config.InstaConnectors
|
||||||
);
|
);
|
||||||
|
gelatoGasPriceOracle = await ethers.getContractAt(
|
||||||
|
GelatoGasPriceOracle.abi,
|
||||||
|
bre.network.config.GelatoGasPriceOracle
|
||||||
|
);
|
||||||
|
compoundResolver = await ethers.getContractAt(
|
||||||
|
CompoundResolver.abi,
|
||||||
|
bre.network.config.CompoundResolver
|
||||||
|
);
|
||||||
// instaEvent = await ethers.getContractAt(
|
// instaEvent = await ethers.getContractAt(
|
||||||
// InstaEvent.abi,
|
// InstaEvent.abi,
|
||||||
// bre.network.config.InstaEvent
|
// bre.network.config.InstaEvent
|
||||||
|
@ -449,7 +537,7 @@ describe("Debt Bridge with External Provider", function () {
|
||||||
//#endregion
|
//#endregion
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Use Maker Compound refinancing if the maker vault become unsafe after a market move.", async function () {
|
it("#1: Use Maker Compound refinancing if the maker vault become unsafe after a market move.", async function () {
|
||||||
// User Actions
|
// User Actions
|
||||||
// Step 1 : User create a DeFi Smart Account
|
// Step 1 : User create a DeFi Smart Account
|
||||||
// Step 2 : User open a Vault, put some ether on it and borrow some dai
|
// Step 2 : User open a Vault, put some ether on it and borrow some dai
|
||||||
|
@ -566,6 +654,10 @@ describe("Debt Bridge with External Provider", function () {
|
||||||
// It will be done through a algorithm that will optimize the
|
// It will be done through a algorithm that will optimize the
|
||||||
// total borrow rate.
|
// total borrow rate.
|
||||||
|
|
||||||
|
let wantedLiquidationRatioOnProtocol1 = ethers.utils.parseUnits("3", 18);
|
||||||
|
let wantedLiquidationRatioOnProtocol2 = ethers.utils.parseUnits("19", 17);
|
||||||
|
let currencyPair = "ETH/USD";
|
||||||
|
|
||||||
const debtBridgeCondition = new GelatoCoreLib.Condition({
|
const debtBridgeCondition = new GelatoCoreLib.Condition({
|
||||||
inst: conditionMakerVaultIsSafe.address,
|
inst: conditionMakerVaultIsSafe.address,
|
||||||
data: await conditionMakerVaultIsSafe.getConditionData(
|
data: await conditionMakerVaultIsSafe.getConditionData(
|
||||||
|
@ -585,9 +677,9 @@ describe("Debt Bridge with External Provider", function () {
|
||||||
functionname: "debtBridgeMakerToCompound",
|
functionname: "debtBridgeMakerToCompound",
|
||||||
inputs: [
|
inputs: [
|
||||||
cdpId,
|
cdpId,
|
||||||
ethers.utils.parseUnits("3", 18),
|
wantedLiquidationRatioOnProtocol1,
|
||||||
ethers.utils.parseUnits("18", 17),
|
wantedLiquidationRatioOnProtocol2,
|
||||||
"ETH/USD",
|
currencyPair,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
|
@ -748,7 +840,37 @@ describe("Debt Bridge with External Provider", function () {
|
||||||
// will execute the user's task to make the user position safe
|
// will execute the user's task to make the user position safe
|
||||||
// by a debt refinancing in compound.
|
// by a debt refinancing in compound.
|
||||||
|
|
||||||
|
//#region EXPECTED OUTCOME
|
||||||
|
|
||||||
|
let latestPrice = await oracleAggregator.getMakerTokenPrice(currencyPair);
|
||||||
|
let fees = ethers.utils
|
||||||
|
.parseUnits("2000000", 0)
|
||||||
|
.mul(await gelatoGasPriceOracle.latestAnswer());
|
||||||
|
let debt = await connectGelatoDebtBridge.getMakerVaultDebt(cdpId);
|
||||||
|
let collateral = wmul(
|
||||||
|
await connectGelatoDebtBridge.getMakerVaultCollateralBalance(cdpId),
|
||||||
|
latestPrice
|
||||||
|
).sub(fees);
|
||||||
|
|
||||||
|
let expectedColWithdrawAmount = wcollateralToWithdraw(
|
||||||
|
wantedLiquidationRatioOnProtocol1,
|
||||||
|
wantedLiquidationRatioOnProtocol2,
|
||||||
|
collateral,
|
||||||
|
debt,
|
||||||
|
latestPrice
|
||||||
|
);
|
||||||
|
|
||||||
|
let expectedBorAmountToPayBack = wborrowedTokenToPayback(
|
||||||
|
wantedLiquidationRatioOnProtocol1,
|
||||||
|
wantedLiquidationRatioOnProtocol2,
|
||||||
|
collateral,
|
||||||
|
debt
|
||||||
|
);
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
let providerBalanceBeforeExecution = await providerWallet.getBalance();
|
let providerBalanceBeforeExecution = await providerWallet.getBalance();
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
connectedGelatoCore.exec(taskReceipt, {
|
connectedGelatoCore.exec(taskReceipt, {
|
||||||
gasPrice: gelatoGasPrice, // Exectutor must use gelatoGasPrice (Chainlink fast gwei)
|
gasPrice: gelatoGasPrice, // Exectutor must use gelatoGasPrice (Chainlink fast gwei)
|
||||||
|
@ -757,15 +879,47 @@ describe("Debt Bridge with External Provider", function () {
|
||||||
).to.emit(gelatoCore, "LogExecSuccess");
|
).to.emit(gelatoCore, "LogExecSuccess");
|
||||||
|
|
||||||
let providerBalanceAfterExecution = await providerWallet.getBalance();
|
let providerBalanceAfterExecution = await providerWallet.getBalance();
|
||||||
|
|
||||||
expect(providerBalanceAfterExecution).to.be.gt(
|
expect(providerBalanceAfterExecution).to.be.gt(
|
||||||
providerBalanceBeforeExecution
|
providerBalanceBeforeExecution
|
||||||
);
|
);
|
||||||
const amtOfBorrowedDAIOnCompound = (
|
|
||||||
await cDaiToken.getAccountSnapshot(dsa.address)
|
// compound position of DSA on cDai and cEth
|
||||||
)[2];
|
let compoundPosition = await compoundResolver.getCompoundData(dsa.address, [
|
||||||
expect(amtOfBorrowedDAIOnCompound).to.be.lt(
|
cDaiToken.address,
|
||||||
ethers.utils.parseUnits("1000", 18)
|
cEthToken.address,
|
||||||
); // Check the borrow amount
|
]);
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
let exchangeRateCethToEth = (await cEthToken.getCash())
|
||||||
|
.add(await cEthToken.totalBorrows())
|
||||||
|
.sub(await cEthToken.totalReserves())
|
||||||
|
.div(await cEthToken.totalSupply());
|
||||||
|
|
||||||
|
expect(
|
||||||
|
expectedBorAmountToPayBack.sub(
|
||||||
|
compoundPosition[0].borrowBalanceStoredUser
|
||||||
|
)
|
||||||
|
).to.be.gt(ethers.utils.parseUnits("1", 0));
|
||||||
|
expect(
|
||||||
|
expectedColWithdrawAmount.sub(
|
||||||
|
compoundPosition[1].balanceOfUser.mul(exchangeRateCethToEth)
|
||||||
|
)
|
||||||
|
).to.be.gt(ethers.utils.parseUnits("1", 0));
|
||||||
|
expect(
|
||||||
|
expectedBorAmountToPayBack.sub(
|
||||||
|
compoundPosition[0].borrowBalanceStoredUser
|
||||||
|
)
|
||||||
|
).to.be.lt(ethers.utils.parseUnits("1", 16));
|
||||||
|
expect(
|
||||||
|
expectedColWithdrawAmount.sub(
|
||||||
|
compoundPosition[1].balanceOfUser.mul(exchangeRateCethToEth)
|
||||||
|
)
|
||||||
|
).to.be.lt(ethers.utils.parseUnits("1", 14));
|
||||||
|
|
||||||
|
// DSA contain 1000 DAI
|
||||||
expect(await daiToken.balanceOf(dsa.address)).to.be.equal(
|
expect(await daiToken.balanceOf(dsa.address)).to.be.equal(
|
||||||
ethers.utils.parseUnits("1000", 18)
|
ethers.utils.parseUnits("1000", 18)
|
||||||
);
|
);
|
||||||
|
|
182
test/3_ConditionMakerVaultIsSafe.test.js
Normal file
182
test/3_ConditionMakerVaultIsSafe.test.js
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
const {expect} = require("chai");
|
||||||
|
const bre = require("@nomiclabs/buidler");
|
||||||
|
const {ethers} = bre;
|
||||||
|
|
||||||
|
// #region Contracts ABI
|
||||||
|
|
||||||
|
const ConnectMaker = require("../pre-compiles/ConnectMaker.json");
|
||||||
|
const GetCdps = require("../pre-compiles/GetCdps.json");
|
||||||
|
const DssCdpManager = require("../pre-compiles/DssCdpManager.json");
|
||||||
|
const InstaList = require("../pre-compiles/InstaList.json");
|
||||||
|
const InstaAccount = require("../pre-compiles/InstaAccount.json");
|
||||||
|
const InstaIndex = require("../pre-compiles/InstaIndex.json");
|
||||||
|
const IERC20 = require("../pre-compiles/IERC20.json");
|
||||||
|
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
describe("ConditionMakerVaultIsSafe gelato condition contract unit test", function () {
|
||||||
|
this.timeout(0);
|
||||||
|
if (bre.network.name !== "ganache") {
|
||||||
|
console.error("Test Suite is meant to be run on ganache only");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let userWallet;
|
||||||
|
let userAddress;
|
||||||
|
|
||||||
|
let getCdps;
|
||||||
|
let dssCdpManager;
|
||||||
|
let instaList;
|
||||||
|
let instaIndex;
|
||||||
|
let daiToken;
|
||||||
|
|
||||||
|
let conditionMakerVaultIsSafe;
|
||||||
|
let oracleAggregator;
|
||||||
|
|
||||||
|
let cdpId;
|
||||||
|
let dsa;
|
||||||
|
|
||||||
|
before(async function () {
|
||||||
|
// Get Test Wallet for local testnet
|
||||||
|
[userWallet] = await ethers.getSigners();
|
||||||
|
userAddress = await userWallet.getAddress();
|
||||||
|
|
||||||
|
// Ganache default accounts prefilled with 100 ETH
|
||||||
|
expect(await userWallet.getBalance()).to.be.gt(
|
||||||
|
ethers.utils.parseEther("10")
|
||||||
|
);
|
||||||
|
|
||||||
|
instaIndex = await ethers.getContractAt(
|
||||||
|
InstaIndex.abi,
|
||||||
|
bre.network.config.InstaIndex
|
||||||
|
);
|
||||||
|
instaList = await ethers.getContractAt(
|
||||||
|
InstaList.abi,
|
||||||
|
bre.network.config.InstaList
|
||||||
|
);
|
||||||
|
getCdps = await ethers.getContractAt(
|
||||||
|
GetCdps.abi,
|
||||||
|
bre.network.config.GetCdps
|
||||||
|
);
|
||||||
|
dssCdpManager = await ethers.getContractAt(
|
||||||
|
DssCdpManager.abi,
|
||||||
|
bre.network.config.DssCdpManager
|
||||||
|
);
|
||||||
|
daiToken = await ethers.getContractAt(IERC20.abi, bre.network.config.DAI);
|
||||||
|
|
||||||
|
// ========== Test Setup ============
|
||||||
|
|
||||||
|
const OracleAggregator = await ethers.getContractFactory(
|
||||||
|
"OracleAggregator"
|
||||||
|
);
|
||||||
|
|
||||||
|
oracleAggregator = await OracleAggregator.deploy();
|
||||||
|
await oracleAggregator.deployed();
|
||||||
|
|
||||||
|
const ConditionMakerVaultIsSafe = await ethers.getContractFactory(
|
||||||
|
"ConditionMakerVaultIsSafe"
|
||||||
|
);
|
||||||
|
|
||||||
|
conditionMakerVaultIsSafe = await ConditionMakerVaultIsSafe.deploy(
|
||||||
|
oracleAggregator.address
|
||||||
|
);
|
||||||
|
await conditionMakerVaultIsSafe.deployed();
|
||||||
|
|
||||||
|
// Create DeFi Smart 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)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create/Deposit/Borrow a Vault
|
||||||
|
const openVault = await bre.run("abi-encode-withselector", {
|
||||||
|
abi: ConnectMaker.abi,
|
||||||
|
functionname: "open",
|
||||||
|
inputs: ["ETH-A"],
|
||||||
|
});
|
||||||
|
|
||||||
|
await dsa.cast([bre.network.config.ConnectMaker], [openVault], userAddress);
|
||||||
|
|
||||||
|
let cdps = await getCdps.getCdpsAsc(dssCdpManager.address, dsa.address);
|
||||||
|
cdpId = String(cdps.ids[0]);
|
||||||
|
|
||||||
|
expect(cdps.ids[0].isZero()).to.be.false;
|
||||||
|
|
||||||
|
await dsa.cast(
|
||||||
|
[bre.network.config.ConnectMaker],
|
||||||
|
[
|
||||||
|
await bre.run("abi-encode-withselector", {
|
||||||
|
abi: ConnectMaker.abi,
|
||||||
|
functionname: "deposit",
|
||||||
|
inputs: [cdpId, ethers.utils.parseEther("10"), 0, 0],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
userAddress,
|
||||||
|
{
|
||||||
|
value: ethers.utils.parseEther("10"),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
await dsa.cast(
|
||||||
|
[bre.network.config.ConnectMaker],
|
||||||
|
[
|
||||||
|
await bre.run("abi-encode-withselector", {
|
||||||
|
abi: ConnectMaker.abi,
|
||||||
|
functionname: "borrow",
|
||||||
|
inputs: [cdpId, ethers.utils.parseUnits("1000", 18), 0, 0],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
userAddress
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(await daiToken.balanceOf(dsa.address)).to.be.equal(
|
||||||
|
ethers.utils.parseEther("1000")
|
||||||
|
);
|
||||||
|
// Add ETH/USD Maker Medianizer in the Oracle Aggregator
|
||||||
|
|
||||||
|
await oracleAggregator.addOracle(
|
||||||
|
"ETH/USD",
|
||||||
|
"0x729D19f657BD0614b4985Cf1D82531c67569197B"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#1: ok should return NotOKMakerVaultIsSafe when the ETH/USD price is above the defined limit", async function () {
|
||||||
|
let data = await conditionMakerVaultIsSafe.getConditionData(
|
||||||
|
cdpId,
|
||||||
|
"ETH/USD",
|
||||||
|
ethers.utils.parseUnits("30", 17)
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(await conditionMakerVaultIsSafe.ok(0, data, 0)).to.be.equal(
|
||||||
|
"NotOKMakerVaultIsSafe"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#2: ok should return OK when the ETH/USD price is lower than the defined limit", async function () {
|
||||||
|
let data = await conditionMakerVaultIsSafe.getConditionData(
|
||||||
|
cdpId,
|
||||||
|
"ETH/USD",
|
||||||
|
ethers.utils.parseUnits("30", 17)
|
||||||
|
);
|
||||||
|
|
||||||
|
//#region Mock Part
|
||||||
|
|
||||||
|
oracleAggregator.mock(true, ethers.utils.parseUnits("299", 18));
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
expect(await conditionMakerVaultIsSafe.ok(0, data, 0)).to.be.equal(
|
||||||
|
"NotOKMakerVaultIsSafe"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
281
test/4_ConnectGelatoProviderPayment.test.js
Normal file
281
test/4_ConnectGelatoProviderPayment.test.js
Normal file
|
@ -0,0 +1,281 @@
|
||||||
|
const {expect} = require("chai");
|
||||||
|
const bre = require("@nomiclabs/buidler");
|
||||||
|
const {ethers} = bre;
|
||||||
|
|
||||||
|
// #region Contracts ABI
|
||||||
|
|
||||||
|
const ConnectMaker = require("../pre-compiles/ConnectMaker.json");
|
||||||
|
const GetCdps = require("../pre-compiles/GetCdps.json");
|
||||||
|
const DssCdpManager = require("../pre-compiles/DssCdpManager.json");
|
||||||
|
const ConnectBasic = require("../pre-compiles/ConnectBasic.json");
|
||||||
|
const InstaList = require("../pre-compiles/InstaList.json");
|
||||||
|
const InstaAccount = require("../pre-compiles/InstaAccount.json");
|
||||||
|
const InstaIndex = require("../pre-compiles/InstaIndex.json");
|
||||||
|
const IERC20 = require("../pre-compiles/IERC20.json");
|
||||||
|
const InstaConnector = require("../pre-compiles/InstaConnectors.json");
|
||||||
|
const ConnectGelatoProviderPaymentABI = require("../artifacts/ConnectGelatoProviderPayment.json");
|
||||||
|
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
describe("Gelato Provider Payment Connector unit test", function () {
|
||||||
|
this.timeout(0);
|
||||||
|
if (bre.network.name !== "ganache") {
|
||||||
|
console.error("Test Suite is meant to be run on ganache only");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let userWallet;
|
||||||
|
let userAddress;
|
||||||
|
let providerWallet;
|
||||||
|
let providerAddress;
|
||||||
|
|
||||||
|
let instaList;
|
||||||
|
let instaIndex;
|
||||||
|
let daiToken;
|
||||||
|
let instaConnectors;
|
||||||
|
let instaMaster;
|
||||||
|
let connectBasic;
|
||||||
|
let getCdps;
|
||||||
|
let dssCdpManager;
|
||||||
|
|
||||||
|
let connectGelatoProviderPayment;
|
||||||
|
|
||||||
|
let dsa;
|
||||||
|
let cdpId;
|
||||||
|
|
||||||
|
before(async function () {
|
||||||
|
// Get Test Wallet for local testnet
|
||||||
|
[userWallet] = await ethers.getSigners();
|
||||||
|
userAddress = await userWallet.getAddress();
|
||||||
|
|
||||||
|
[, providerWallet] = await ethers.getSigners();
|
||||||
|
providerAddress = await providerWallet.getAddress();
|
||||||
|
|
||||||
|
instaMaster = await ethers.provider.getSigner(
|
||||||
|
bre.network.config.InstaMaster
|
||||||
|
);
|
||||||
|
|
||||||
|
// Ganache default accounts prefilled with 100 ETH
|
||||||
|
expect(await userWallet.getBalance()).to.be.gt(
|
||||||
|
ethers.utils.parseEther("10")
|
||||||
|
);
|
||||||
|
|
||||||
|
instaIndex = await ethers.getContractAt(
|
||||||
|
InstaIndex.abi,
|
||||||
|
bre.network.config.InstaIndex
|
||||||
|
);
|
||||||
|
instaList = await ethers.getContractAt(
|
||||||
|
InstaList.abi,
|
||||||
|
bre.network.config.InstaList
|
||||||
|
);
|
||||||
|
connectBasic = await ethers.getContractAt(
|
||||||
|
ConnectBasic.abi,
|
||||||
|
bre.network.config.ConnectBasic
|
||||||
|
);
|
||||||
|
instaConnectors = await ethers.getContractAt(
|
||||||
|
InstaConnector.abi,
|
||||||
|
bre.network.config.InstaConnectors
|
||||||
|
);
|
||||||
|
getCdps = await ethers.getContractAt(
|
||||||
|
GetCdps.abi,
|
||||||
|
bre.network.config.GetCdps
|
||||||
|
);
|
||||||
|
dssCdpManager = await ethers.getContractAt(
|
||||||
|
DssCdpManager.abi,
|
||||||
|
bre.network.config.DssCdpManager
|
||||||
|
);
|
||||||
|
daiToken = await ethers.getContractAt(IERC20.abi, bre.network.config.DAI);
|
||||||
|
|
||||||
|
// ========== Test Setup ============
|
||||||
|
|
||||||
|
const connectorLength = await instaConnectors.connectorLength();
|
||||||
|
const connectorId = connectorLength.add(1);
|
||||||
|
|
||||||
|
const ConnectGelatoProviderPayment = await ethers.getContractFactory(
|
||||||
|
"ConnectGelatoProviderPayment"
|
||||||
|
);
|
||||||
|
connectGelatoProviderPayment = await ConnectGelatoProviderPayment.deploy(
|
||||||
|
connectorId
|
||||||
|
);
|
||||||
|
connectGelatoProviderPayment.deployed();
|
||||||
|
|
||||||
|
await instaConnectors
|
||||||
|
.connect(instaMaster)
|
||||||
|
.enable(connectGelatoProviderPayment.address);
|
||||||
|
|
||||||
|
await userWallet.sendTransaction({
|
||||||
|
to: bre.network.config.InstaMaster,
|
||||||
|
value: ethers.utils.parseEther("0.1"),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await instaConnectors.isConnector([connectGelatoProviderPayment.address])
|
||||||
|
).to.be.true;
|
||||||
|
|
||||||
|
// ========== Create DeFi Smart Account for User 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)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#1: payProvider should pay to Provider 300x10^18 token dai", async function () {
|
||||||
|
let providerDAIBalanceBefore = await daiToken.balanceOf(providerAddress);
|
||||||
|
|
||||||
|
await dsa.cast(
|
||||||
|
[bre.network.config.ConnectMaker],
|
||||||
|
[
|
||||||
|
await bre.run("abi-encode-withselector", {
|
||||||
|
abi: ConnectMaker.abi,
|
||||||
|
functionname: "open",
|
||||||
|
inputs: ["ETH-A"],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
userAddress
|
||||||
|
);
|
||||||
|
|
||||||
|
let cdps = await getCdps.getCdpsAsc(dssCdpManager.address, dsa.address);
|
||||||
|
cdpId = String(cdps.ids[0]);
|
||||||
|
|
||||||
|
expect(cdps.ids[0].isZero()).to.be.false;
|
||||||
|
|
||||||
|
await dsa.cast(
|
||||||
|
[bre.network.config.ConnectMaker],
|
||||||
|
[
|
||||||
|
await bre.run("abi-encode-withselector", {
|
||||||
|
abi: ConnectMaker.abi,
|
||||||
|
functionname: "deposit",
|
||||||
|
inputs: [cdpId, ethers.utils.parseEther("10"), 0, 0],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
userAddress,
|
||||||
|
{
|
||||||
|
value: ethers.utils.parseEther("10"),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
await dsa.cast(
|
||||||
|
[bre.network.config.ConnectMaker],
|
||||||
|
[
|
||||||
|
await bre.run("abi-encode-withselector", {
|
||||||
|
abi: ConnectMaker.abi,
|
||||||
|
functionname: "borrow",
|
||||||
|
inputs: [cdpId, ethers.utils.parseUnits("1000", 18), 0, 0],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
userAddress
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(await daiToken.balanceOf(dsa.address)).to.be.equal(
|
||||||
|
ethers.utils.parseEther("1000")
|
||||||
|
);
|
||||||
|
|
||||||
|
await dsa.cast(
|
||||||
|
[connectGelatoProviderPayment.address],
|
||||||
|
[
|
||||||
|
await bre.run("abi-encode-withselector", {
|
||||||
|
abi: ConnectGelatoProviderPaymentABI.abi,
|
||||||
|
functionname: "payProvider",
|
||||||
|
inputs: [
|
||||||
|
providerAddress,
|
||||||
|
daiToken.address,
|
||||||
|
ethers.utils.parseUnits("300", 18),
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
userAddress
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(await daiToken.balanceOf(providerAddress)).to.be.equal(
|
||||||
|
providerDAIBalanceBefore.add(ethers.utils.parseUnits("300", 18))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#2: payProvider should pay to Provider 1 ether", async function () {
|
||||||
|
let providerBalanceBefore = await providerWallet.getBalance();
|
||||||
|
|
||||||
|
await dsa.cast(
|
||||||
|
[connectBasic.address, connectGelatoProviderPayment.address],
|
||||||
|
[
|
||||||
|
await bre.run("abi-encode-withselector", {
|
||||||
|
abi: ConnectBasic.abi,
|
||||||
|
functionname: "deposit",
|
||||||
|
inputs: [
|
||||||
|
"0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
|
||||||
|
ethers.utils.parseEther("1"),
|
||||||
|
0,
|
||||||
|
"105",
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
await bre.run("abi-encode-withselector", {
|
||||||
|
abi: ConnectGelatoProviderPaymentABI.abi,
|
||||||
|
functionname: "payProvider",
|
||||||
|
inputs: [
|
||||||
|
providerAddress,
|
||||||
|
"0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
|
||||||
|
0,
|
||||||
|
"105",
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
userAddress,
|
||||||
|
{
|
||||||
|
value: ethers.utils.parseEther("1"),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(await providerWallet.getBalance()).to.be.equal(
|
||||||
|
providerBalanceBefore.add(ethers.utils.parseEther("1"))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#3: payProvider should return error message ConnectGelatoProviderPayment.payProvider:INVALIDADDESS when provider is Zero Address", async function () {
|
||||||
|
expect(
|
||||||
|
dsa.cast(
|
||||||
|
[connectBasic.address, connectGelatoProviderPayment.address],
|
||||||
|
[
|
||||||
|
await bre.run("abi-encode-withselector", {
|
||||||
|
abi: ConnectBasic.abi,
|
||||||
|
functionname: "deposit",
|
||||||
|
inputs: [
|
||||||
|
"0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
|
||||||
|
ethers.utils.parseEther("1"),
|
||||||
|
0,
|
||||||
|
"105",
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
await bre.run("abi-encode-withselector", {
|
||||||
|
abi: ConnectGelatoProviderPaymentABI.abi,
|
||||||
|
functionname: "payProvider",
|
||||||
|
inputs: [
|
||||||
|
ethers.constants.AddressZero,
|
||||||
|
"0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
|
||||||
|
0,
|
||||||
|
"105",
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
userAddress,
|
||||||
|
{
|
||||||
|
value: ethers.utils.parseEther("1"),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
).to.be.revertedWith(
|
||||||
|
"ConnectGelatoProviderPayment.payProvider:INVALIDADDESS."
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
51
test/5_OracleAggregator.test.js
Normal file
51
test/5_OracleAggregator.test.js
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
const {expect} = require("chai");
|
||||||
|
const bre = require("@nomiclabs/buidler");
|
||||||
|
const {ethers} = bre;
|
||||||
|
|
||||||
|
describe("Oracle Aggregator unit test", function () {
|
||||||
|
this.timeout(0);
|
||||||
|
if (bre.network.name !== "ganache") {
|
||||||
|
console.error("Test Suite is meant to be run on ganache only");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let oracleAggregator;
|
||||||
|
|
||||||
|
before(async function () {
|
||||||
|
const OracleAggregator = await ethers.getContractFactory(
|
||||||
|
"OracleAggregator"
|
||||||
|
);
|
||||||
|
oracleAggregator = await OracleAggregator.deploy();
|
||||||
|
oracleAggregator.deployed();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#1: addOracle should add a maker medianizer for a currencyPair", async function () {
|
||||||
|
await oracleAggregator.addOracle(
|
||||||
|
"ETH/USD",
|
||||||
|
"0x729D19f657BD0614b4985Cf1D82531c67569197B"
|
||||||
|
);
|
||||||
|
expect(await oracleAggregator.makerOracle("ETH/USD")).to.be.equal(
|
||||||
|
"0x729D19f657BD0614b4985Cf1D82531c67569197B"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#2: addOracle should revert when adding a maker medianizer and for this currency pair it was been already added", async function () {
|
||||||
|
expect(
|
||||||
|
oracleAggregator.addOracle(
|
||||||
|
"ETH/USD",
|
||||||
|
"0x729D19f657BD0614b4985Cf1D82531c67569197B"
|
||||||
|
)
|
||||||
|
).to.be.revertedWith("OracleAggregator.Maker: Oracle already set.");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#3: getMakerTokenPrice should return ETH/USD prize", async function () {
|
||||||
|
expect((await oracleAggregator.getMakerTokenPrice("ETH/USD")).isZero()).to
|
||||||
|
.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#4: getMakerTokenPrice should return OracleAggregator.getMakerTokenPrice: CurrencyPairNotSupported. when currencyPair are not supported / not been added", async function () {
|
||||||
|
expect(oracleAggregator.getMakerTokenPrice("ETH/DAI")).to.be.revertedWith(
|
||||||
|
"OracleAggregator.getMakerTokenPrice: CurrencyPairNotSupported."
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
195
test/6_ProviderModuleDSA.test.js
Normal file
195
test/6_ProviderModuleDSA.test.js
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
const {expect} = require("chai");
|
||||||
|
const bre = require("@nomiclabs/buidler");
|
||||||
|
const {ethers} = bre;
|
||||||
|
const GelatoCoreLib = require("@gelatonetwork/core");
|
||||||
|
|
||||||
|
// #region Contracts ABI
|
||||||
|
|
||||||
|
const ConnectAuth = require("../pre-compiles/ConnectAuth.json");
|
||||||
|
const InstaList = require("../pre-compiles/InstaList.json");
|
||||||
|
const InstaAccount = require("../pre-compiles/InstaAccount.json");
|
||||||
|
const InstaIndex = require("../pre-compiles/InstaIndex.json");
|
||||||
|
const InstaConnectors = require("../pre-compiles/InstaConnectors.json");
|
||||||
|
const ConnectGelatoProviderPaymentABI = require("../artifacts/ConnectGelatoProviderPayment.json");
|
||||||
|
|
||||||
|
const ETH = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
|
||||||
|
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
describe("Provider Module unit test", function () {
|
||||||
|
this.timeout(0);
|
||||||
|
if (bre.network.name !== "ganache") {
|
||||||
|
console.error("Test Suite is meant to be run on ganache only");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let providerModuleDSA;
|
||||||
|
let connectGelatoProviderPayment;
|
||||||
|
|
||||||
|
let instaIndex;
|
||||||
|
let gelatoCore;
|
||||||
|
let instaConnectors;
|
||||||
|
let instaList;
|
||||||
|
|
||||||
|
let userWallet;
|
||||||
|
let userAddress;
|
||||||
|
let providerWallet;
|
||||||
|
let providerAddress;
|
||||||
|
let dsa;
|
||||||
|
|
||||||
|
before(async function () {
|
||||||
|
// Get Test Wallet for local testnet
|
||||||
|
[userWallet] = await ethers.getSigners();
|
||||||
|
userAddress = await userWallet.getAddress();
|
||||||
|
|
||||||
|
[, providerWallet] = await ethers.getSigners();
|
||||||
|
providerAddress = await providerWallet.getAddress();
|
||||||
|
|
||||||
|
// Ganache default accounts prefilled with 100 ETH
|
||||||
|
expect(await userWallet.getBalance()).to.be.gt(
|
||||||
|
ethers.utils.parseEther("10")
|
||||||
|
);
|
||||||
|
/////////////////// Get Deployed Contract //////////////////
|
||||||
|
instaIndex = await ethers.getContractAt(
|
||||||
|
InstaIndex.abi,
|
||||||
|
bre.network.config.InstaIndex
|
||||||
|
);
|
||||||
|
instaConnectors = await ethers.getContractAt(
|
||||||
|
InstaConnectors.abi,
|
||||||
|
bre.network.config.InstaConnectors
|
||||||
|
);
|
||||||
|
gelatoCore = await ethers.getContractAt(
|
||||||
|
GelatoCoreLib.GelatoCore.abi,
|
||||||
|
bre.network.config.GelatoCore
|
||||||
|
);
|
||||||
|
instaList = await ethers.getContractAt(
|
||||||
|
InstaList.abi,
|
||||||
|
bre.network.config.InstaList
|
||||||
|
);
|
||||||
|
|
||||||
|
////////////////// Deploy Needed Contracts ////////////////////////
|
||||||
|
const connectorLength = await instaConnectors.connectorLength();
|
||||||
|
const connectorId = connectorLength.add(1);
|
||||||
|
|
||||||
|
const ConnectGelatoProviderPayment = await ethers.getContractFactory(
|
||||||
|
"ConnectGelatoProviderPayment"
|
||||||
|
);
|
||||||
|
connectGelatoProviderPayment = await ConnectGelatoProviderPayment.deploy(
|
||||||
|
connectorId
|
||||||
|
);
|
||||||
|
await connectGelatoProviderPayment.deployed();
|
||||||
|
|
||||||
|
const ProviderModuleDSA = await ethers.getContractFactory(
|
||||||
|
"ProviderModuleDSA"
|
||||||
|
);
|
||||||
|
providerModuleDSA = await ProviderModuleDSA.deploy(
|
||||||
|
instaIndex.address,
|
||||||
|
gelatoCore.address,
|
||||||
|
connectGelatoProviderPayment.address
|
||||||
|
);
|
||||||
|
await providerModuleDSA.deployed();
|
||||||
|
|
||||||
|
///////////////// Setup /////////////////////////
|
||||||
|
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)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Uncomment when ethers bug will be solved. revertedWith produce the following during call "AssertionError: Expected transaction to be reverted"
|
||||||
|
// it("isProvided should revert due to none listing of userProxy", async function () {
|
||||||
|
// expect(
|
||||||
|
// providerModuleDSA.isProvided(
|
||||||
|
// ethers.constants.AddressZero,
|
||||||
|
// ethers.constants.AddressZero,
|
||||||
|
// [[], [], 0, 0]
|
||||||
|
// )
|
||||||
|
// ).to.be.revertedWith("ProviderModuleDSA.isProvided:InvalidUserProxy");
|
||||||
|
// });
|
||||||
|
|
||||||
|
// it("isProvided should revert due to lack of right of gelatoCore to act on the dsa behalf", async function () {
|
||||||
|
// expect(
|
||||||
|
// providerModuleDSA.isProvided(
|
||||||
|
// dsa.address,
|
||||||
|
// ethers.constants.AddressZero,
|
||||||
|
// [[], [], 0, 0]
|
||||||
|
// )
|
||||||
|
// ).to.be.revertedWith("ProviderModuleDSA.isProvided:GelatoCoreNotAuth");
|
||||||
|
// });
|
||||||
|
|
||||||
|
it("#1: isProvided should return OK", async function () {
|
||||||
|
// Give authorization to Gelato on user DSA
|
||||||
|
await dsa.cast(
|
||||||
|
[bre.network.config.ConnectAuth],
|
||||||
|
[
|
||||||
|
await bre.run("abi-encode-withselector", {
|
||||||
|
abi: ConnectAuth.abi,
|
||||||
|
functionname: "add",
|
||||||
|
inputs: [gelatoCore.address],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
userAddress
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(await dsa.isAuth(gelatoCore.address)).to.be.true;
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await providerModuleDSA.isProvided(
|
||||||
|
dsa.address,
|
||||||
|
ethers.constants.AddressZero,
|
||||||
|
[[], [], 0, 0]
|
||||||
|
)
|
||||||
|
).to.be.equal("OK");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#2: execPayload should return payload with the right provider", async function () {
|
||||||
|
// Task creation for sending to execPayload
|
||||||
|
let payProvider = new GelatoCoreLib.Action({
|
||||||
|
addr: connectGelatoProviderPayment.address,
|
||||||
|
data: await bre.run("abi-encode-withselector", {
|
||||||
|
abi: ConnectGelatoProviderPaymentABI.abi,
|
||||||
|
functionname: "payProvider",
|
||||||
|
inputs: [ethers.constants.AddressZero, ETH, 0, "105", 0],
|
||||||
|
}),
|
||||||
|
operation: GelatoCoreLib.Operation.Delegatecall,
|
||||||
|
});
|
||||||
|
|
||||||
|
const task = new GelatoCoreLib.Task({
|
||||||
|
conditions: [],
|
||||||
|
actions: [payProvider],
|
||||||
|
});
|
||||||
|
|
||||||
|
let result = await providerModuleDSA.execPayload(
|
||||||
|
0,
|
||||||
|
ethers.constants.AddressZero,
|
||||||
|
providerAddress,
|
||||||
|
task,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
//#region retrieving the replaced provider address from the payload
|
||||||
|
let abi = new ethers.utils.AbiCoder();
|
||||||
|
|
||||||
|
let datas = abi.decode(
|
||||||
|
["address[]", "bytes[]", "address"],
|
||||||
|
ethers.utils.hexDataSlice(result.payload, 4)
|
||||||
|
)[1];
|
||||||
|
|
||||||
|
let paymentReceivingAddress = abi.decode(
|
||||||
|
["address", "address", "uint256", "uint256", "uint256"],
|
||||||
|
ethers.utils.hexDataSlice(datas[0], 4)
|
||||||
|
)[0];
|
||||||
|
//#endregion
|
||||||
|
expect(paymentReceivingAddress).to.be.equal(providerAddress);
|
||||||
|
});
|
||||||
|
});
|
141
test/7_ConnectGelatoDebtBridge.test.js
Normal file
141
test/7_ConnectGelatoDebtBridge.test.js
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
const {expect} = require("chai");
|
||||||
|
const bre = require("@nomiclabs/buidler");
|
||||||
|
const {ethers} = bre;
|
||||||
|
|
||||||
|
const WAD = ethers.utils.parseUnits("1", 18);
|
||||||
|
|
||||||
|
//#region DSMath function
|
||||||
|
|
||||||
|
let wdiv = (x, y) => {
|
||||||
|
return x.mul(WAD).add(y.div(2)).div(y);
|
||||||
|
};
|
||||||
|
|
||||||
|
let wmul = (x, y) => {
|
||||||
|
return x.mul(y).add(WAD.div(2)).div(WAD);
|
||||||
|
};
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
describe("Gelato Debt Bridge Connector unit test", function () {
|
||||||
|
this.timeout(0);
|
||||||
|
if (bre.network.name !== "ganache") {
|
||||||
|
console.error("Test Suite is meant to be run on ganache only");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let connectGelatoDebtBridge;
|
||||||
|
before(async function () {
|
||||||
|
const ConnectGelatoDebtBridge = await ethers.getContractFactory(
|
||||||
|
"ConnectGelatoDebtBridgeMock"
|
||||||
|
);
|
||||||
|
connectGelatoDebtBridge = await ConnectGelatoDebtBridge.deploy(
|
||||||
|
0,
|
||||||
|
ethers.constants.AddressZero
|
||||||
|
);
|
||||||
|
connectGelatoDebtBridge.deployed();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#1: _wcollateralToWithdraw should return the amount of collateral to withdraw on protocol 1 and to put on protocol 2", async function () {
|
||||||
|
// 3 times more collateral than borrowed amount in protocol 1
|
||||||
|
let wantedLiquidationRatioOnProtocol1 = ethers.utils.parseUnits("3", 18);
|
||||||
|
// 1.5 times more collateral than borrowed amount in protocol 2
|
||||||
|
let wantedLiquidationRatioOnProtocol2 = ethers.utils.parseUnits("15", 17);
|
||||||
|
// The amount of collateral locked
|
||||||
|
let col = ethers.utils.parseUnits("1", 18);
|
||||||
|
// The amount of borrowed token
|
||||||
|
let borrowedToken = ethers.utils.parseUnits("100", 18);
|
||||||
|
// how much one collateral is worth on borrowed token
|
||||||
|
let collateralPrice = ethers.utils.parseUnits("250", 18);
|
||||||
|
// the amount of collateral in borrowed token
|
||||||
|
let collateral = col
|
||||||
|
.mul(collateralPrice)
|
||||||
|
.div(ethers.utils.parseUnits("1", 18)); // div to have everything in wad standard
|
||||||
|
|
||||||
|
// Check this document https://drive.google.com/file/d/1OV3ZbJPd2Yr-3l0rst6tK3ycfhhg6Nfh/view?usp=sharing for more details one the used formula
|
||||||
|
|
||||||
|
//#region CALCULATION REPLICATION
|
||||||
|
|
||||||
|
let expectedColToWithdraw = wmul(
|
||||||
|
wmul(
|
||||||
|
wantedLiquidationRatioOnProtocol1,
|
||||||
|
wantedLiquidationRatioOnProtocol2
|
||||||
|
),
|
||||||
|
borrowedToken
|
||||||
|
); // doc ref : c_r x comp_r x d_2
|
||||||
|
expectedColToWithdraw = expectedColToWithdraw.sub(
|
||||||
|
wmul(wantedLiquidationRatioOnProtocol1, collateral)
|
||||||
|
); // doc ref : c_r x comp_r x d_2 - c_r x e_2
|
||||||
|
expectedColToWithdraw = wdiv(
|
||||||
|
expectedColToWithdraw,
|
||||||
|
wantedLiquidationRatioOnProtocol2.sub(wantedLiquidationRatioOnProtocol1)
|
||||||
|
); // doc ref : (c_r x comp_r x d_2 - c_r x e_2)/ (comp_r - c_r)
|
||||||
|
expectedColToWithdraw = collateral.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
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await connectGelatoDebtBridge.wcollateralToWithdraw(
|
||||||
|
wantedLiquidationRatioOnProtocol1,
|
||||||
|
wantedLiquidationRatioOnProtocol2,
|
||||||
|
collateral,
|
||||||
|
borrowedToken,
|
||||||
|
collateralPrice
|
||||||
|
)
|
||||||
|
).to.be.equal(expectedColToWithdraw);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#2: _wborrowedTokenToPayback should return the amount of borrowed token to pay back on protocol 1", async function () {
|
||||||
|
// 3 times more collateral than borrowed amount in protocol 1
|
||||||
|
let wantedLiquidationRatioOnProtocol1 = ethers.utils.parseUnits("3", 18);
|
||||||
|
// 1.5 times more collateral than borrowed amount in protocol 2
|
||||||
|
let wantedLiquidationRatioOnProtocol2 = ethers.utils.parseUnits("15", 17);
|
||||||
|
// The amount of collateral locked
|
||||||
|
let col = ethers.utils.parseUnits("1", 18);
|
||||||
|
// The amount of borrowed token
|
||||||
|
let borrowedToken = ethers.utils.parseUnits("100", 18);
|
||||||
|
// how much one collateral is worth on borrowed token
|
||||||
|
let collateralPrice = ethers.utils.parseUnits("250", 18);
|
||||||
|
// the amount of collateral in borrowed token
|
||||||
|
let collateral = col
|
||||||
|
.mul(collateralPrice)
|
||||||
|
.div(ethers.utils.parseUnits("1", 18)); // div to have everything in wad standard
|
||||||
|
|
||||||
|
// Check this document https://drive.google.com/file/d/1OV3ZbJPd2Yr-3l0rst6tK3ycfhhg6Nfh/view?usp=sharing for more details one the used formula
|
||||||
|
|
||||||
|
//#region CALCULATION REPLICATION
|
||||||
|
|
||||||
|
let expectedBorToPayBack = wmul(
|
||||||
|
wmul(
|
||||||
|
wantedLiquidationRatioOnProtocol1,
|
||||||
|
wantedLiquidationRatioOnProtocol2
|
||||||
|
),
|
||||||
|
borrowedToken
|
||||||
|
); // doc ref : c_r x comp_r x d_2
|
||||||
|
expectedBorToPayBack = expectedBorToPayBack.sub(
|
||||||
|
wmul(wantedLiquidationRatioOnProtocol1, collateral)
|
||||||
|
); // doc ref : c_r x comp_r x d_2 - c_r x e_2
|
||||||
|
expectedBorToPayBack = wdiv(
|
||||||
|
expectedBorToPayBack,
|
||||||
|
wantedLiquidationRatioOnProtocol2.sub(wantedLiquidationRatioOnProtocol1)
|
||||||
|
); // 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), wantedLiquidationRatioOnProtocol1),
|
||||||
|
expectedBorToPayBack
|
||||||
|
); // doc ref : (1/c_r)((c_r x comp_r x d_2 - c_r x e_2)/ (comp_r - c_r))
|
||||||
|
expectedBorToPayBack = borrowedToken.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
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await connectGelatoDebtBridge.wborrowedTokenToPayback(
|
||||||
|
wantedLiquidationRatioOnProtocol1,
|
||||||
|
wantedLiquidationRatioOnProtocol2,
|
||||||
|
collateral,
|
||||||
|
borrowedToken
|
||||||
|
)
|
||||||
|
).to.be.equal(expectedBorToPayBack);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user