Skip to content

Commit

Permalink
Removes the breached requirement from redemption
Browse files Browse the repository at this point in the history
  • Loading branch information
alsco77 committed Jun 22, 2020
1 parent f9f87c7 commit bd2a4d2
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 26 deletions.
22 changes: 4 additions & 18 deletions contracts/masset/forge-validator/ForgeValidator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";
* @author Stability Labs Pty. Ltd.
* @notice Calculates whether or not minting or redemption is valid, based
* on how it affects the underlying basket collateral weightings
* @dev VERSION: 1.0
* DATE: 2020-05-05
* @dev VERSION: 1.1
* DATE: 2020-06-22
*/
contract ForgeValidator is IForgeValidator {

Expand Down Expand Up @@ -222,8 +222,7 @@ contract ForgeValidator is IForgeValidator {
// If the basket is in an affected state, enforce proportional redemption
if(
_basketIsFailed ||
data.atLeastOneBroken ||
(data.overWeightCount == 0 && data.atLeastOneBreached)
data.atLeastOneBroken
) {
return (false, "Must redeem proportionately", false);
} else if (data.overWeightCount > idxCount) {
Expand All @@ -249,7 +248,7 @@ contract ForgeValidator is IForgeValidator {
newTotalVault = newTotalVault.sub(ratioedRedemptionAmount);
}

// Get overweight/breached after
// Get overweight after
bool atLeastOneBecameOverweight =
_getOverweightBassetsAfter(newTotalVault, _allBassets, data.ratioedBassetVaults, data.isOverWeight);

Expand Down Expand Up @@ -333,7 +332,6 @@ contract ForgeValidator is IForgeValidator {
bool isValid;
string reason;
bool atLeastOneBroken;
bool atLeastOneBreached;
uint256 overWeightCount;
bool[] isOverWeight;
uint256[] ratioedBassetVaults;
Expand All @@ -357,16 +355,11 @@ contract ForgeValidator is IForgeValidator {
isValid: true,
reason: "",
atLeastOneBroken: false,
atLeastOneBreached: false,
overWeightCount: 0,
isOverWeight: new bool[](len),
ratioedBassetVaults: new uint256[](len)
});

uint256 onePercentOfTotal = _total.mulTruncate(1e16);
// Number of units below max a bAsset can be before deemed as breached
uint256 weightBreachThreshold = StableMath.min(onePercentOfTotal, 5e22);

for(uint256 i = 0; i < len; i++) {
BassetStatus status = _bAssets[i].status;
if(status == BassetStatus.Blacklisted) {
Expand All @@ -390,13 +383,6 @@ contract ForgeValidator is IForgeValidator {
response.isOverWeight[i] = true;
response.overWeightCount += 1;
}

// if the bAsset isn't overweight, check if it's within the bound
if(!bAssetOverWeight) {
uint256 lowerBound = weightBreachThreshold > maxWeightInUnits ? 0 : maxWeightInUnits.sub(weightBreachThreshold);
bool isInBound = ratioedBasset > lowerBound && ratioedBasset <= maxWeightInUnits;
response.atLeastOneBreached = response.atLeastOneBreached || isInBound;
}
}
}

Expand Down
8 changes: 5 additions & 3 deletions test/masset/TestMassetRedemption.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -756,7 +756,7 @@ contract("Masset - Redeem", async (accounts) => {
beforeEach(async () => {
await runSetup(false);
});
it("should force proportional redemption no matter what", async () => {
it("should allow redemption as long as nothing goes overweight", async () => {
const { bAssets, mAsset, basketManager } = massetDetails;
const composition = await massetMachine.getBasketComposition(massetDetails);
// Expect 4 bAssets with 100 weightings
Expand All @@ -782,9 +782,11 @@ contract("Masset - Redeem", async (accounts) => {
// Should succeed if we redeem this
const bAsset = bAssets[0];
const bAssetDecimals = await bAsset.decimals();
await assertBasicRedemption(massetDetails, 2, bAsset, true);
// 30% * 93 = 27.8, meaning bAssets[1] is now overweight
await expectRevert(
mAsset.redeem(bAsset.address, simpleToExactAmount(10, bAssetDecimals)),
"Must redeem proportionately",
mAsset.redeem(bAsset.address, simpleToExactAmount(5, bAssetDecimals)),
"bAssets must remain below max weight",
);
});
});
Expand Down
32 changes: 27 additions & 5 deletions test/masset/forge-validator/TestForgeValidatorR.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,7 @@ contract("ForgeValidator", async (accounts) => {
});
});
context("in a basket with bAssets nearing threshold (max weight breached)", async () => {
it("enforces proportional redemption", async () => {
it("allows redemption as long as nothing goes overweight", async () => {
/**
* TotalSupply: 100e18
* MaxWeights: [ 40, 40, 40, 40]
Expand All @@ -530,8 +530,19 @@ contract("ForgeValidator", async (accounts) => {
setBasset(40, "10.5"),
setBasset(40, 20),
],
[setArgs(0, 1)],
setResult(false, "Must redeem proportionately"),
[setArgs(0, 10)],
setResult(true, "", true),
);
await assertRedeem(
setBasket(false, 100),
[
setBasset(40, "39.5"),
setBasset(40, 30),
setBasset(40, "10.5"),
setBasset(40, 20),
],
[setArgs(1, 3)],
setResult(false, "bAssets must remain below max weight"),
);
});
describe("and using multiple inputs", async () => {
Expand All @@ -552,8 +563,19 @@ contract("ForgeValidator", async (accounts) => {
setBasset(40, "10.5"),
setBasset(40, 20),
],
[setArgs(0, 1), setArgs(3, 3)],
setResult(false, "Must redeem proportionately"),
[setArgs(0, 5), setArgs(3, 3)],
setResult(true, "", true),
);
await assertRedeem(
setBasket(false, 100),
[
setBasset(40, "39.5"),
setBasset(40, 30),
setBasset(40, "10.5"),
setBasset(40, 20),
],
[setArgs(0, 1), setArgs(1, 7)],
setResult(false, "bAssets must remain below max weight"),
);
});
});
Expand Down

0 comments on commit bd2a4d2

Please sign in to comment.