Skip to content

Commit

Permalink
Work on tests
Browse files Browse the repository at this point in the history
  • Loading branch information
neodaoist committed Sep 9, 2023
1 parent 067d6f8 commit be6af8b
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 171 deletions.
18 changes: 14 additions & 4 deletions src/ValoremOptionsClearinghouse.sol
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ contract ValoremOptionsClearinghouse is ERC1155, IValoremOptionsClearinghouse {

/**
* @notice Stores the state of options written and exercised for a bucket.
* Used in fair exercise assignment assignment to calculate the ratio of
* underlying assets to exercise assets to be transferred to claimants.
* Used in fair exercise assignment to calculate the ratio of underlying
* assets to exercise assets to be transferred to claimants.
*/
struct Bucket {
/// @custom:member amountWritten The number of option contracts written into this bucket.
Expand Down Expand Up @@ -180,7 +180,7 @@ contract ValoremOptionsClearinghouse is ERC1155, IValoremOptionsClearinghouse {
}

/// @inheritdoc IValoremOptionsClearinghouse
function claim(uint256 claimId) external view returns (Claim memory claimInfo) {
function claim(uint256 claimId) public view returns (Claim memory claimInfo) {
(uint160 optionKey, uint96 claimKey) = _decodeTokenId(claimId);

if (!_isClaimInitialized(optionKey, claimKey)) {
Expand Down Expand Up @@ -497,12 +497,19 @@ contract ValoremOptionsClearinghouse is ERC1155, IValoremOptionsClearinghouse {
return tokenId;
}

//
// Net Offsetting Positions
//

/// @inheritdoc IValoremOptionsClearinghouse
function net(uint256 claimId) external {}

Check warning on line 505 in src/ValoremOptionsClearinghouse.sol

View workflow job for this annotation

GitHub Actions / Forge unit tests

Code contains empty blocks

//
// Redeem Claims
//

/// @inheritdoc IValoremOptionsClearinghouse
function redeem(uint256 claimId) external {
function redeem(uint256 claimId) public {
(uint160 optionKey, uint96 claimKey) = _decodeTokenId(claimId);

// You can't redeem an option.
Expand Down Expand Up @@ -533,14 +540,17 @@ contract ValoremOptionsClearinghouse is ERC1155, IValoremOptionsClearinghouse {
uint256 totalUnderlyingAssetAmount;
uint256 totalExerciseAssetAmount;

// Calculate the collateral of the Claim.
for (uint256 i = len; i > 0; i--) {
(uint256 indexUnderlyingAmount, uint256 indexExerciseAmount) = _getAssetAmountsForClaimIndex(
underlyingAssetAmount, exerciseAssetAmount, optionTypeState, claimIndices, i - 1
);

// Accumulate the amount exercised and unexercised in these variables
// for later multiplication by optionRecord.exerciseAmount/underlyingAmount.
totalUnderlyingAssetAmount += indexUnderlyingAmount;
totalExerciseAssetAmount += indexExerciseAmount;

// This zeroes out the array during the redemption process for a gas refund.
claimIndices.pop();
}
Expand Down
4 changes: 2 additions & 2 deletions src/interfaces/IValoremOptionsClearinghouse.sol
Original file line number Diff line number Diff line change
Expand Up @@ -483,9 +483,9 @@ interface IValoremOptionsClearinghouse {
//////////////////////////////////////////////////////////////*/

/**
* TODO
* @notice TODO
*/
// function net(uint256 optionid) external;
function net(uint256 optionId) external;

/*//////////////////////////////////////////////////////////////
// Redeem Claims
Expand Down
271 changes: 110 additions & 161 deletions test/ValoremOptionsClearinghouse-v1.1.unit.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -81,167 +81,116 @@ contract ValoremOptionsClearinghousev11UnitTest is BaseClearinghouseTest {

// TODO

// function test_close() public {
// uint256 balanceA = ERC20A.balanceOf(ALICE);
// uint256 balanceB = ERC20B.balanceOf(ALICE);

// // Alice writes 10 options
// vm.startPrank(ALICE);
// uint256 optionId = engine.newOptionType({
// underlyingAsset: address(ERC20A),
// underlyingAmount: 1 ether,
// exerciseAsset: address(ERC20B),
// exerciseAmount: 8 ether,
// exerciseTimestamp: uint40(block.timestamp),
// expiryTimestamp: uint40(block.timestamp + 30 days)
// });
// uint256 claimId = engine.write(optionId, 10);

// uint256 expectedWriteAmount = 10 * 1 ether;

// assertEq(engine.balanceOf(ALICE, optionId), 10, "Alice option tokens before");
// assertEq(engine.balanceOf(ALICE, claimId), 1, "Alice claim tokens before");
// assertEq(
// ERC20A.balanceOf(ALICE),
// balanceA - expectedWriteAmount - _calculateFee(expectedWriteAmount),
// "Alice underlying asset before"
// );
// assertEq(ERC20B.balanceOf(ALICE), balanceB, "Alice exercise asset before");

// // Alice closes offsetting positions after no Longs have been exercised
// engine.close(optionId);

// assertEq(engine.balanceOf(ALICE, optionId), 0, "Alice option tokens after");
// assertEq(engine.balanceOf(ALICE, claimId), 0, "Alice claim tokens after");
// assertEq(ERC20A.balanceOf(ALICE), balanceA, "Alice underlying asset after");
// assertEq(ERC20B.balanceOf(ALICE), balanceB, "Alice exercise asset after");
// }

// function test_close_whenPartiallyExercisedByWriter() public {
// uint256 balanceA = ERC20A.balanceOf(ALICE);
// uint256 balanceB = ERC20B.balanceOf(ALICE);

// // Alice writes 10 options
// vm.startPrank(ALICE);
// uint256 optionId = engine.newOptionType({
// underlyingAsset: address(ERC20A),
// underlyingAmount: 1 ether,
// exerciseAsset: address(ERC20B),
// exerciseAmount: 8 ether,
// exerciseTimestamp: uint40(block.timestamp),
// expiryTimestamp: uint40(block.timestamp + 30 days)
// });
// uint256 claimId = engine.write(optionId, 10);

// uint256 expectedWriteAmount = 10 * 1 ether;
// uint256 expectedExerciseAmount = 3 * 8 ether;

// assertEq(engine.balanceOf(ALICE, optionId), 10, "Alice option tokens before");
// assertEq(engine.balanceOf(ALICE, claimId), 1, "Alice claim tokens before");
// assertEq(
// ERC20A.balanceOf(ALICE),
// balanceA - expectedWriteAmount - _calculateFee(expectedWriteAmount),
// "Alice underlying asset before"
// );
// assertEq(ERC20B.balanceOf(ALICE), balanceB, "Alice exercise asset before");

// // Alice exercises 3 Longs
// engine.exercise(optionId, 3);

// assertEq(engine.balanceOf(ALICE, optionId), 7, "Alice option tokens after exercise");
// assertEq(engine.balanceOf(ALICE, claimId), 0, "Alice claim tokens after exercise");
// assertEq(
// ERC20A.balanceOf(ALICE),
// balanceA - expectedWriteAmount - _calculateFee(expectedWriteAmount) + (3 * 1 ether),
// "Alice underlying asset after exercise"
// );
// assertEq(
// ERC20B.balanceOf(ALICE),
// balanceB - expectedExerciseAmount - _calculateFee(expectedExerciseAmount),
// "Alice exercise asset after exercise"
// );

// // Alice closes remaining 7 Longs and claims collateral back from 3 Longs that she exercised
// engine.close(optionId);

// assertEq(engine.balanceOf(ALICE, optionId), 0, "Alice option tokens after close");
// assertEq(engine.balanceOf(ALICE, claimId), 0, "Alice claim tokens after close");
// assertEq(ERC20A.balanceOf(ALICE), balanceA, "Alice underlying asset after close");
// assertEq(ERC20B.balanceOf(ALICE), balanceB, "Alice exercise asset after close");
// }

// function test_close_whenPartiallyExercisedByOtherHolder() public {
// uint256 aliceBalanceA = ERC20A.balanceOf(ALICE);
// uint256 aliceBalanceB = ERC20B.balanceOf(ALICE);
// uint256 bobBalanceA = ERC20A.balanceOf(BOB);
// uint256 bobBalanceB = ERC20B.balanceOf(BOB);

// // Alice writes 10 options
// vm.startPrank(ALICE);
// uint256 optionId = engine.newOptionType({
// underlyingAsset: address(ERC20A),
// underlyingAmount: 1 ether,
// exerciseAsset: address(ERC20B),
// exerciseAmount: 8 ether,
// exerciseTimestamp: uint40(block.timestamp),
// expiryTimestamp: uint40(block.timestamp + 30 days)
// });
// uint256 claimId = engine.write(optionId, 10);

// uint256 expectedWriteAmount = 10 * 1 ether;
// uint256 expectedExerciseAmount = 3 * 8 ether;

// assertEq(engine.balanceOf(ALICE, optionId), 10, "Alice option tokens before");
// assertEq(engine.balanceOf(ALICE, claimId), 1, "Alice claim tokens before");
// assertEq(
// ERC20A.balanceOf(ALICE),
// aliceBalanceA - expectedWriteAmount - _calculateFee(expectedWriteAmount),
// "Alice underlying asset before"
// );
// assertEq(ERC20B.balanceOf(ALICE), aliceBalanceB, "Alice exercise asset before");

// // Alice transfers 3 Longs to Bob
// engine.safeTransferFrom(ALICE, BOB, optionId, 3, "");
// vm.stopPrank();

// assertEq(engine.balanceOf(ALICE, optionId), 7, "Alice option tokens after transfer");
// assertEq(engine.balanceOf(ALICE, claimId), 1, "Alice claim tokens after transfer");

// // Bob exercises 3 Longs
// vm.prank(BOB);
// engine.exercise(optionId, 3);

// assertEq(
// ERC20A.balanceOf(ALICE),
// aliceBalanceA - expectedWriteAmount - _calculateFee(expectedWriteAmount),
// "Alice underlying asset after exercise"
// );
// assertEq(
// ERC20B.balanceOf(ALICE),
// aliceBalanceB,
// "Alice exercise asset after exercise"
// );
// assertEq(
// ERC20A.balanceOf(BOB),
// bobBalanceA + (3 * 1 ether),
// "Bob underlying asset after exercise"
// );
// assertEq(
// ERC20B.balanceOf(BOB),
// bobBalanceB - expectedExerciseAmount - _calculateFee(expectedExerciseAmount),
// "Bob exercise asset after exercise"
// );

// // Alice closes remaining 7 Longs and claims collateral back from 3 Longs that Bob exercised
// engine.close(optionId);

// assertEq(engine.balanceOf(ALICE, optionId), 0, "Alice option tokens after close");
// assertEq(engine.balanceOf(ALICE, claimId), 0, "Alice claim tokens after close");
// assertEq(ERC20A.balanceOf(ALICE), aliceBalanceA - expectedWriteAmount - _calculateFee(expectedWriteAmount) + (3 * 1 ether), "Alice underlying asset after close");
// assertEq(ERC20B.balanceOf(ALICE), aliceBalanceB + expectedExerciseAmount, "Alice exercise asset after close");
// assertEq(ERC20A.balanceOf(BOB), bobBalanceA, "Bob underlying asset after close");
// assertEq(ERC20B.balanceOf(BOB), bobBalanceB, "Bob exercise asset after close");
// }
function test_net_whenUnassigned() public {
uint256 balanceA = ERC20A.balanceOf(ALICE);
uint256 balanceB = ERC20B.balanceOf(ALICE);

// Alice writes 10 Options
vm.startPrank(ALICE);
uint256 optionId = engine.newOptionType({
underlyingAsset: address(ERC20A),
underlyingAmount: 1 ether,
exerciseAsset: address(ERC20B),
exerciseAmount: 8 ether,
exerciseTimestamp: uint40(block.timestamp),
expiryTimestamp: uint40(block.timestamp + 30 days)
});
uint256 claimId = engine.write(optionId, 10);

uint256 expectedWriteAmount = 10 * 1 ether;

assertEq(engine.balanceOf(ALICE, optionId), 10, "Alice option tokens before");
assertEq(engine.balanceOf(ALICE, claimId), 1, "Alice claim tokens before");
assertEq(
ERC20A.balanceOf(ALICE),
balanceA - expectedWriteAmount - _calculateFee(expectedWriteAmount),
"Alice underlying asset before"
);
assertEq(ERC20B.balanceOf(ALICE), balanceB, "Alice exercise asset before");

// Alice nets offsetting positions after no Options have been exercised
engine.net(claimId);

assertEq(engine.balanceOf(ALICE, optionId), 0, "Alice option tokens after");
assertEq(engine.balanceOf(ALICE, claimId), 0, "Alice claim tokens after");
assertEq(ERC20A.balanceOf(ALICE), balanceA - _calculateFee(expectedWriteAmount), "Alice underlying asset after"); // still less write fee
assertEq(ERC20B.balanceOf(ALICE), balanceB, "Alice exercise asset after");
}

function test_net_whenPartiallyExercised() public {
uint256 aliceBalanceA = ERC20A.balanceOf(ALICE);
uint256 aliceBalanceB = ERC20B.balanceOf(ALICE);
uint256 bobBalanceA = ERC20A.balanceOf(BOB);
uint256 bobBalanceB = ERC20B.balanceOf(BOB);

// Alice writes 10 Options
vm.startPrank(ALICE);
uint256 optionId = engine.newOptionType({
underlyingAsset: address(ERC20A),
underlyingAmount: 1 ether,
exerciseAsset: address(ERC20B),
exerciseAmount: 8 ether,
exerciseTimestamp: uint40(block.timestamp),
expiryTimestamp: uint40(block.timestamp + 30 days)
});
uint256 claimId = engine.write(optionId, 10);

uint256 expectedWriteAmount = 10 * 1 ether;
uint256 expectedExerciseAmount = 3 * 8 ether;

assertEq(engine.balanceOf(ALICE, optionId), 10, "Alice option tokens before");
assertEq(engine.balanceOf(ALICE, claimId), 1, "Alice claim tokens before");
assertEq(
ERC20A.balanceOf(ALICE),
aliceBalanceA - expectedWriteAmount - _calculateFee(expectedWriteAmount),
"Alice underlying asset before"
);
assertEq(ERC20B.balanceOf(ALICE), aliceBalanceB, "Alice exercise asset before");

// Alice transfers 3 Options to Bob
engine.safeTransferFrom(ALICE, BOB, optionId, 3, "");
vm.stopPrank();

assertEq(engine.balanceOf(ALICE, optionId), 7, "Alice option tokens after transfer");
assertEq(engine.balanceOf(ALICE, claimId), 1, "Alice claim tokens after transfer");

// Bob exercises 3 Options
vm.prank(BOB);
engine.exercise(optionId, 3);

assertEq(
ERC20A.balanceOf(ALICE),
aliceBalanceA - expectedWriteAmount - _calculateFee(expectedWriteAmount),
"Alice underlying asset after exercise"
);
assertEq(ERC20B.balanceOf(ALICE), aliceBalanceB, "Alice exercise asset after exercise");
assertEq(ERC20A.balanceOf(BOB), bobBalanceA + (3 * 1 ether), "Bob underlying asset after exercise");
assertEq(
ERC20B.balanceOf(BOB),
bobBalanceB - expectedExerciseAmount - _calculateFee(expectedExerciseAmount),
"Bob exercise asset after exercise"
);

// Alice closes remaining 7 Options and gets collateral back from 3 Options that Bob exercised
engine.net(claimId);

assertEq(engine.balanceOf(ALICE, optionId), 0, "Alice option tokens after close");
assertEq(engine.balanceOf(ALICE, claimId), 0, "Alice claim tokens after close");
assertEq(
ERC20A.balanceOf(ALICE),
aliceBalanceA - expectedWriteAmount - _calculateFee(expectedWriteAmount) + (3 * 1 ether),
"Alice underlying asset after close"
);
assertEq(ERC20B.balanceOf(ALICE), aliceBalanceB + expectedExerciseAmount, "Alice exercise asset after close");
assertEq(ERC20A.balanceOf(BOB), bobBalanceA + (3 * 1 ether), "Bob underlying asset after close");
assertEq(
ERC20B.balanceOf(BOB),
bobBalanceB - expectedExerciseAmount - _calculateFee(expectedExerciseAmount),
"Bob exercise asset after close"
);
}

// TODO remaining scenarios

/*//////////////////////////////////////////////////////////////
// redeem() early
Expand Down
6 changes: 2 additions & 4 deletions test/ValoremOptionsClearinghouse.integration.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -340,10 +340,9 @@ contract ValoremOptionsClearinghouseIntegrationTest is BaseClearinghouseTest {
engine.write(daiOptionId, optionsWrittenDaiUnderlying);
engine.write(usdcOptionId, optionsWrittenUsdcUnderlying);
vm.stopPrank();
expectedFees[0] = (((testUnderlyingAmount * optionsWrittenWethUnderlying) / 10_000) * engine.feeBps());

expectedFees[0] = (((testUnderlyingAmount * optionsWrittenWethUnderlying) / 10_000) * engine.feeBps());
expectedFees[1] = (((daiUnderlyingAmount * optionsWrittenDaiUnderlying) / 10_000) * engine.feeBps());

expectedFees[2] = (((usdcUnderlyingAmount * optionsWrittenUsdcUnderlying) / 10_000) * engine.feeBps());

for (uint256 i = 0; i < tokens.length; i++) {
Expand Down Expand Up @@ -451,10 +450,9 @@ contract ValoremOptionsClearinghouseIntegrationTest is BaseClearinghouseTest {
// taken for any of these assets, and the 1 wei-left-behind gas optimization
// has already happened, therefore actual fee swept amount = true fee amount.
uint256[] memory expectedFees = new uint256[](3);
expectedFees[0] = (((daiExerciseAmount * optionsWrittenDaiExercise) / 10_000) * engine.feeBps());

expectedFees[0] = (((daiExerciseAmount * optionsWrittenDaiExercise) / 10_000) * engine.feeBps());
expectedFees[1] = (((wethExerciseAmount * optionsWrittenWethExercise) / 10_000) * engine.feeBps());

expectedFees[2] = (((usdcExerciseAmount * optionsWrittenUsdcExercise) / 10_000) * engine.feeBps());

for (uint256 i = 0; i < tokens.length; i++) {
Expand Down

0 comments on commit be6af8b

Please sign in to comment.