add test for instadapp event return values. address PR comments:

- add setUints to all applicable functions
    - use uint256 rather than uint for event data
This commit is contained in:
Edward Mulraney 2021-06-04 12:18:16 +01:00
parent ec8fd393a1
commit 97db94fe59
6 changed files with 1844 additions and 986 deletions

View File

@ -28,15 +28,15 @@ contract Events {
uint getRepayId,
uint setBorrowId
);
event LogClaimCollateralFromRedemption(address indexed borrower);
event LogClaimCollateralFromRedemption(address indexed borrower, uint amount, uint setId);
/* Stability Pool */
event LogStabilityDeposit(address indexed borrower, uint amount, address frontendTag, uint getId);
event LogStabilityWithdraw(address indexed borrower, uint amount, uint setId);
event LogStabilityMoveEthGainToTrove(address indexed borrower);
event LogStabilityMoveEthGainToTrove(address indexed borrower, uint amount);
/* Staking */
event LogStake(address indexed borrower, uint amount, uint getId);
event LogUnstake(address indexed borrower, uint amount, uint setId);
event LogClaimGains(address indexed borrower);
event LogClaimStakingGains(address indexed borrower, uint ethAmount, uint lusdAmount);
}

View File

@ -52,9 +52,16 @@ interface StabilityPoolLike {
function provideToSP(uint _amount, address _frontEndTag) external;
function withdrawFromSP(uint _amount) external;
function withdrawETHGainToTrove(address _upperHint, address _lowerHint) external;
function getDepositorETHGain(address _depositor) external view returns (uint);
}
interface StakingLike {
function stake(uint _LQTYamount) external;
function unstake(uint _LQTYamount) external;
function getPendingETHGain(address _user) external view returns (uint);
function getPendingLUSDGain(address _user) external view returns (uint);
}
interface CollateralSurplusLike {
function getCollateral(address _account) external view returns (uint);
}

View File

