diff --git a/src/HookCoveredCall.sol b/src/HookCoveredCall.sol
index 8f263e3..71361a0 100644
--- a/src/HookCoveredCall.sol
+++ b/src/HookCoveredCall.sol
@@ -8,8 +8,6 @@ import "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol";
/// future. Further, each covered call is mapped to a specific ERC-721 contract address -- meaning there is one covered
/// call contract per collection.
contract HookCoveredCall is BeaconProxy {
- // TODO(HOOK-789)[GAS]: Explore implemeting the initialize function by setting storage slots on the
- // newly deployed contract to avoid additional method calls.
constructor(
address beacon,
address nftAddress,
diff --git a/src/HookCoveredCallImplV1.sol b/src/HookCoveredCallImplV1.sol
index 9fac387..2dacf6b 100644
--- a/src/HookCoveredCallImplV1.sol
+++ b/src/HookCoveredCallImplV1.sol
@@ -39,8 +39,8 @@ contract HookCoveredCallImplV1 is
/// @notice The metadata for each covered call option
/// @param writer The address of the writer that created the call option
/// @param owner The address of the current owner of the underlying, updated as bidding occurs
- /// @param tokenAddress The address of the NFT that the option is on
- /// @param tokenId The tokenId of the NFT that the option is on
+ /// @param vaultAddress the address of the vault holding the underlying asset
+ /// @param assetId the asset id of the underlying within the vault
/// @param strike The strike price to exercise the call option
/// @param expiration The expiration time of the call option
/// @param settled a flag that marks when a settlement action has taken place successfully
@@ -49,6 +49,7 @@ contract HookCoveredCallImplV1 is
struct CallOption {
address writer;
address vaultAddress;
+ uint256 assetId;
uint256 strike;
uint256 expiration;
uint256 bid;
@@ -71,9 +72,9 @@ contract HookCoveredCallImplV1 is
/// @dev storage of all existing options contracts.
mapping(uint256 => CallOption) public optionParams;
- /// @dev the address of the ERC-721 contract that can serve as underlying assets for this
+ /// @dev the address of the token contract permitted to serve as underlying assets for this
/// instrument.
- address public allowedNftContract;
+ address public allowedUnderlyingAddress;
/// @dev the address of WETH on the chain where this contract is deployed
address public weth;
@@ -131,7 +132,7 @@ contract HookCoveredCallImplV1 is
_protocol = IHookProtocol(protocol);
_erc721VaultFactory = IHookERC721VaultFactory(hookVaultFactory);
weth = _protocol.getWETHAddress();
- allowedNftContract = nftContract;
+ allowedUnderlyingAddress = nftContract;
/// Initialize basic configuration.
/// Even though these are defaults, we cannot set them in the constructor because
@@ -148,6 +149,7 @@ contract HookCoveredCallImplV1 is
/// @dev See {IHookCoveredCall-mintWithVault}.
function mintWithVault(
address vaultAddress,
+ uint256 assetId,
uint256 strikePrice,
uint256 expirationTime,
Signatures.Signature calldata signature
@@ -155,57 +157,79 @@ contract HookCoveredCallImplV1 is
IHookVault vault = IHookVault(vaultAddress);
require(
- allowedNftContract == vault.assetAddress(),
+ allowedUnderlyingAddress == vault.assetAddress(assetId),
"mintWithVault -- token must be on the project allowlist"
);
- require(vault.getHoldsAsset(), "mintWithVault-- asset must be in vault");
+ require(
+ vault.getHoldsAsset(assetId),
+ "mintWithVault-- asset must be in vault"
+ );
// the beneficial owner is the only one able to impose entitlements, so
// we need to require that they've done so here.
- address writer = vault.getBeneficialOwner();
+ address writer = vault.getBeneficialOwner(assetId);
Entitlements.Entitlement memory entitlement = Entitlements.Entitlement({
beneficialOwner: writer,
operator: address(this),
vaultAddress: address(vault),
+ assetId: assetId,
expiry: expirationTime
});
vault.imposeEntitlement(entitlement, signature);
return
- _mintOptionWithVault(writer, address(vault), strikePrice, expirationTime);
+ _mintOptionWithVault(
+ writer,
+ address(vault),
+ assetId,
+ strikePrice,
+ expirationTime
+ );
}
/// @dev See {IHookCoveredCall-mintWithEntitledVault}.
function mintWithEntitledVault(
address vaultAddress,
+ uint256 assetId,
uint256 strikePrice,
uint256 expirationTime
) external whenNotPaused returns (uint256) {
IHookVault vault = IHookVault(vaultAddress);
require(
- allowedNftContract == vault.assetAddress(),
+ allowedUnderlyingAddress == vault.assetAddress(assetId),
"mintWithVault -- token must be on the project allowlist"
);
- require(vault.getHoldsAsset(), "mintWithVault-- asset must be in vault");
- (bool active, address operator) = vault.getCurrentEntitlementOperator();
+ require(
+ vault.getHoldsAsset(assetId),
+ "mintWithVault-- asset must be in vault"
+ );
+ (bool active, address operator) = vault.getCurrentEntitlementOperator(
+ assetId
+ );
require(
active && operator == address(this),
"mintWithVault -- call contact must be the entitled operator"
);
require(
- expirationTime == vault.entitlementExpiration(),
+ expirationTime == vault.entitlementExpiration(assetId),
"mintWithVault -- entitlement expiration must match call expiration"
);
// the beneficial owner owns the asset so
// they should recieve the option.
- address writer = vault.getBeneficialOwner();
+ address writer = vault.getBeneficialOwner(assetId);
return
- _mintOptionWithVault(writer, vaultAddress, strikePrice, expirationTime);
+ _mintOptionWithVault(
+ writer,
+ vaultAddress,
+ assetId,
+ strikePrice,
+ expirationTime
+ );
}
/// @dev See {IHookCoveredCall-mintWithErc721}.
@@ -216,8 +240,9 @@ contract HookCoveredCallImplV1 is
uint256 expirationTime
) external whenNotPaused returns (uint256) {
address tokenOwner = IERC721(tokenAddress).ownerOf(tokenId);
+ uint256 assetId = 0; /// assume that the token is using an individual vault.
require(
- allowedNftContract == tokenAddress,
+ allowedUnderlyingAddress == tokenAddress,
"mintWithErc721 -- token must be on the project allowlist"
);
@@ -246,6 +271,7 @@ contract HookCoveredCallImplV1 is
beneficialOwner: tokenOwner,
operator: address(this),
vaultAddress: vault,
+ assetId: assetId, /// assume that the asset within the vault has assetId 0
expiry: expirationTime
});
@@ -260,11 +286,18 @@ contract HookCoveredCallImplV1 is
// make sure that the vault actually has the asset.
require(
- IHookVault(vault).getHoldsAsset(),
+ IHookVault(vault).getHoldsAsset(assetId),
"mintWithErc712 -- asset must be in vault"
);
- return _mintOptionWithVault(tokenOwner, vault, strikePrice, expirationTime);
+ return
+ _mintOptionWithVault(
+ tokenOwner,
+ vault,
+ assetId,
+ strikePrice,
+ expirationTime
+ );
}
/// @notice internal use function to record the option and mint it
@@ -272,11 +305,13 @@ contract HookCoveredCallImplV1 is
/// has a valid entitlement, and has the asset inside it
/// @param writer the writer of the call option, usually the current owner of the underlying asset
/// @param vaultAddress the address of the IHookVault which contains the underlying asset
+ /// @param assetId the id of the underlying asset
/// @param strikePrice the strike price for this current option, in ETH
/// @param expirationTime the time after which the option will be considered expired
function _mintOptionWithVault(
address writer,
address vaultAddress,
+ uint256 assetId,
uint256 strikePrice,
uint256 expirationTime
) private returns (uint256) {
@@ -294,6 +329,7 @@ contract HookCoveredCallImplV1 is
optionParams[newOptionId] = CallOption({
writer: writer,
vaultAddress: vaultAddress,
+ assetId: assetId,
strike: strikePrice,
expiration: expirationTime,
bid: 0,
@@ -313,6 +349,7 @@ contract HookCoveredCallImplV1 is
emit CallCreated(
writer,
vaultAddress,
+ assetId,
newOptionId,
strikePrice,
expirationTime
@@ -373,7 +410,7 @@ contract HookCoveredCallImplV1 is
// the new high bidder is the beneficial owner of the asset.
// The beneficial owner must be set here instead of with a final bid
// because the ability to
- IHookVault(call.vaultAddress).setBeneficialOwner(msg.sender);
+ IHookVault(call.vaultAddress).setBeneficialOwner(call.assetId, msg.sender);
// emit event
emit Bid(optionId, bidAmt, msg.sender);
@@ -429,7 +466,7 @@ contract HookCoveredCallImplV1 is
_safeTransferETHWithFallback(ownerOf(optionId), spread);
if (returnNft) {
- IHookVault(call.vaultAddress).withdrawalAsset();
+ IHookVault(call.vaultAddress).withdrawalAsset(call.assetId);
}
// burn nft
@@ -481,17 +518,21 @@ contract HookCoveredCallImplV1 is
_safeTransferETHWithFallback(call.highBidder, call.bid);
// if we have a bid, we may have set the bidder, so make sure to revert it here.
- IHookVault(call.vaultAddress).setBeneficialOwner(call.writer);
+ IHookVault(call.vaultAddress).setBeneficialOwner(
+ call.assetId,
+ call.writer
+ );
}
if (returnNft) {
// Because the call is not expired, we should be able to reclaim the asset from the vault
if (call.expiration > block.timestamp) {
IHookVault(call.vaultAddress).clearEntitlementAndDistribute(
+ call.assetId,
call.writer
);
} else {
- IHookVault(call.vaultAddress).withdrawalAsset();
+ IHookVault(call.vaultAddress).withdrawalAsset(call.assetId);
}
}
@@ -507,9 +548,6 @@ contract HookCoveredCallImplV1 is
/// the protocol. Bidders could bid in this settlement auction, and in the middle of the auction the writer
/// could call this reclaim method. If they do that, they'll get their nft back _however_ there is no way for
/// the current bidder to reclaim their money.
- ///
- /// TODO: To fix this, we're specifically sending that high bidder's money back; however, we should verify that
- /// there are not patterns we need to watch here.
}
//// ---- Administrative Fns.
@@ -593,11 +631,15 @@ contract HookCoveredCallImplV1 is
'.base { fill: white; font-family: serif; font-size: 14px; }';
- parts[1] = HookStrings.toAsciiString(vault.assetAddress());
+ parts[1] = HookStrings.toAsciiString(
+ vault.assetAddress(optionParams[tokenId].assetId)
+ );
parts[2] = '';
- parts[3] = HookStrings.toString(vault.assetTokenId());
+ parts[3] = HookStrings.toString(
+ vault.assetTokenId(optionParams[tokenId].assetId)
+ );
parts[4] = "";
diff --git a/src/HookERC721VaultImplV1.sol b/src/HookERC721VaultImplV1.sol
index 03514b7..0240edf 100644
--- a/src/HookERC721VaultImplV1.sol
+++ b/src/HookERC721VaultImplV1.sol
@@ -25,6 +25,8 @@ contract HookERC721VaultImplV1 is
Initializable,
ReentrancyGuard
{
+ uint256 private constant ASSET_ID = 0;
+
/// ---------------- STORAGE ---------------- ///
/// @dev these are the NFT contract address and tokenId the vault is covering
@@ -65,7 +67,7 @@ contract HookERC721VaultImplV1 is
/// @dev See {IHookERC721Vault-withdrawalAsset}.
/// @dev withdrawals can only be performed by the beneficial owner if there are no entitlements
- function withdrawalAsset() external {
+ function withdrawalAsset(uint256) external {
// require(msg.sender == beneficialOwner, "the beneficial owner is the only one able to withdrawl");
require(
!hasActiveEntitlement(),
@@ -74,7 +76,7 @@ contract HookERC721VaultImplV1 is
_nftContract.safeTransferFrom(address(this), beneficialOwner, _tokenId);
- emit AssetWithdrawn(msg.sender, beneficialOwner);
+ emit AssetWithdrawn(ASSET_ID, msg.sender, beneficialOwner);
}
/// @dev See {IHookERC721Vault-imposeEntitlement}.
@@ -166,7 +168,7 @@ contract HookERC721VaultImplV1 is
"onERC721Received -- non-escrow asset returned when airdrops are disabled"
);
}
- emit AssetReceived(from, operator, msg.sender, tokenId);
+ emit AssetReceived(from, operator, msg.sender, tokenId, ASSET_ID);
return this.onERC721Received.selector;
}
@@ -206,15 +208,15 @@ contract HookERC721VaultImplV1 is
}
/// @dev See {IHookERC721Vault-flashLoan}.
- function flashLoan(address receiverAddress, bytes calldata params)
- external
- override
- nonReentrant
- {
+ function flashLoan(
+ uint256 assetId,
+ address receiverAddress,
+ bytes calldata params
+ ) external override nonReentrant {
IERC721FlashLoanReceiver receiver = IERC721FlashLoanReceiver(
receiverAddress
);
-
+ require(assetId == ASSET_ID, "flashLoan -- invalid asset id");
require(receiverAddress != address(0), "flashLoan -- zero address");
require(
msg.sender == beneficialOwner,
@@ -261,7 +263,11 @@ contract HookERC721VaultImplV1 is
/// @notice Looks up the address of the currently entitled operator
/// @dev returns the null address if there is no active entitlement
/// @return operator the address of the current operator
- function entitledOperatorContract() external view returns (address operator) {
+ function entitledOperatorContract(uint256)
+ external
+ view
+ returns (address operator)
+ {
if (!hasActiveEntitlement()) {
return address(0);
} else {
@@ -270,7 +276,11 @@ contract HookERC721VaultImplV1 is
}
/// @dev See {IHookVault-entitlementExpiration}.
- function entitlementExpiration() external view returns (uint256 expiry) {
+ function entitlementExpiration(uint256)
+ external
+ view
+ returns (uint256 expiry)
+ {
if (!hasActiveEntitlement()) {
return 0;
} else {
@@ -279,26 +289,28 @@ contract HookERC721VaultImplV1 is
}
/// @dev See {IHookERC721Vault-getBeneficialOwner}.
- function getBeneficialOwner() external view returns (address) {
+ function getBeneficialOwner(uint256) external view returns (address) {
return beneficialOwner;
}
/// @dev See {IHookERC721Vault-getHoldsAsset}.
- function getHoldsAsset() external view returns (bool holdsAsset) {
+ function getHoldsAsset(uint256) external view returns (bool holdsAsset) {
return _nftContract.ownerOf(_tokenId) == address(this);
}
- function assetAddress() external view returns (address) {
+ function assetAddress(uint256) external view returns (address) {
return address(_nftContract);
}
- function assetTokenId() external view returns (uint256) {
+ function assetTokenId(uint256) external view returns (uint256) {
return _tokenId;
}
/// @dev See {IHookERC721Vault-setBeneficialOwner}.
/// setBeneficialOwner can only be called by the entitlementContract if there is an activeEntitlement.
- function setBeneficialOwner(address newBeneficialOwner) external {
+ function setBeneficialOwner(uint256 assetId, address newBeneficialOwner)
+ external
+ {
if (hasActiveEntitlement()) {
require(
msg.sender == _currentEntitlement.operator,
@@ -310,12 +322,16 @@ contract HookERC721VaultImplV1 is
"setBeneficialOwner -- only the current owner can update the beneficial owner"
);
}
+ require(
+ assetId == ASSET_ID,
+ "setBeneficialOwner -- this contract only contains one asset"
+ );
_setBeneficialOwner(newBeneficialOwner);
}
/// @dev See {IHookERC721Vault-clearEntitlement}.
/// @dev This can only be called if an entitlement currently exists, otherwise it would be a no-op
- function clearEntitlement() public {
+ function clearEntitlement(uint256) public {
require(
hasActiveEntitlement(),
"clearEntitlement -- an active entitlement must exist"
@@ -332,7 +348,7 @@ contract HookERC721VaultImplV1 is
/// intended reciever, which should match the beneficialOwner. The function will throw if
/// the reciever and owner do not match.
/// @param reciever the intended reciever of the asset
- function clearEntitlementAndDistribute(address reciever)
+ function clearEntitlementAndDistribute(uint256, address reciever)
external
nonReentrant
{
@@ -340,9 +356,9 @@ contract HookERC721VaultImplV1 is
beneficialOwner == reciever,
"clearEntitlementAndDistribute -- Only the beneficial owner can recieve the asset"
);
- clearEntitlement();
+ clearEntitlement(ASSET_ID);
IERC721(_nftContract).safeTransferFrom(address(this), reciever, _tokenId);
- emit AssetWithdrawn(msg.sender, beneficialOwner);
+ emit AssetWithdrawn(ASSET_ID, msg.sender, beneficialOwner);
}
/// @dev Get the EIP-712 hash of an Entitlement.
@@ -397,9 +413,14 @@ contract HookERC721VaultImplV1 is
entitlement.vaultAddress == address(this),
"_verifyAndRegisterEntitlement -- the entitled contract must match the vault contract"
);
+ require(
+ entitlement.assetId == ASSET_ID,
+ "_verifyAndRegisterEntitlement -- the entitled contract must match the vault contract"
+ );
_currentEntitlement = entitlement;
_hasEntitlement = true;
emit EntitlementImposed(
+ ASSET_ID,
entitlement.operator,
entitlement.expiry,
beneficialOwner
@@ -411,17 +432,18 @@ contract HookERC721VaultImplV1 is
address(0),
address(0),
address(0),
+ ASSET_ID,
0
);
_hasEntitlement = false;
- emit EntitlementCleared(beneficialOwner);
+ emit EntitlementCleared(ASSET_ID, beneficialOwner);
}
function hasActiveEntitlement() public view returns (bool) {
return block.timestamp < _currentEntitlement.expiry && _hasEntitlement;
}
- function getCurrentEntitlementOperator()
+ function getCurrentEntitlementOperator(uint256)
external
view
returns (bool isActive, address operator)
@@ -436,6 +458,6 @@ contract HookERC721VaultImplV1 is
"_setBeneficialOwner -- new owner is the zero address"
);
beneficialOwner = newBeneficialOwner;
- emit BeneficialOwnerSet(newBeneficialOwner, msg.sender);
+ emit BeneficialOwnerSet(ASSET_ID, newBeneficialOwner, msg.sender);
}
}
diff --git a/src/interfaces/IHookCoveredCall.sol b/src/interfaces/IHookCoveredCall.sol
index f3cc8a9..e45316a 100644
--- a/src/interfaces/IHookCoveredCall.sol
+++ b/src/interfaces/IHookCoveredCall.sol
@@ -31,16 +31,23 @@ import "../lib/Signatures.sol";
/// of the instrument NFT, the strike price is transferred to the writer. The high bid is transferred to the holder of
/// the option.
interface IHookCoveredCall is IERC721 {
+ /// @notice emitted when a new call option is successfully minted with a specific underlying vault
event CallCreated(
address writer,
address vaultAddress,
+ uint256 assetId,
uint256 optionId,
uint256 strikePrice,
uint256 expiration
);
+ /// @notice emitted when a call option is destroyed
event CallDestroyed(uint256 optionId);
+ /// @notice emitted when a call option settlement auction gets and accepts a new bid
+ /// @param bidder the account placing the bid that is now the high bidder
+ /// @param bidAmount the amount of the bid (in wei)
+ /// @param optionId the option for the underlying that was bid on
event Bid(uint256 optionId, uint256 bidAmount, address bidder);
/// @notice Mints a new call option for a particular "underlying" ERC-721 NFT with a given strike price and expiration
@@ -57,26 +64,30 @@ interface IHookCoveredCall is IERC721 {
) external returns (uint256);
/// @notice Mints a new call option for the assets deposited in a particular vault given strike price and expiration.
- /// @param _vaultAddress the contract address of the vault currently holding the call option
- /// @param _strikePrice the strike price for the call option being written
- /// @param _expirationTime time the timestamp after which the option will be expired
+ /// @param vaultAddress the contract address of the vault currently holding the call option
+ /// @param assetId the id of the asset within the vault
+ /// @param strikePrice the strike price for the call option being written
+ /// @param expirationTime time the timestamp after which the option will be expired
/// @param signature the signature used to place the entitlement onto the vault
function mintWithVault(
- address _vaultAddress,
- uint256 _strikePrice,
- uint256 _expirationTime,
+ address vaultAddress,
+ uint256 assetId,
+ uint256 strikePrice,
+ uint256 expirationTime,
Signatures.Signature calldata signature
) external returns (uint256);
/// @notice Mints a new call option for the assets deposited in a particular vault given strike price and expiration.
/// That vault must already have a registered entitlement for this contract with the correct expiration registered.
- /// @param _vaultAddress the contract address of the vault currently holding the call option
- /// @param _strikePrice the strike price for the call option being written
- /// @param _expirationTime time the timestamp after which the option will be expired
+ /// @param vaultAddress the contract address of the vault currently holding the call option
+ /// @param assetId the id of the asset within the vault
+ /// @param strikePrice the strike price for the call option being written
+ /// @param expirationTime time the timestamp after which the option will be expired
function mintWithEntitledVault(
- address _vaultAddress,
- uint256 _strikePrice,
- uint256 _expirationTime
+ address vaultAddress,
+ uint256 assetId,
+ uint256 strikePrice,
+ uint256 expirationTime
) external returns (uint256);
/// @notice Bid in the settlement auction for an option. The paid amount is the bid,
diff --git a/src/interfaces/IHookERC721Vault.sol b/src/interfaces/IHookERC721Vault.sol
index d99e3f6..4e672e7 100644
--- a/src/interfaces/IHookERC721Vault.sol
+++ b/src/interfaces/IHookERC721Vault.sol
@@ -21,7 +21,7 @@ interface IHookERC721Vault is IHookVault, IERC721Receiver {
event AssetFlashLoaned(address owner, address flashLoanImpl);
/// @notice the tokenID of the underlying ERC721 token;
- function assetTokenId() external view returns (uint256);
+ function assetTokenId(uint256 assetId) external view returns (uint256);
/// @notice flashLoans the vaulted asset to another contract for use and return to the vault. Only the owner
/// may perform the flashloan
@@ -30,5 +30,9 @@ interface IHookERC721Vault is IHookVault, IERC721Receiver {
/// @param receiverAddress the contract which implements the {IERC721FlashLoanReceiver} interface to utilize the
/// asset while it is loaned out
/// @param params calldata params to forward to the reciever
- function flashLoan(address receiverAddress, bytes calldata params) external;
+ function flashLoan(
+ uint256 assetId,
+ address receiverAddress,
+ bytes calldata params
+ ) external;
}
diff --git a/src/interfaces/IHookVault.sol b/src/interfaces/IHookVault.sol
index 0751920..aff30e1 100644
--- a/src/interfaces/IHookVault.sol
+++ b/src/interfaces/IHookVault.sol
@@ -28,7 +28,7 @@ interface IHookVault {
/// @notice emitted when an entitlement is placed on an asset
event EntitlementImposed(
uint256 assetId,
- address entitledAccout,
+ address entitledAccount,
uint256 expiry,
address beneficialOwner
);
@@ -54,6 +54,8 @@ interface IHookVault {
uint256 assetId
);
+ event AssetWithdrawn(uint256 assetId, address to, address beneficialOwner);
+
/// @notice Withdrawal an unencumbered asset from this vault
/// @param assetId the asset to remove from the vault
function withdrawalAsset(uint256 assetId) external;
diff --git a/src/lib/Entitlements.sol b/src/lib/Entitlements.sol
index 684648c..4ebdc0d 100644
--- a/src/lib/Entitlements.sol
+++ b/src/lib/Entitlements.sol
@@ -3,8 +3,6 @@ pragma solidity ^0.8.10;
import "./Signatures.sol";
library Entitlements {
- // TODO: Should we add a nonce to this struct? This would allow us to make the
- // tokenIds cancelable.
uint256 private constant _ENTITLEMENT_TYPEHASH =
uint256(
keccak256(
diff --git a/src/test/HookCoveredCallIntegrationTest.sol b/src/test/HookCoveredCallIntegrationTest.sol
index 1033c45..8d418e5 100644
--- a/src/test/HookCoveredCallIntegrationTest.sol
+++ b/src/test/HookCoveredCallIntegrationTest.sol
@@ -38,6 +38,7 @@ contract HookCoveredCallIntegrationTest is HookProtocolTest {
emit CallCreated(
address(writer),
address(token),
+ 0,
1, // This would be the first option id.
1000,
expiration
diff --git a/src/test/HookCoveredCallTests.sol b/src/test/HookCoveredCallTests.sol
index f741d39..aea0b71 100644
--- a/src/test/HookCoveredCallTests.sol
+++ b/src/test/HookCoveredCallTests.sol
@@ -34,6 +34,7 @@ contract HookCoveredCallMintTests is HookProtocolTest {
emit CallCreated(
address(writer),
address(token),
+ 0,
1, // This would be the first option id.
1000,
expiration
@@ -70,10 +71,11 @@ contract HookCoveredCallMintTests is HookProtocolTest {
writer
);
vm.expectEmit(true, true, true, true);
- emit CallCreated(address(writer), address(vault), 1, 1000, expiration);
+ emit CallCreated(address(writer), address(vault), 0, 1, 1000, expiration);
uint256 optionId = calls.mintWithVault(
address(vault),
+ 0,
1000,
expiration,
sig
@@ -84,7 +86,7 @@ contract HookCoveredCallMintTests is HookProtocolTest {
"owner should own the option"
);
- (bool isActive, address operator) = vault.getCurrentEntitlementOperator();
+ (bool isActive, address operator) = vault.getCurrentEntitlementOperator(0);
assertTrue(isActive, "there should be an active entitlement");
assertTrue(
operator == address(calls),
@@ -116,6 +118,7 @@ contract HookCoveredCallMintTests is HookProtocolTest {
);
uint256 optionId = calls.mintWithVault(
address(vault),
+ 0,
1000,
expiration,
sig
@@ -141,6 +144,7 @@ contract HookCoveredCallMintTests is HookProtocolTest {
vm.expectRevert("mintWithVault-- asset must be in vault");
uint256 optionId = calls.mintWithVault(
address(vault),
+ 0,
1000,
expiration,
sig
@@ -166,6 +170,7 @@ contract HookCoveredCallMintTests is HookProtocolTest {
vm.expectRevert("mintWithVault -- token must be on the project allowlist");
uint256 optionId = calls.mintWithVault(
address(vault),
+ 0,
1000,
expiration,
sig
@@ -189,6 +194,7 @@ contract HookCoveredCallMintTests is HookProtocolTest {
emit CallCreated(
address(writer),
address(token),
+ 0,
1, // This would be the first option id.
1000,
expiration
@@ -213,6 +219,7 @@ contract HookCoveredCallMintTests is HookProtocolTest {
emit CallCreated(
address(writer),
address(token),
+ 0,
2, // This would be the second option id.
1000,
expiration
@@ -249,6 +256,7 @@ contract HookCoveredCallMintTests is HookProtocolTest {
emit CallCreated(
address(writer),
address(token),
+ 0,
1, // This would be the first option id.
1000,
expiration
@@ -292,7 +300,7 @@ contract HookCoveredCallMintTests is HookProtocolTest {
vm.expectRevert(
"validateEntitlementSignature --- not signed by beneficialOwner"
);
- calls.mintWithVault(address(vault), 1000, expiration, signature);
+ calls.mintWithVault(address(vault), 0, 1000, expiration, signature);
}
function testCannotMintOptionInvalidExpiration() public {
@@ -411,6 +419,7 @@ contract HookCoveredCallMintTests is HookProtocolTest {
emit CallCreated(
address(writer),
address(token),
+ 0,
1, // This would be the first option id.
1000,
expiration
@@ -450,6 +459,7 @@ contract HookCoveredCallMintTests is HookProtocolTest {
emit CallCreated(
address(writer),
address(token),
+ 0,
1, // This would be the first option id.
1000,
expiration
@@ -481,6 +491,7 @@ contract HookCoveredCallMintTests is HookProtocolTest {
emit CallCreated(
address(writer),
address(token),
+ 0,
1, // This would be the first option id.
1000,
expiration
@@ -513,6 +524,7 @@ contract HookCoveredCallMintTests is HookProtocolTest {
emit CallCreated(
address(writer),
address(token),
+ 0,
1, // This would be the first option id.
1000,
expiration
@@ -556,6 +568,7 @@ contract HookCoveredCallMintTests is HookProtocolTest {
emit CallCreated(
address(writer),
address(token),
+ 0,
1, // This would be the first option id.
1000,
expiration
@@ -910,7 +923,10 @@ contract HookCoveredCallSettleTests is HookProtocolTest {
address(token),
underlyingTokenId
);
- vm.expectCall(vaultAddress, abi.encodeWithSignature("withdrawalAsset()"));
+ vm.expectCall(
+ vaultAddress,
+ abi.encodeWithSignature("withdrawalAsset(uint256)", 0)
+ );
vm.prank(writer);
calls.settleOption(optionTokenId, true);
@@ -1221,7 +1237,10 @@ contract HookCoveredCallReclaimTests is HookProtocolTest {
address(token),
underlyingTokenId
);
- vm.expectCall(vaultAddress, abi.encodeWithSignature("withdrawalAsset()"));
+ vm.expectCall(
+ vaultAddress,
+ abi.encodeWithSignature("withdrawalAsset(uint256)", 0)
+ );
calls.reclaimAsset(optionTokenId, true);
}
@@ -1311,7 +1330,10 @@ contract HookCoveredCallReclaimTests is HookProtocolTest {
address(token),
underlyingTokenId
);
- vm.expectCall(vaultAddress, abi.encodeWithSignature("withdrawalAsset()"));
+ vm.expectCall(
+ vaultAddress,
+ abi.encodeWithSignature("withdrawalAsset(uint256)", 0)
+ );
calls.reclaimAsset(optionTokenId, true);
}
@@ -1360,7 +1382,10 @@ contract HookCoveredCallReclaimTests is HookProtocolTest {
address(token),
underlyingTokenId
);
- vm.expectCall(vaultAddress, abi.encodeWithSignature("withdrawalAsset()"));
+ vm.expectCall(
+ vaultAddress,
+ abi.encodeWithSignature("withdrawalAsset(uint256)", 0)
+ );
calls.reclaimAsset(optionTokenId, true);
}
@@ -1412,7 +1437,10 @@ contract HookCoveredCallReclaimTests is HookProtocolTest {
address(token),
underlyingTokenId
);
- vm.expectCall(vaultAddress, abi.encodeWithSignature("withdrawalAsset()"));
+ vm.expectCall(
+ vaultAddress,
+ abi.encodeWithSignature("withdrawalAsset(uint256)", 0)
+ );
calls.reclaimAsset(optionTokenId, true);
}
}
diff --git a/src/test/HookVaultTests.sol b/src/test/HookVaultTests.sol
index 7879d07..3cace63 100644
--- a/src/test/HookVaultTests.sol
+++ b/src/test/HookVaultTests.sol
@@ -54,6 +54,7 @@ contract HookVaultTests is HookProtocolTest {
beneficialOwner: ownerAdd,
operator: operator,
vaultAddress: vaultAddress,
+ assetId: 0,
expiry: _expiry
});
@@ -100,11 +101,11 @@ contract HookVaultTests is HookProtocolTest {
HookERC721VaultImplV1 vaultImpl = HookERC721VaultImplV1(vaultAddress);
assertTrue(
- vaultImpl.getHoldsAsset(),
+ vaultImpl.getHoldsAsset(0),
"the token should be owned by the vault"
);
assertTrue(
- vaultImpl.getBeneficialOwner() == writer,
+ vaultImpl.getBeneficialOwner(0) == writer,
"writer should be the beneficial owner"
);
assertTrue(
@@ -142,7 +143,7 @@ contract HookVaultTests is HookProtocolTest {
IERC721FlashLoanReceiver flashLoan = new FlashLoanSuccess();
vm.prank(writer);
- vaultImpl.flashLoan(address(flashLoan), " ");
+ vaultImpl.flashLoan(0, address(flashLoan), " ");
assertTrue(
token.ownerOf(tokenId) == vaultAddress,
"good flashloan should work"
@@ -186,7 +187,7 @@ contract HookVaultTests is HookProtocolTest {
vm.expectRevert(
"flashLoan -- flashLoan feature disabled for this contract"
);
- vaultImpl.flashLoan(address(flashLoan), " ");
+ vaultImpl.flashLoan(0, address(flashLoan), " ");
assertTrue(
token.ownerOf(tokenId) == vaultAddress,
"good flashloan should work"
@@ -222,7 +223,7 @@ contract HookVaultTests is HookProtocolTest {
IERC721FlashLoanReceiver flashLoan = new FlashLoanApproveForAll();
vm.prank(writer);
- vaultImpl.flashLoan(address(flashLoan), " ");
+ vaultImpl.flashLoan(0, address(flashLoan), " ");
assertTrue(
token.ownerOf(tokenId) == vaultAddress,
"good flashloan should work"
@@ -259,7 +260,7 @@ contract HookVaultTests is HookProtocolTest {
vm.prank(writer);
vm.expectRevert("flashLoan -- the flash loan contract must return true");
- vaultImpl.flashLoan(address(flashLoan), " ");
+ vaultImpl.flashLoan(0, address(flashLoan), " ");
assertTrue(
token.ownerOf(tokenId) == vaultAddress,
"good flashloan should work"
@@ -296,7 +297,7 @@ contract HookVaultTests is HookProtocolTest {
vm.prank(writer);
vm.expectRevert("ERC721: transfer caller is not owner nor approved");
- vaultImpl.flashLoan(address(flashLoan), " ");
+ vaultImpl.flashLoan(0, address(flashLoan), " ");
assertTrue(
token.ownerOf(tokenId) == vaultAddress,
"good flashloan should work"
@@ -333,7 +334,7 @@ contract HookVaultTests is HookProtocolTest {
vm.prank(writer);
vm.expectRevert("ERC721: operator query for nonexistent token");
- vaultImpl.flashLoan(address(flashLoan), " ");
+ vaultImpl.flashLoan(0, address(flashLoan), " ");
// operation reverted, so we can still mess with the asset
assertTrue(
token.ownerOf(tokenId) == vaultAddress,
@@ -370,7 +371,7 @@ contract HookVaultTests is HookProtocolTest {
IERC721FlashLoanReceiver flashLoan = new FlashLoanVerifyCalldata();
vm.prank(writer);
- vaultImpl.flashLoan(address(flashLoan), "hello world");
+ vaultImpl.flashLoan(0, address(flashLoan), "hello world");
// operation reverted, so we can still mess with the asset
assertTrue(
token.ownerOf(tokenId) == vaultAddress,
@@ -408,7 +409,7 @@ contract HookVaultTests is HookProtocolTest {
vm.prank(writer);
vm.expectRevert("should check helloworld");
- vaultImpl.flashLoan(address(flashLoan), "hello world wrong!");
+ vaultImpl.flashLoan(0, address(flashLoan), "hello world wrong!");
// operation reverted, so we can still mess with the asset
assertTrue(
token.ownerOf(tokenId) == vaultAddress,
@@ -443,11 +444,11 @@ contract HookVaultTests is HookProtocolTest {
vaultImpl.imposeEntitlement(entitlement, sig);
assertTrue(
- vaultImpl.getHoldsAsset(),
+ vaultImpl.getHoldsAsset(0),
"the token should be owned by the vault"
);
assertTrue(
- vaultImpl.getBeneficialOwner() == writer,
+ vaultImpl.getBeneficialOwner(0) == writer,
"writer should be the beneficial owner"
);
assertTrue(
@@ -461,7 +462,7 @@ contract HookVaultTests is HookProtocolTest {
"withdrawalAsset -- the asset canot be withdrawn with an active entitlement"
);
vm.prank(writer);
- vaultImpl.withdrawalAsset();
+ vaultImpl.withdrawalAsset(0);
}
function testEntitlementGoesAwayAfterExpiration() public {
@@ -502,9 +503,9 @@ contract HookVaultTests is HookProtocolTest {
);
vm.prank(writer);
- vaultImpl.withdrawalAsset();
+ vaultImpl.withdrawalAsset(0);
assertTrue(
- !vaultImpl.getHoldsAsset(),
+ !vaultImpl.getHoldsAsset(0),
"the token should not be owned by the vault"
);
@@ -540,7 +541,7 @@ contract HookVaultTests is HookProtocolTest {
HookERC721VaultImplV1 vaultImpl = HookERC721VaultImplV1(vaultAddress);
vm.prank(mockContract);
- vaultImpl.clearEntitlement();
+ vaultImpl.clearEntitlement(0);
assertTrue(
!vaultImpl.hasActiveEntitlement(),
@@ -549,9 +550,9 @@ contract HookVaultTests is HookProtocolTest {
// check that the owner can actually withdrawl
vm.prank(writer);
- vaultImpl.withdrawalAsset();
+ vaultImpl.withdrawalAsset(0);
assertTrue(
- !vaultImpl.getHoldsAsset(),
+ !vaultImpl.getHoldsAsset(0),
"the token should not be owned by the vault"
);
@@ -648,7 +649,7 @@ contract HookVaultTests is HookProtocolTest {
);
vm.prank(mockContract);
- vaultImpl.clearEntitlement();
+ vaultImpl.clearEntitlement(0);
assertTrue(
!vaultImpl.hasActiveEntitlement(),
@@ -677,7 +678,7 @@ contract HookVaultTests is HookProtocolTest {
function testOnlyOneEntitlementAllowed() public {
(address vaultAddress, uint256 tokenId) = createVaultandAsset();
- address mockContract = address(69);
+ address mockContract = address(3333);
uint256 expiration = block.timestamp + 1 days;
(
@@ -761,13 +762,13 @@ contract HookVaultTests is HookProtocolTest {
vm.expectRevert(
"clearEntitlement -- only the entitled address can clear the entitlement"
);
- vaultImpl.clearEntitlement();
+ vaultImpl.clearEntitlement(0);
vm.prank(address(55566677788899911));
vm.expectRevert(
"clearEntitlement -- only the entitled address can clear the entitlement"
);
- vaultImpl.clearEntitlement();
+ vaultImpl.clearEntitlement(0);
}
function testClearAndDistributeReturnsNFT() public {
@@ -796,7 +797,7 @@ contract HookVaultTests is HookProtocolTest {
HookERC721VaultImplV1 vaultImpl = HookERC721VaultImplV1(vaultAddress);
vm.prank(mockContract);
- vaultImpl.clearEntitlementAndDistribute(writer);
+ vaultImpl.clearEntitlementAndDistribute(0, writer);
assertTrue(
!vaultImpl.hasActiveEntitlement(),
@@ -870,6 +871,6 @@ contract HookVaultTests is HookProtocolTest {
"clearEntitlementAndDistribute -- Only the beneficial owner can recieve the asset"
);
vm.prank(mockContract);
- vaultImpl.clearEntitlementAndDistribute(address(0x033333344545));
+ vaultImpl.clearEntitlementAndDistribute(0, address(0x033333344545));
}
}
diff --git a/src/test/utils/base.sol b/src/test/utils/base.sol
index 69adc8d..02eac44 100644
--- a/src/test/utils/base.sol
+++ b/src/test/utils/base.sol
@@ -45,6 +45,7 @@ contract HookProtocolTest is Test, EIP712, PermissionConstants {
event CallCreated(
address writer,
address vaultAddress,
+ uint256 assetId,
uint256 optionId,
uint256 strikePrice,
uint256 expiration
@@ -117,6 +118,7 @@ contract HookProtocolTest is Test, EIP712, PermissionConstants {
emit CallCreated(
address(writer),
address(token),
+ 0,
1, // This would be the first option id.
1000,
expiration
@@ -168,6 +170,7 @@ contract HookProtocolTest is Test, EIP712, PermissionConstants {
beneficialOwner: address(writer),
operator: address(calls),
vaultAddress: va,
+ assetId: 0,
expiry: expiry
})
);