Skip to content

Commit

Permalink
Better functionality and test for spread bidding
Browse files Browse the repository at this point in the history
  • Loading branch information
regynald committed Apr 25, 2022
1 parent b153b41 commit b29eeb9
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 8 deletions.
17 changes: 9 additions & 8 deletions src/HookCoveredCallImplV1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -257,9 +257,6 @@ contract HookCoveredCallImplV1 is
uint256 bidAmt = msg.value;
CallOption storage call = optionParams[optionId];

// TODO(HOOK-805) allow option writer to make a bid with an deposited amount equal
// to the spread between the their bid and the option's strike price.

uint256 normalizedBid = bidAmt;

if (call.writer == msg.sender) {
Expand Down Expand Up @@ -352,12 +349,16 @@ contract HookCoveredCallImplV1 is
(bool sent, ) = ownerOf(optionId).call{value: spread}("");
require(sent, "Failed to send Ether to option holder");

// return send option holder their earnings
(
bool writerSent, /* bytes memory writerData */

) = call.writer.call{value: call.strike}("");
require(writerSent, "Failed to send Ether to option writer");
// If the option writer is the high bidder then they don't recieve the strike and only the underlying asset
if (call.highBidder != call.writer) {
// return send option holder their earnings
(
bool writerSent, /* bytes memory writerData */

) = call.writer.call{value: call.strike}("");
require(writerSent, "Failed to send Ether to option writer");
}

if (returnNft) {
IHookERC721Vault(call.vaultAddress).withdrawalAsset();
Expand Down
103 changes: 103 additions & 0 deletions src/test/HookCoveredCallTests.sol
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,65 @@ contract HookCoveredCallBidTests is HookProtocolTest {
vm.expectRevert("bid - bid is lower than the current bid");
calls.bid{value: 0.09 ether}(optionTokenId);
}

function testWriterCanBidOnSpread() public {
vm.deal(writer, 1 ether);
vm.warp(block.timestamp + 2.1 days);

vm.prank(writer);
calls.bid{value: 1}(optionTokenId);

assertTrue(
calls.currentBid(optionTokenId) == 1001,
"bid 1 wei over strike price"
);
assertTrue(
calls.currentBidder(optionTokenId) == writer,
"writer should be highest bidder"
);
assertTrue(
writer.balance == 1 ether - 1,
"writer should have only used 1 wei to bid"
);
}

function testWriterCanOutbidOnSpread() public {
address firstBidder = address(37);
vm.label(firstBidder, "First option bidder");
vm.deal(firstBidder, 1 ether);
vm.deal(writer, 1 ether);

uint256 firstBidderStartBalance = firstBidder.balance;
uint256 writerStartBalance = writer.balance;

vm.warp(block.timestamp + 2.1 days);

vm.prank(firstBidder);
calls.bid{value: 0.1 ether}(optionTokenId);

uint256 strike = 1000;
uint256 bidAmount = 0.1 ether - strike + 1;

vm.prank(writer);
calls.bid{value: bidAmount}(optionTokenId);

assertTrue(
calls.currentBid(optionTokenId) == 0.1 ether + 1,
"high bid should be 0.1 ether + 1 wei"
);
assertTrue(
calls.currentBidder(optionTokenId) == writer,
"writer should be highest bidder"
);
assertTrue(
firstBidderStartBalance == firstBidder.balance,
"first bidder should have been refunded their bid"
);
assertTrue(
writer.balance == 1 ether - bidAmount,
"writer should have only used 0.1 ether + 1 wei to bid"
);
}
}


Expand Down Expand Up @@ -720,6 +779,50 @@ contract HookCoveredCallSettleTests is HookProtocolTest {
vm.expectRevert("settle -- the call cannot already be settled");
calls.settleOption(optionTokenId, true);
}

function testSettleOptionWhenWriterHighBidder() public {
vm.startPrank(writer);
uint256 underlyingTokenId2 = 1;
token.mint(writer, underlyingTokenId2);
vm.deal(writer, 1 ether);

uint256 buyerStartBalance = buyer.balance;
uint256 writerStartBalance = writer.balance;

// Writer approve operator and covered call
token.setApprovalForAll(address(calls), true);

uint256 expiration = block.timestamp + 3 days;

uint256 optionId = calls.mint(
address(token),
underlyingTokenId2,
1000,
expiration,
makeSignature(underlyingTokenId2, expiration, writer)
);

// Assume that the writer somehow sold the option NFT to the buyer.
// Outside of the scope of these tests.
calls.safeTransferFrom(writer, buyer, optionId);

// Option expires in 3 days from current block; bidding starts in 2 days.
vm.warp(block.timestamp + 2.1 days);
calls.bid{value: 1 wei}(optionId);
vm.warp(block.timestamp + 1 days);

calls.settleOption(optionId, false);

assertTrue(
buyerStartBalance + 1 wei == buyer.balance,
"buyer gets the option spread (winning bid of 1001 wei - strike price of 1000)"
);

assertTrue(
writerStartBalance - 1 == writer.balance,
"option writer only loses spread (1 wei)"
);
}
}


Expand Down

0 comments on commit b29eeb9

Please sign in to comment.