Skip to content

fix(tests): Small fixes for BasisTradingModule audit changes #243

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

Merged
merged 4 commits into from
Apr 13, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
22 changes: 13 additions & 9 deletions contracts/protocol/modules/v2/PerpV2LeverageModuleV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import { PreciseUnitMath } from "../../../lib/PreciseUnitMath.sol";
import { AddressArrayUtils } from "../../../lib/AddressArrayUtils.sol";
import { UnitConversionUtils } from "../../../lib/UnitConversionUtils.sol";


/**
* @title PerpV2LeverageModuleV2
* @author Set Protocol
Expand Down Expand Up @@ -1053,25 +1054,28 @@ contract PerpV2LeverageModuleV2 is ModuleBaseV2, ReentrancyGuard, Ownable, SetTo
}

/**
* @dev Sets the external position unit based on PerpV2 account value.
* @dev Sets the external position unit based on PerpV2 Vault collateral balance. If there more than 1
* position unit of USDC of account value (allowing for PRECISE UNIT rounding errors) adds the component
* and/or the external position to the SetToken. Else, untracks the component and/or removes external
* position from the SetToken. Refer to PositionV2#editExternalPosition for detailed flow.
*
* NOTE: Setting external position unit to the collateral balance is acceptable because, as noted above, the
* external position unit is only updated on an as-needed basis during issuance, redemption, deposit and
* withdraw. It does not reflect the current value of the Set's perpetual position. The true current value can
* be calculated from getPositionNotionalInfo.
*
* @param _setToken Instance of SetToken
*/
function _updateExternalPositionUnit(ISetToken _setToken) internal {
int256 accountValueUnit = perpClearingHouse.getAccountValue(address(_setToken))
int256 collateralValueUnit = perpVault.getBalance(address(_setToken))
.toPreciseUnitsFromDecimals(collateralDecimals)
.preciseDiv(_setToken.totalSupply().toInt256())
.fromPreciseUnitToDecimals(collateralDecimals);

// Set the external position unit based on PerpV2 Account value; If there is more than 1 position unit of USDC of account
// value (to tolerate PRECISE_UNIT math rounding errors), add the component and/or the external position to the SetToken.
// Else, untrack the component and/or remove external position from the SetToken. Refer to PositionV2#editExternalPosition for detailed flow.
// Setting external posiiton unit to 1 or 0 is acceptable because, As noted above, the external position unit is only updated on an as-needed
// basis during issuance, redemption, deposit and withdraw. It does not reflect the current value of the Set's perpetual position.
// The current value can be calculated from getPositionNotionalInfo.
_setToken.editExternalPosition(
address(collateralToken),
address(this),
accountValueUnit > 1 ? 1 : 0,
collateralValueUnit,
""
);
}
Expand Down
14 changes: 13 additions & 1 deletion test/integration/perpV2BasisTradingSlippageIssuance.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ describe("PerpV2BasisTradingSlippageIssuance", () => {
setToken.address,
{
feeRecipient: owner.address,
performanceFeePercentage: ether(.0),
performanceFeePercentage: ether(.1),
maxPerformanceFeePercentage: ether(.2)
}
);
Expand Down Expand Up @@ -294,6 +294,7 @@ describe("PerpV2BasisTradingSlippageIssuance", () => {
baseToken,
2,
ether(.02),
true,
true
);

Expand Down Expand Up @@ -508,6 +509,7 @@ describe("PerpV2BasisTradingSlippageIssuance", () => {
baseToken,
2,
ether(.02),
true,
true
);

Expand Down Expand Up @@ -855,6 +857,7 @@ describe("PerpV2BasisTradingSlippageIssuance", () => {
baseToken,
6,
ether(.02),
true,
true
);

Expand Down Expand Up @@ -909,7 +912,12 @@ describe("PerpV2BasisTradingSlippageIssuance", () => {

describe("when liquidation results in negative account value", () => {
beforeEach(async () => {
// Move oracle price down, wait one day
await perpSetup.setBaseTokenOraclePrice(vETH, usdcUnits(10.5));
await increaseTimeAsync(ONE_DAY_IN_SECONDS);

// Calculated leverage = ~8.5X = 8_654_438_822_995_683_587
// Lever again to track funding as `settled`
await leverUp(
setToken,
perpBasisTradingModule,
Expand All @@ -918,9 +926,13 @@ describe("PerpV2BasisTradingSlippageIssuance", () => {
baseToken,
6,
ether(.02),
true,
true
);

// Freeze funding changes
await perpSetup.clearingHouseConfig.setMaxFundingRate(ZERO);

// Move oracle price down to 5 USDC to enable liquidation
await perpSetup.setBaseTokenOraclePrice(vETH, usdcUnits(5.0));

Expand Down
4 changes: 2 additions & 2 deletions test/integration/perpV2LeverageV2SlippageIssuance.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import {
} from "@utils/test/index";
import { PerpV2Fixture, SystemFixture } from "@utils/fixtures";
import { BigNumber } from "ethers";
import { ONE, ADDRESS_ZERO, ZERO, MAX_UINT_256, ZERO_BYTES } from "@utils/constants";
import { ADDRESS_ZERO, ZERO, MAX_UINT_256, ZERO_BYTES } from "@utils/constants";

const expect = getWaffleExpect();

Expand Down Expand Up @@ -373,7 +373,7 @@ describe("PerpV2LeverageSlippageIssuance", () => {
);

expect(defaultPositionUnit).eq(ZERO);
expect(externalPositionUnit).eq(ONE);
expect(externalPositionUnit).eq(depositQuantityUnit);
});
});

Expand Down
9 changes: 6 additions & 3 deletions test/protocol/modules/v2/perpV2BasisTradingModule.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -779,7 +779,8 @@ describe("PerpV2BasisTradingModule", () => {
const externalPositionUnit = await subjectSetToken.getExternalPositionRealUnit(usdc.address, perpBasisTradingModule.address);
const expectedExternalPositionUnit = await calculateExternalPositionUnit(
subjectSetToken,
perpSetup
perpSetup,
perpBasisTradingModule
);
expect(externalPositionUnit).eq(expectedExternalPositionUnit);
});
Expand Down Expand Up @@ -870,7 +871,8 @@ describe("PerpV2BasisTradingModule", () => {
const externalPositionUnit = await subjectSetToken.getExternalPositionRealUnit(usdc.address, perpBasisTradingModule.address);
const expectedExternalPositionUnit = await calculateExternalPositionUnit(
subjectSetToken,
perpSetup
perpSetup,
perpBasisTradingModule
);
expect(externalPositionUnit).eq(expectedExternalPositionUnit);
});
Expand Down Expand Up @@ -1020,7 +1022,8 @@ describe("PerpV2BasisTradingModule", () => {
const externalPositionUnit = await setToken.getExternalPositionRealUnit(usdc.address, perpBasisTradingModule.address);
const expectedExternalPositionUnit = await calculateExternalPositionUnit(
setToken,
perpSetup
perpSetup,
perpBasisTradingModule
);
expect(externalPositionUnit).eq(expectedExternalPositionUnit);
});
Expand Down
18 changes: 12 additions & 6 deletions test/protocol/modules/v2/perpV2LeverageModuleV2.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1205,7 +1205,8 @@ describe("PerpV2LeverageModuleV2", () => {
const externalPositionUnit = await subjectSetToken.getExternalPositionRealUnit(usdc.address, perpLeverageModule.address);
const expectedExternalPositionUnit = await calculateExternalPositionUnit(
subjectSetToken,
perpSetup
perpSetup,
perpLeverageModule,
);
expect(externalPositionUnit).eq(expectedExternalPositionUnit);
});
Expand Down Expand Up @@ -1261,7 +1262,8 @@ describe("PerpV2LeverageModuleV2", () => {
const externalPositionUnit = await subjectSetToken.getExternalPositionRealUnit(usdc.address, perpLeverageModule.address);
const expectedExternalPositionUnit = await calculateExternalPositionUnit(
subjectSetToken,
perpSetup
perpSetup,
perpLeverageModule
);

// Deposit notional amount = specified position unit * totalSupply = 1 * 2 = $2
Expand Down Expand Up @@ -1344,7 +1346,8 @@ describe("PerpV2LeverageModuleV2", () => {
const externalPositionUnit = await subjectSetToken.getExternalPositionRealUnit(usdc.address, perpLeverageModule.address);
const expectedExternalPositionUnit = await calculateExternalPositionUnit(
subjectSetToken,
perpSetup
perpSetup,
perpLeverageModule
);

// Deposit amount = $1 * 2 (two deposits)
Expand Down Expand Up @@ -1438,7 +1441,8 @@ describe("PerpV2LeverageModuleV2", () => {
const externalPositionUnit = await subjectSetToken.getExternalPositionRealUnit(usdc.address, perpLeverageModule.address);
const expectedExternalPositionUnit = await calculateExternalPositionUnit(
subjectSetToken,
perpSetup
perpSetup,
perpLeverageModule
);

// Deposit amount = $1 * 2 (two deposits)
Expand Down Expand Up @@ -1579,7 +1583,8 @@ describe("PerpV2LeverageModuleV2", () => {
const externalPositionUnit = await subjectSetToken.getExternalPositionRealUnit(usdc.address, perpLeverageModule.address);
const expectedExternalPositionUnit = await calculateExternalPositionUnit(
subjectSetToken,
perpSetup
perpSetup,
perpLeverageModule
);
expect(externalPositionUnit).eq(expectedExternalPositionUnit);
});
Expand Down Expand Up @@ -1657,7 +1662,8 @@ describe("PerpV2LeverageModuleV2", () => {
const externalPositionUnit = await subjectSetToken.getExternalPositionRealUnit(usdc.address, perpLeverageModule.address);
const expectedExternalPositionUnit = await calculateExternalPositionUnit(
subjectSetToken,
perpSetup
perpSetup,
perpLeverageModule
);
expect(externalPositionUnit).eq(expectedExternalPositionUnit);
});
Expand Down
32 changes: 21 additions & 11 deletions utils/common/perpV2Utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
preciseMul
} from "../index";

import { ONE, TWO, ZERO, ONE_DAY_IN_SECONDS } from "../constants";
import { TWO, ZERO, ONE_DAY_IN_SECONDS } from "../constants";
import { PerpV2BasisTradingModule, PerpV2LeverageModuleV2, SetToken } from "../contracts";
import { PerpV2Fixture } from "../fixtures";

Expand All @@ -27,7 +27,8 @@ export async function leverUp(
baseToken: Address,
leverageRatio: number,
slippagePercentage: BigNumber,
isLong: boolean
isLong: boolean,
trackFunding?: boolean,
): Promise<BigNumber>{
const spotPrice = await fixture.getSpotPrice(baseToken);
const totalSupply = await setToken.totalSupply();
Expand All @@ -50,12 +51,21 @@ export async function leverUp(
totalSupply
);

await module.connect(owner.wallet).trade(
setToken.address,
baseToken,
baseTradeQuantityUnit,
receiveQuoteQuantityUnit
);
if (trackFunding) {
await (module as PerpV2BasisTradingModule).connect(owner.wallet).tradeAndTrackFunding(
setToken.address,
baseToken,
baseTradeQuantityUnit,
receiveQuoteQuantityUnit
);
} else {
await module.connect(owner.wallet).trade(
setToken.address,
baseToken,
baseTradeQuantityUnit,
receiveQuoteQuantityUnit
);
}

return baseTradeQuantityUnit;
}
Expand Down Expand Up @@ -180,10 +190,10 @@ export async function calculateUSDCTransferOutPreciseUnits(
export async function calculateExternalPositionUnit(
setToken: SetToken,
fixture: PerpV2Fixture,
module: PerpV2LeverageModuleV2 | PerpV2BasisTradingModule
): Promise<BigNumber> {
const totalPositionValue = await fixture.clearingHouse.getAccountValue(setToken.address);
// return toUSDCDecimals(preciseDiv(totalPositionValue, await setToken.totalSupply()));
return totalPositionValue.gt(ZERO) ? ONE : ZERO;
const accountInfo = await module.getAccountInfo(setToken.address);
return toUSDCDecimals(preciseDiv(accountInfo.collateralBalance, await setToken.totalSupply()));
}

// On every interaction with perpV2, it settles funding for a trader into owed realized pnl
Expand Down