Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🦟 Add whitelist to liquidations #7

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions contracts/Interfaces/IVesselManagerOperations.sol
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ interface IVesselManagerOperations is ITrinityBase {
error VesselManagerOperations__VesselNotActive();
error VesselManagerOperations__InvalidParam();
error VesselManagerOperations__NotTimelock();
error VesselManagerOperations__LiquidatorNotWhitelisted();

// Structs ----------------------------------------------------------------------------------------------------------

Expand Down
12 changes: 11 additions & 1 deletion contracts/VesselManagerOperations.sol
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ contract VesselManagerOperations is IVesselManagerOperations, UUPSUpgradeable, R
* starting from the one with the lowest collateral ratio in the system, and moving upwards.
*/
function liquidateVessels(address _asset, uint256 _n) external override nonReentrant {
if (!IAdminContract(adminContract).getRedeemerIsWhitelisted(msg.sender)) {
revert VesselManagerOperations__LiquidatorNotWhitelisted();
}

LocalVariables_OuterLiquidationFunction memory vars;
LiquidationTotals memory totals;
vars.price = IPriceFeed(priceFeed).fetchPrice(_asset);
Expand Down Expand Up @@ -110,6 +114,9 @@ contract VesselManagerOperations is IVesselManagerOperations, UUPSUpgradeable, R
* Attempt to liquidate a custom list of vessels provided by the caller.
*/
function batchLiquidateVessels(address _asset, address[] memory _vesselArray) public override nonReentrant {
if (!IAdminContract(adminContract).getRedeemerIsWhitelisted(msg.sender)) {
revert VesselManagerOperations__LiquidatorNotWhitelisted();
}
if (_vesselArray.length == 0 || _vesselArray.length > BATCH_SIZE_LIMIT) {
revert VesselManagerOperations__InvalidArraySize();
}
Expand Down Expand Up @@ -870,7 +877,10 @@ contract VesselManagerOperations is IVesselManagerOperations, UUPSUpgradeable, R
uint256 _price
) internal view {
address redeemer = msg.sender;
require(IAdminContract(adminContract).getRedeemerIsWhitelisted(redeemer), "VesselManagerOperations: Redeemer not whitelisted");
require(
IAdminContract(adminContract).getRedeemerIsWhitelisted(redeemer),
"VesselManagerOperations: Redeemer not whitelisted"
);

uint256 redemptionBlockTimestamp = IAdminContract(adminContract).getRedemptionBlockTimestamp(_asset);
if (redemptionBlockTimestamp > block.timestamp) {
Expand Down
6 changes: 5 additions & 1 deletion test/trinity/BorrowerOperationsTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ const deploy = async (treasury, mintingAccounts) => {
vesselManagerOperations = contracts.core.vesselManagerOperations
shortTimelock = contracts.core.shortTimelock
longTimelock = contracts.core.longTimelock

for(const account of mintingAccounts) {
await adminContract.setWhitelistedRedeemer(account, true)
}
}

contract("BorrowerOperations", async accounts => {
Expand All @@ -60,7 +64,7 @@ contract("BorrowerOperations", async accounts => {

describe("BorrowerOperations Mechanisms", async () => {
before(async () => {
await deploy(treasury, [])
await deploy(treasury, accounts.slice(0, 20))

TRI_GAS_COMPENSATION_ERC20 = await adminContract.getDebtTokenGasCompensation(erc20.address)
MIN_NET_DEBT_ERC20 = await adminContract.getMinNetDebt(erc20.address)
Expand Down
4 changes: 4 additions & 0 deletions test/trinity/GasCompensationTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ const deploy = async (treasury, mintingAccounts) => {
longTimelock = contracts.core.longTimelock

validCollateral = await adminContract.getValidCollateral()

for(const account of mintingAccounts) {
await adminContract.setWhitelistedRedeemer(account, true)
}
}

contract("Gas compensation tests", async accounts => {
Expand Down
4 changes: 4 additions & 0 deletions test/trinity/StabilityPoolTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ const deploy = async (treasury, mintingAccounts) => {

// getDepositorGains() expects a sorted collateral array
validCollateral = validCollateral.slice(0).sort((a, b) => toBN(a.toLowerCase()).sub(toBN(b.toLowerCase())))

for(const account of mintingAccounts) {
await adminContract.setWhitelistedRedeemer(account, true)
}
}

contract("StabilityPool", async accounts => {
Expand Down
65 changes: 48 additions & 17 deletions test/trinity/VesselManagerTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ const deploy = async (treasury, mintingAccounts) => {

// getDepositorGains() expects a sorted collateral array
validCollateral = validCollateral.slice(0).sort((a, b) => toBN(a.toLowerCase()).sub(toBN(b.toLowerCase())))

for(const account of mintingAccounts) {
await adminContract.setWhitelistedRedeemer(account, true)
}
}

/* NOTE: Some tests involving ETH redemption fees do not test for specific fee values.
Expand Down Expand Up @@ -126,6 +130,24 @@ contract("VesselManager", async accounts => {
})

describe("Liquidations", async () => {
it("liquidate(): reverts when not whitelisted", async () => {
await openVessel({
asset: erc20.address,
ICR: toBN(dec(4, 18)),
extraParams: { from: alice },
})

await adminContract.setWhitelistedRedeemer(alice, false)

try {
const tx = await vesselManagerOperations.liquidate(erc20.address, alice, {from: alice})
assert.isFalse(tx.receipt.status)
} catch (err) {
assert.include(err.message, "revert")
assert.include(err.message, "VesselManagerOperations__LiquidatorNotWhitelisted()")
}
})

it("liquidate(): closes a Vessel that has ICR < MCR", async () => {
await openVessel({
asset: erc20.address,
Expand Down Expand Up @@ -1412,6 +1434,19 @@ contract("VesselManager", async accounts => {

// --- liquidateVessels() ---

it("liquidateVessels(): reverts when not whitelisted", async () => {
await adminContract.setWhitelistedRedeemer(alice, false)

try {
const tx = await vesselManagerOperations.liquidateVessels(erc20.address, 2, {from: alice})
assert.isFalse(tx.receipt.status)
} catch (err) {
console.log(err.message)
nezouse marked this conversation as resolved.
Show resolved Hide resolved
assert.include(err.message, "revert")
assert.include(err.message, "VesselManagerOperations__LiquidatorNotWhitelisted()")
}
})

it("liquidateVessels(): liquidates a Vessel that a) was skipped in a previous liquidation and b) has pending rewards", async () => {
// A, B, C, D, E open vessels

Expand Down Expand Up @@ -2442,6 +2477,19 @@ contract("VesselManager", async accounts => {
// --- batchLiquidateVessels() ---

describe("Batch Liquidations", async () => {
it("batchLiquidateVessels(): reverts when not whitelisted", async () => {
await adminContract.setWhitelistedRedeemer(alice, false)

try {
const tx = await vesselManagerOperations.batchLiquidateVessels(erc20.address, [], {from: alice})
assert.isFalse(tx.receipt.status)
} catch (err) {
console.log(err.message)
nezouse marked this conversation as resolved.
Show resolved Hide resolved
assert.include(err.message, "revert")
assert.include(err.message, "VesselManagerOperations__LiquidatorNotWhitelisted()")
}
})

it("batchLiquidateVessels(): liquidates a Vessel that a) was skipped in a previous liquidation and b) has pending rewards", async () => {
// A, B, C, D, E open vessels

Expand Down Expand Up @@ -3223,7 +3271,6 @@ contract("VesselManager", async accounts => {
// skip redemption
await time.increase(redemptionWait)

await adminContract.setWhitelistedRedeemer(dennis, true)
// this time tx should succeed
await vesselManagerOperations.redeemCollateral(
erc20.address,
Expand Down Expand Up @@ -3292,7 +3339,6 @@ contract("VesselManager", async accounts => {
// Dennis redeems 20 debt tokens
// Don't pay for gas, as it makes it easier to calculate the received collateral

await adminContract.setWhitelistedRedeemer(dennis, true)
const redemptionTx = await vesselManagerOperations.redeemCollateral(
erc20.address,
redemptionAmount,
Expand Down Expand Up @@ -3393,7 +3439,6 @@ contract("VesselManager", async accounts => {
// skip redemption bootstrapping phase
await th.fastForwardTime(timeValues.SECONDS_IN_ONE_WEEK * 2, web3.currentProvider)

await adminContract.setWhitelistedRedeemer(dennis, true)
// Dennis redeems 20 debt tokens
const redemptionTx = await vesselManagerOperations.redeemCollateral(
erc20.address,
Expand Down Expand Up @@ -3494,7 +3539,6 @@ contract("VesselManager", async accounts => {
// skip redemption bootstrapping phase
await th.fastForwardTime(timeValues.SECONDS_IN_ONE_WEEK * 2, web3.currentProvider)

await adminContract.setWhitelistedRedeemer(dennis, true)
// Dennis redeems 20 debt tokens
const redemptionTx = await vesselManagerOperations.redeemCollateral(
erc20.address,
Expand Down Expand Up @@ -3607,7 +3651,6 @@ contract("VesselManager", async accounts => {
// Dennis redeems 20 debt tokens
// Don't pay for gas, as it makes it easier to calculate the received Ether

await adminContract.setWhitelistedRedeemer(dennis, true)
const redemptionTx = await vesselManagerOperations.redeemCollateral(
erc20.address,
redemptionAmount,
Expand Down Expand Up @@ -3705,7 +3748,6 @@ contract("VesselManager", async accounts => {
// skip redemption bootstrapping phase
await th.fastForwardTime(timeValues.SECONDS_IN_ONE_WEEK * 2, web3.currentProvider)

await adminContract.setWhitelistedRedeemer(flyn, true)
// Flyn redeems collateral
await vesselManagerOperations.redeemCollateral(
erc20.address,
Expand Down Expand Up @@ -3802,7 +3844,6 @@ contract("VesselManager", async accounts => {

// Flyn redeems collateral with only two iterations

await adminContract.setWhitelistedRedeemer(flyn, true)
await vesselManagerOperations.redeemCollateral(
erc20.address,
attemptedRedemptionAmount_Asset,
Expand Down Expand Up @@ -3996,7 +4037,6 @@ contract("VesselManager", async accounts => {
// skip redemption bootstrapping phase
await th.fastForwardTime(timeValues.SECONDS_IN_ONE_WEEK * 2, web3.currentProvider)

await adminContract.setWhitelistedRedeemer(alice, true)
// Alice redeems 1 debt token from Carol's Vessel
await vesselManagerOperations.redeemCollateral(
erc20.address,
Expand All @@ -4011,7 +4051,6 @@ contract("VesselManager", async accounts => {
)
}

await adminContract.setWhitelistedRedeemer(dennis, true)
// Dennis tries to redeem 20 debt tokens
const redemptionTx = await vesselManagerOperations.redeemCollateral(
erc20.address,
Expand Down Expand Up @@ -4140,7 +4179,6 @@ contract("VesselManager", async accounts => {
// skip bootstrapping phase
await th.fastForwardTime(timeValues.SECONDS_IN_ONE_WEEK * 2, web3.currentProvider)

await adminContract.setWhitelistedRedeemer(carol, true)
await vesselManagerOperations.redeemCollateral(
erc20.address,
A_debt_Asset,
Expand Down Expand Up @@ -4219,7 +4257,6 @@ contract("VesselManager", async accounts => {
// skip bootstrapping phase
await th.fastForwardTime(timeValues.SECONDS_IN_ONE_WEEK * 2, web3.currentProvider)

await adminContract.setWhitelistedRedeemer(dennis, true)
const tx_Asset = await vesselManagerOperations.redeemCollateral(
erc20.address,
redemptionAmount_Asset,
Expand Down Expand Up @@ -4807,7 +4844,6 @@ contract("VesselManager", async accounts => {
erin
)

await adminContract.setWhitelistedRedeemer(erin, true)
await vesselManagerOperations.redeemCollateral(
erc20.address,
dec(400, 18),
Expand Down Expand Up @@ -4906,7 +4942,6 @@ contract("VesselManager", async accounts => {
const { 0: upperPartialRedemptionHint_1_Asset, 1: lowerPartialRedemptionHint_1_Asset } =
await sortedVessels.findInsertPosition(erc20.address, partialRedemptionHintNICR_Asset, erin, erin)

await adminContract.setWhitelistedRedeemer(erin, true)
const redemptionTx_Asset = await vesselManagerOperations.redeemCollateral(
erc20.address,
dec(1000, 18),
Expand Down Expand Up @@ -5059,7 +5094,6 @@ contract("VesselManager", async accounts => {
// skip redemption bootstrapping phase
await th.fastForwardTime(timeValues.SECONDS_IN_ONE_WEEK * 2, web3.currentProvider)

await adminContract.setWhitelistedRedeemer(erin, true)
// Erin redeems 120 debt tokens
await ({ 0: firstRedemptionHint, 1: partialRedemptionHintNewICR } =
await vesselManagerOperations.getRedemptionHints(erc20.address, _120_, price, 0))
Expand Down Expand Up @@ -5094,7 +5128,6 @@ contract("VesselManager", async accounts => {
const { 0: upperPartialRedemptionHint_2, 1: lowerPartialRedemptionHint_2 } =
await sortedVessels.findInsertPosition(erc20.address, partialRedemptionHintNewICR, flyn, flyn)

await adminContract.setWhitelistedRedeemer(flyn, true)
const redemption_2 = await vesselManagerOperations.redeemCollateral(
erc20.address,
_373_,
Expand Down Expand Up @@ -5126,7 +5159,6 @@ contract("VesselManager", async accounts => {
const { 0: upperPartialRedemptionHint_3, 1: lowerPartialRedemptionHint_3 } =
await sortedVessels.findInsertPosition(erc20.address, partialRedemptionHintNewICR, graham, graham)

await adminContract.setWhitelistedRedeemer(graham, true)
const redemption_3 = await vesselManagerOperations.redeemCollateral(
erc20.address,
_950_,
Expand Down Expand Up @@ -6402,7 +6434,6 @@ contract("VesselManager", async accounts => {
const { 0: firstRedemptionHint_Asset, 1: partialRedemptionHintNICR_Asset } =
await vesselManagerOperations.getRedemptionHints(erc20.address, TRIAmount_Asset, price, 0)

await adminContract.setWhitelistedRedeemer(alice, true)
// Don't pay for gas, as it makes it easier to calculate the received Ether
const redemptionTx_Asset = await vesselManagerOperations.redeemCollateral(
erc20.address,
Expand Down
4 changes: 4 additions & 0 deletions test/trinity/VesselManager_LiquidationRewardsTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ const deploy = async (treasury, mintingAccounts) => {
vesselManagerOperations = contracts.core.vesselManagerOperations
shortTimelock = contracts.core.shortTimelock
longTimelock = contracts.core.longTimelock

for(const account of mintingAccounts) {
await adminContract.setWhitelistedRedeemer(account, true)
}
}

contract("VesselManager - Redistribution reward calculations", async accounts => {
Expand Down
4 changes: 4 additions & 0 deletions test/trinity/VesselManager_RecoveryModeTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ const deploy = async (treasury, mintingAccounts) => {

// getDepositorGains() expects a sorted collateral array
validCollateral = validCollateral.slice(0).sort((a, b) => toBN(a.toLowerCase()).sub(toBN(b.toLowerCase())))

for(const account of mintingAccounts) {
await adminContract.setWhitelistedRedeemer(account, true)
}
}

contract("VesselManager - in Recovery Mode", async accounts => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ const deploy = async (treasury, mintingAccounts) => {

// getDepositorGains() expects a sorted collateral array
validCollateral = validCollateral.slice(0).sort((a, b) => toBN(a.toLowerCase()).sub(toBN(b.toLowerCase())))

for(const account of mintingAccounts) {
await adminContract.setWhitelistedRedeemer(account, true)
}
}

contract("VesselManager - in Recovery Mode - back to normal mode in 1 tx", async accounts => {
Expand Down
Loading