@ -4,12 +4,17 @@ pragma solidity ^0.7.6;
* @title Liquity.
* @dev Lending & Borrowing.
*/
import "hardhat/console.sol";
import { BorrowerOperationsLike, TroveManagerLike, StabilityPoolLike, StakingLike } from "./interface.sol";
import {
BorrowerOperationsLike,
TroveManagerLike,
StabilityPoolLike,
StakingLike,
CollateralSurplusLike
} from "./interface.sol";
import { Stores } from "../../common/stores.sol";
import { Helpers } from "./helpers.sol";
import { Events } from "./events.sol";
import "hardhat/console.sol";
abstract contract LiquityResolver is Events, Helpers {
BorrowerOperationsLike internal constant borrowerOperations =
@ -20,7 +25,10 @@ abstract contract LiquityResolver is Events, Helpers {
StabilityPoolLike(0x66017D22b0f8556afDd19FC67041899Eb65a21bb);
StakingLike internal constant staking =
StakingLike(0x4f9Fbb3f1E99B56e0Fe2892e623Ed36A76Fc605d);
CollateralSurplusLike internal constant collateralSurplus =
CollateralSurplusLike(0x3D32e8b97Ed5881324241Cf03b2DA5E2EBcE5521);
// Prevents stack-too-deep error
struct AdjustTrove {
uint maxFeePercentage;
uint withdrawAmount;
@ -30,10 +38,6 @@ abstract contract LiquityResolver is Events, Helpers {
bool isBorrow;
}
constructor() {
console.log("Liquity Connector contract deployed at", address(this));
}
/* Begin: Trove */
/**
@ -56,7 +60,17 @@ abstract contract LiquityResolver is Events, Helpers {
uint getId,
uint setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
// User can either send ETH directly or have it collected from a previous spell
/*
User has three options for depositing ETH collateral to open a Trove:
- Send ETH directly with this function call
- Have ETH collected from a previous spell
- Have ETH collected from the DSA's existing balance
*/
if (getId != 0 && depositAmount != 0) {
revert("open(): Cannot supply a depositAmount if a non-zero getId is supplied");
}
depositAmount = getUint(getId, depositAmount);
borrowerOperations.openTrove{value: depositAmount}(
@ -68,7 +82,7 @@ abstract contract LiquityResolver is Events, Helpers {
// Allow other spells to use the borrowed amount
setUint(setId, borrowAmount);
_eventName = "LogOpen(address,uint,uint,uint,uint,uint)";
_eventName = "LogOpen(address,uint256,uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(msg.sender, maxFeePercentage, depositAmount, borrowAmount, getId, setId);
}
@ -83,7 +97,7 @@ abstract contract LiquityResolver is Events, Helpers {
// Allow other spells to use the collateral released from the Trove
setUint(setId, collateral);
_eventName = "LogClose(address,uint)";
_eventName = "LogClose(address,uint256)";
_eventParam = abi.encode(msg.sender, setId);
}
@ -101,9 +115,12 @@ abstract contract LiquityResolver is Events, Helpers {
address lowerHint,
uint getId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
if (getId != 0 && amount != 0) {
revert("deposit(): Cannot supply an amount if a non-zero getId is supplied");
}
amount = getUint(getId, amount);
borrowerOperations.addColl{value: amount}(upperHint, lowerHint);
_eventName = "LogDeposit(address,uint,uint)";
_eventName = "LogDeposit(address,uint256,uint256)";
_eventParam = abi.encode(msg.sender, amount, getId);
}
@ -124,7 +141,7 @@ abstract contract LiquityResolver is Events, Helpers {
borrowerOperations.withdrawColl(amount, upperHint, lowerHint);
setUint(setId, amount);
_eventName = "LogWithdraw(address,uint,uint)";
_eventName = "LogWithdraw(address,uint256,uint256)";
_eventParam = abi.encode(msg.sender, amount, setId);
}
@ -147,7 +164,7 @@ abstract contract LiquityResolver is Events, Helpers {
borrowerOperations.withdrawLUSD(maxFeePercentage, amount, upperHint, lowerHint);
setUint(setId, amount); // TODO: apply fee / get exact amount borrowed (with the fee applied)
_eventName = "LogBorrow(address,uint,uint)";
_eventName = "LogBorrow(address,uint256,uint256)";
_eventParam = abi.encode(msg.sender, amount, setId);
}
@ -165,9 +182,12 @@ abstract contract LiquityResolver is Events, Helpers {
address lowerHint,
uint getId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
if (getId != 0 && amount != 0) {
revert("repay(): Cannot supply an amount if a non-zero getId is supplied");
}
amount = getUint(getId, amount);
borrowerOperations.repayLUSD(amount, upperHint, lowerHint);
_eventName = "LogRepay(address,uint,uint)";
_eventName = "LogRepay(address,uint256,uint256)";
_eventParam = abi.encode(msg.sender, amount, getId);
}
@ -199,6 +219,13 @@ abstract contract LiquityResolver is Events, Helpers {
uint getRepayId,
uint setBorrowId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
if (getDepositId != 0 && depositAmount != 0) {
revert("adjust(): Cannot supply a depositAmount if a non-zero getDepositId is supplied");
}
if (getRepayId != 0 && repayAmount != 0) {
revert("adjust(): Cannot supply a repayAmount if a non-zero getRepayId is supplied");
}
AdjustTrove memory adjustTrove;
adjustTrove.maxFeePercentage = maxFeePercentage;
@ -223,18 +250,22 @@ abstract contract LiquityResolver is Events, Helpers {
// Allow other spells to use the borrowed amount
setUint(setBorrowId, borrowAmount);
_eventName = "LogAdjust(address,uint,uint,uint,uint,uint,uint,uint,uint,uint)";
_eventParam = abi.encode(msg.sender, maxFeePercentage, depositAmount, borrowAmount, getDepositId, setWithdrawId, getRepayId, setBorrowId);
_eventName = "LogAdjust(address,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(msg.sender, maxFeePercentage, depositAmount, withdrawAmount, borrowAmount, repayAmount, getDepositId, setWithdrawId, getRepayId, setBorrowId);
}
/**
* @dev Withdraw remaining ETH balance from user's redeemed Trove to their DSA
* @param setId Optional storage slot to store the ETH claimed
* @notice Claim remaining collateral from Trove
*/
function claimCollateralFromRedemption() external returns(string memory _eventName, bytes memory _eventParam) {
function claimCollateralFromRedemption(uint setId) external returns(string memory _eventName, bytes memory _eventParam) {
uint amount = collateralSurplus.getCollateral(address(this));
borrowerOperations.claimCollateral();
_eventName = "LogClaimCollateralFromRedemption(address)";
_eventParam = abi.encode(msg.sender);
setUint(setId, amount);
_eventName = "LogClaimCollateralFromRedemption(address,uint256,uint256)";
_eventParam = abi.encode(msg.sender, amount, setId);
}
/* End: Trove */
@ -256,7 +287,7 @@ abstract contract LiquityResolver is Events, Helpers {
stabilityPool.provideToSP(amount, frontendTag);
_eventName = "LogStabilityDeposit(address,uint,address,uint)";
_eventName = "LogStabilityDeposit(address,uint256,address,uint256)";
_eventParam = abi.encode(msg.sender, amount, frontendTag, getId);
}
@ -273,7 +304,7 @@ abstract contract LiquityResolver is Events, Helpers {
stabilityPool.withdrawFromSP(amount);
setUint(setId, amount);
_eventName = "LogStabilityWithdraw(address,uint,uint)";
_eventName = "LogStabilityWithdraw(address,uint256,uint256)";
_eventParam = abi.encode(msg.sender, amount, setId);
}
@ -287,10 +318,10 @@ abstract contract LiquityResolver is Events, Helpers {
address upperHint,
address lowerHint
) external returns (string memory _eventName, bytes memory _eventParam) {
uint amount = stabilityPool.getDepositorETHGain(address(this));
stabilityPool.withdrawETHGainToTrove(upperHint, lowerHint);
_eventName = "LogStabilityMoveEthGainToTrove(address)";
_eventParam = abi.encode(msg.sender);
_eventName = "LogStabilityMoveEthGainToTrove(address,uint256)";
_eventParam = abi.encode(msg.sender, amount);
}
/* End: Stability Pool */
@ -308,7 +339,7 @@ abstract contract LiquityResolver is Events, Helpers {
) external returns (string memory _eventName, bytes memory _eventParam) {
amount = getUint(getId, amount);
staking.stake(amount);
_eventName = "LogStake(address,uint,uint)";
_eventName = "LogStake(address,uint256,uint256)";
_eventParam = abi.encode(msg.sender, amount, getId);
}
@ -324,19 +355,27 @@ abstract contract LiquityResolver is Events, Helpers {
) external returns (string memory _eventName, bytes memory _eventParam) {
staking.unstake(amount);
setUint(setId, amount);
_eventName = "LogUnstake(address,uint,uint)";
_eventName = "LogUnstake(address,uint256,uint256)";
_eventParam = abi.encode(msg.sender, amount, setId);
}
/**
* @dev Sends ETH and LUSD gains from Staking to user
* @notice Claim ETH and LUSD gains from Staking
* @param setEthGainId Optional storage slot to store the claimed ETH
* @param setLusdGainId Optional storage slot to store the claimed LUSD
*/
function claimGains() external returns (string memory _eventName, bytes memory _eventParam) {
// claims are gained when a user's stake is adjusted, so we unstake 0 to trigger the claim
staking.unstake(0);
_eventName = "LogClaimGains(address)";
_eventParam = abi.encode(msg.sender);
function claimStakingGains(uint setEthGainId, uint setLusdGainId) external returns (string memory _eventName, bytes memory _eventParam) {
uint ethAmount = staking.getPendingETHGain(address(this));
uint lusdAmount = staking.getPendingLUSDGain(address(this));
// Gains are claimed when a user's stake is adjusted, so we unstake 0 to trigger the claim
staking.unstake(0);
setUint(setEthGainId, ethAmount);
setUint(setLusdGainId, lusdAmount);
_eventName = "LogClaimStakingGains(address,uint256,uint256)";
_eventParam = abi.encode(msg.sender, ethAmount, lusdAmount);
}
/* End: Staking */

View File

@ -60,6 +60,11 @@ const LQTY_TOKEN_ABI = [
"function transfer(address _to, uint256 _value) public returns (bool success)",
];
const COLL_SURPLUS_ADDRESS = "0x3D32e8b97Ed5881324241Cf03b2DA5E2EBcE5521";
const COLL_SURPLUS_ABI = [
"function getCollateral(address _account) external view returns (uint)",
];
module.exports = {
TROVE_MANAGER_ADDRESS,
TROVE_MANAGER_ABI,
@ -81,4 +86,6 @@ module.exports = {
STAKING_ABI,
LQTY_TOKEN_ADDRESS,
LQTY_TOKEN_ABI,
COLL_SURPLUS_ADDRESS,
COLL_SURPLUS_ABI,
};

View File

@ -5,6 +5,7 @@ const hardhatConfig = require("../../hardhat.config");
const deployAndEnableConnector = require("../../scripts/deployAndEnableConnector.js");
const encodeSpells = require("../../scripts/encodeSpells.js");
const getMasterSigner = require("../../scripts/getMasterSigner");
const buildDSAv2 = require("../../scripts/buildDSAv2");
// Instadapp instadappAddresses/ABIs
const instadappAddresses = require("../../scripts/constant/addresses");
@ -13,12 +14,13 @@ const instadappAbi = require("../../scripts/constant/abis");
// Instadapp Liquity Connector artifacts
const connectV2LiquityArtifacts = require("../../artifacts/contracts/mainnet/connectors/liquity/main.sol/ConnectV2Liquity.json");
const connectV2BasicV1Artifacts = require("../../artifacts/contracts/mainnet/connectors/basic/main.sol/ConnectV2Basic.json");
const { ethers } = require("hardhat");
const CONNECTOR_NAME = "LIQUITY-v1-TEST";
const LUSD_GAS_COMPENSATION = hre.ethers.utils.parseUnits("200", 18); // 200 LUSD gas compensation repaid after loan repayment
const BLOCK_NUMBER = 12478159; // Deterministic block number for tests to run against, if you change this, tests will break.
const LIQUIDATABLE_TROVES_BLOCK_NUMBER = 12478159; // Deterministic block number for tests to run against, if you change this, tests will break.
const JUSTIN_SUN_ADDRESS = "0x903d12bf2c57a29f32365917c706ce0e1a84cce3"; // LQTY whale address
const LIQUIDATABLE_TROVE_ADDRESS = "0xafbeb4cb97f3b08ec2fe07ef0dac15d37013a347"; // Trove which is liquidatable at blockNumber: BLOCK_NUMBER
const LIQUIDATABLE_TROVE_ADDRESS = "0xafbeb4cb97f3b08ec2fe07ef0dac15d37013a347"; // Trove which is liquidatable at blockNumber: LIQUIDATABLE_TROVES_BLOCK_NUMBER
const MAX_GAS = hardhatConfig.networks.hardhat.blockGasLimit; // Maximum gas limit (12000000)
const openTroveSpell = async (
@ -48,12 +50,11 @@ const openTroveSpell = async (
0,
],
};
const openTx = await dsa
return await dsa
.connect(signer)
.cast(...encodeSpells([openTroveSpell]), address, {
value: depositAmount,
});
return await openTx.wait();
};
const createDsaTrove = async (
@ -92,6 +93,13 @@ const sendToken = async (token, amount, from, to) => {
return await token.connect(signer).transfer(to, amount);
};
const resetInitialState = async (walletAddress, contracts, isDebug = false) => {
const liquity = await deployAndConnect(contracts, isDebug);
const dsa = await buildDSAv2(walletAddress);
return [liquity, dsa];
};
const resetHardhatBlockNumber = async (blockNumber) => {
return await hre.network.provider.request({
method: "hardhat_reset",
@ -108,7 +116,7 @@ const resetHardhatBlockNumber = async (blockNumber) => {
const deployAndConnect = async (contracts, isDebug = false) => {
// Pin Liquity tests to a particular block number to create deterministic state (Ether price etc.)
await resetHardhatBlockNumber(BLOCK_NUMBER);
await resetHardhatBlockNumber(LIQUIDATABLE_TROVES_BLOCK_NUMBER);
const liquity = {
troveManager: null,
@ -121,6 +129,7 @@ const deployAndConnect = async (contracts, isDebug = false) => {
hintHelpers: null,
sortedTroves: null,
staking: null,
collSurplus: null,
};
const masterSigner = await getMasterSigner();
@ -230,6 +239,14 @@ const deployAndConnect = async (contracts, isDebug = false) => {
);
isDebug && console.log("Staking contract address", liquity.staking.address);
liquity.collSurplus = new ethers.Contract(
contracts.COLL_SURPLUS_ADDRESS,
contracts.COLL_SURPLUS_ABI,
ethers.provider
);
isDebug &&
console.log("CollSurplus contract address", liquity.collSurplus.address);
return liquity;
};
@ -310,18 +327,48 @@ const getRedemptionHints = async (
};
};
const redeem = async (amount, from, to, liquity) => {
await sendToken(liquity.lusdToken, amount, from, to);
const {
partialRedemptionHintNicr,
firstRedemptionHint,
upperHint,
lowerHint,
} = await getRedemptionHints(
amount,
liquity.hintHelpers,
liquity.sortedTroves,
liquity.priceFeed
);
const maxFeePercentage = ethers.utils.parseUnits("0.5", 18); // 0.5% max fee
return await liquity.troveManager
.connect(wallet)
.redeemCollateral(
amount,
firstRedemptionHint,
upperHint,
lowerHint,
partialRedemptionHintNicr,
0,
maxFeePercentage,
{
gasLimit: MAX_GAS, // permit max gas
}
);
};
module.exports = {
deployAndConnect,
resetInitialState,
createDsaTrove,
openTroveSpell,
sendToken,
getTroveInsertionHints,
getRedemptionHints,
redeem,
CONNECTOR_NAME,
LUSD_GAS_COMPENSATION,
BLOCK_NUMBER,
JUSTIN_SUN_ADDRESS,
LIQUIDATABLE_TROVE_ADDRESS,
MAX_GAS,
resetHardhatBlockNumber,
getTroveInsertionHints,
getRedemptionHints,
};

File diff suppressed because it is too large Load Diff