From c4900dcc0c62647b30f1b77c41d92789073fa75c Mon Sep 17 00:00:00 2001 From: MrDeadCe11 <84342118+MrDeadCe11@users.noreply.github.com> Date: Tue, 25 Jun 2024 14:26:08 -0500 Subject: [PATCH] updated natspec and readme (#43) * updated natspec and readme * Final cleanup * author ordering --------- Co-authored-by: Patrick Gallagher --- README.md | 39 ++++++++++++------- src/contracts/SIP15Zone.sol | 18 ++++++--- src/contracts/Vault721Adapter.sol | 2 +- src/sips/SIP15Decoder.sol | 35 ++++++++++++++++- src/sips/SIP15Encoder.sol | 24 ++++++++++-- test/e2e/SetUp.sol | 2 +- ...ansferValidationSIP15ZoneOffererTest.t.sol | 4 +- 7 files changed, 94 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 6e7415d..fab2088 100644 --- a/README.md +++ b/README.md @@ -11,15 +11,17 @@

-# Dynamic Traits Enforcement Zone +# Dynamic Traits Enforcement Zone -A Seaport zone for specifying and enforcing values of ERC-7496 Dynamic Traits +A Seaport zone which implements [ERC-7496](https://eips.ethereum.org/EIPS/eip-7496) to enforce NFT trait details. -View the SIP-15 standard: https://github.com/open-dollar/SIPs/blob/main/SIPS/sip-15.md +The zone was developed to align with the [SIP-15](https://github.com/open-dollar/SIPs/blob/main/SIPS/sip-15.md) standard from Seaport. ## Setup -1. Copy the `.env.example` and update the following values: +Use the command-line scripts to create, submit, and fulfill an order for an Open Dollar NFV, using the OpenSea API. + +1. Copy the `.env.example` and update the following values: ```bash ARB_SEPOLIA_RPC= @@ -28,26 +30,35 @@ ARB_SEPOLIA_OFFERER_PK= ARB_SEPOLIA_BUYER_PK= ``` -2. Use the “Offerer” wallet to open a vault on Open Dollar testnet https://app.dev.opendollar.com +2. Use the “Offerer” wallet to open a vault on Open Dollar testnet https://app.dev.opendollar.com -2. User the “Buyer” wallet to mint the consideration token "ARB" at https://sepolia.arbiscan.io/address/0x3018EC2AD556f28d2c0665d10b55ebfa469fD749#writeContract +3. User the “Buyer” wallet to mint the consideration token "ARB" at https://sepolia.arbiscan.io/address/0x3018EC2AD556f28d2c0665d10b55ebfa469fD749#writeContract +## Create Listing -## Create listing +Use the `create-listing` scrip to create an order from the "Offerer" wallet. ```bash -yarn +# Install and build the contracts +yarn yarn build -# Create Listing yarn create-listing -yarn create-listing sepolia 313 0.000001 +# eg. +yarn create-listing sepolia 313 0.000001 +``` + +## Fulfill Order -# Execute listing +Use the fulfill script to execute the order from the "Buyer" wallet. + +```bash yarn fulfill +# eg. yarn fulfill sepolia orders/order-1-1718667016.json ``` -Notes: -- Vaults have a 100 second cooldown on testnet before they can be transferred. -- Order `endTime` is 24 hours +Important Notes: + +- On testnet, Open Dollar NFVs have a 100 second cooldown after any modification before they can be transferred. +- The default order `endTime` is currently 24 hours. diff --git a/src/contracts/SIP15Zone.sol b/src/contracts/SIP15Zone.sol index ae46312..cbb396c 100644 --- a/src/contracts/SIP15Zone.sol +++ b/src/contracts/SIP15Zone.sol @@ -12,10 +12,10 @@ import {SIP15ZoneEventsAndErrors} from '../interfaces/SIP15ZoneEventsAndErrors.s import {ISIP15Zone} from '../interfaces/ISIP15Zone.sol'; /** - * @title ODSeaportZone - * @author MrDeadce11 & stephankmin - * @notice SIP15Zone is an implementation of SIP-15. It verifies that the dynamic traits of an NFT - * have not changed between the time of order creation and the time of order fulfillment. + * @title DynamicTraitsEnforcementZone + * @author MrDeadCe11, daopunk, pi0neerpat, CupOJoseph, stephankmin + * @notice DynamicTraitsEnforcementZone is an implementation of SIP-15 for enforcing ERC-7496 traits. It verifies the state of + * dynamic traits after a transfer and supports substandards 1 through 5. Substandard docs: https://github.com/open-dollar/SIPs/blob/main/SIPS/sip-15.md */ contract SIP15Zone is ERC165, ISIP15Zone, SIP15ZoneEventsAndErrors { using SIP15Decoder for bytes; @@ -25,7 +25,7 @@ contract SIP15Zone is ERC165, ISIP15Zone, SIP15ZoneEventsAndErrors { constructor() {} /** - * @dev Validates an order. + * @dev Validates an order. called after order is fulfilled and offers and considerations have been transfered * * @param zoneParameters The context about the order fulfillment and any * supplied extraData. @@ -55,6 +55,10 @@ contract SIP15Zone is ERC165, ISIP15Zone, SIP15ZoneEventsAndErrors { return this.validateOrder.selector; } + /** + * @dev called before order fulfillment. no authorization is required for this zone. + * @return authorizedOrderMagicValue the bytes4 magic order value that authorizes the order + */ function authorizeOrder(ZoneParameters calldata /* zoneParameters*/ ) external view @@ -62,6 +66,10 @@ contract SIP15Zone is ERC165, ISIP15Zone, SIP15ZoneEventsAndErrors { { return this.authorizeOrder.selector; } + /** + * @dev decodes extraData acording to the substandard and then checks the traits according to + * the designated comparison enum/enums. See SIP15encoder for encoding details. + */ function _validateSubstandard(uint8 substandardVersion, bytes calldata extraData) internal view { address token; diff --git a/src/contracts/Vault721Adapter.sol b/src/contracts/Vault721Adapter.sol index ca46299..ac35ff5 100644 --- a/src/contracts/Vault721Adapter.sol +++ b/src/contracts/Vault721Adapter.sol @@ -7,7 +7,7 @@ import {IERC7496} from 'shipyard-core/src/dynamic-traits/interfaces/IERC7496.sol import {IERC721} from '@openzeppelin/token/ERC721/IERC721.sol'; /** * @title Adds support for ERC7496 to an existing ERC721 - * @author OpenFi Foundation + * @author daopunk, MrDeadCe11, pi0neerpat, CupOJoseph * @notice IERC7496 events are never emitted since NFVState is tracked in Vault721 */ diff --git a/src/sips/SIP15Decoder.sol b/src/sips/SIP15Decoder.sol index 287e57a..b0a43c3 100644 --- a/src/sips/SIP15Decoder.sol +++ b/src/sips/SIP15Decoder.sol @@ -8,12 +8,18 @@ library SIP15Decoder { /** * @notice Read the SIP15 substandard version byte from the extraData field of a SIP15 encoded bytes array. * @param extraData bytes calldata + * @return substandard the single byte substandard number 0-5 */ function decodeSubstandardVersion(bytes calldata extraData) internal pure returns (bytes1 substandard) { return BaseSIPDecoder.decodeSubstandardVersion(extraData); } + /** + * @notice decodes data encoding with substandard1Efficient encoder + * @param extraData the encoded bytes with substandard and the extra data + * @return (uint8 comparisonEnum, address token, uint256 identifier, bytes32 traitValue, bytes32 traitKey) + */ - function decodeSubstandard1(bytes calldata extraData) + function decodeSubstandard1Efficient(bytes calldata extraData) internal pure returns (uint8, address, uint256, bytes32, bytes32) @@ -21,7 +27,12 @@ library SIP15Decoder { return _decodeSingleTraitsWithOffset(extraData, 1); } - function decodeSubstandard1Efficient(bytes calldata extraData) + /** + * @notice decodes data encoding with substandard1 encoder + * @param extraData the encoded bytes with substandard and the extra data + * @return (uint8 comparisonEnum, address token, uint256 identifier, bytes32 traitValue, bytes32 traitKey) + */ + function decodeSubstandard1(bytes calldata extraData) internal pure returns (uint8, address, uint256, bytes32, bytes32) @@ -29,6 +40,11 @@ library SIP15Decoder { return _decodeSingleTraitsWithOffset(extraData, 1); } + /** + * @notice decodes data encoding with substandard2 encoder + * @param extraData the encoded bytes with substandard and the extra data + * @return (uint8 comparisonEnum, address token, uint256 identifier, bytes32 traitValue, bytes32 traitKey) + */ function decodeSubstandard2(bytes calldata extraData) internal pure @@ -37,6 +53,11 @@ library SIP15Decoder { return _decodeSingleTraitsWithOffset(extraData, 1); } + /** + * @notice decodes data encoding with substandard3 encoder + * @param extraData the encoded bytes with substandard and the extra data + * @return (uint8 comparisonEnum, address token, uint256 identifier, bytes32 traitValue, bytes32 traitKey) + */ function decodeSubstandard3(bytes calldata extraData) internal pure @@ -45,6 +66,11 @@ library SIP15Decoder { return _decodeSingleTraitsWithOffset(extraData, 1); } + /** + * @notice decodes data encoding with substandard4 encoder + * @param extraData the encoded bytes with substandard and the extra data + * @return (uint8 comparisonEnum, address token, uint256[] identifiers, bytes32 traitValue, bytes32 traitKey) + */ function decodeSubstandard4(bytes calldata extraData) internal pure @@ -53,6 +79,11 @@ library SIP15Decoder { return abi.decode(extraData[1:], (uint8, address, uint256[], bytes32, bytes32)); } + /** + * @notice decodes data encoding with substandard1 encoder + * @param extraData the encoded bytes with substandard and the extra data + * @return Substandard5Comparison + */ function decodeSubstandard5(bytes calldata extraData) internal pure returns (Substandard5Comparison memory) { return abi.decode(extraData[1:], (Substandard5Comparison)); } diff --git a/src/sips/SIP15Encoder.sol b/src/sips/SIP15Encoder.sol index a728d11..1cab67f 100644 --- a/src/sips/SIP15Encoder.sol +++ b/src/sips/SIP15Encoder.sol @@ -18,6 +18,7 @@ library SIP15Encoder { /** * @notice Generate a zone hash for an SIP15 contract, * @param encodedData the SIP15 encoded extra data + * @return bytes32 hashed encoded data */ function generateZoneHash(bytes memory encodedData) internal pure returns (bytes32) { return keccak256(abi.encodePacked(encodedData)); @@ -26,7 +27,9 @@ library SIP15Encoder { /** * @notice Encode extraData for SIP15-substandard-1 Efficient, which specifies the * first consideration item, comparison "equal to", single trait key, zero trait value + * @param zoneParameters the orderParams of the order to be encoded * @param traitKey the bytes32 encoded trait key for checking a trait on an ERC7496 token + * @return bytes the encoded extra data with added substandard */ function encodeSubstandard1Efficient( ZoneParameters memory zoneParameters, @@ -42,10 +45,12 @@ library SIP15Encoder { /** * @notice Encode extraData for SIP15-substandard-1, which specifies the - * first offer item, token address and id from first offer item + * token address and id from first offer item + * @param zoneParameters the zone parameters with the offer to be used for the token and identifier * @param comparisonEnum the comparison enum 0 - 5 * @param traitKey the bytes32 encoded trait key for checking a trait on an ERC7496 token * @param traitValue the expected value of the trait. + * @return bytes the encoded extra data with added substandard */ function encodeSubstandard1( ZoneParameters memory zoneParameters, @@ -63,11 +68,12 @@ library SIP15Encoder { /** * @notice Encode extraData for SIP15-substandard-2, which specifies - * the token and identifier from the first consideration item as well as a comparison enum, trait key and trait value - * @param zoneParameters memory zoneParameters, + * the token and identifier from the first consideration item as well as a comparison enum, trait key and expected trait value + * @param zoneParameters the zoneParameters of the order whose first consideration will be used for the token and identifier * @param comparisonEnum The comparison enum 0 - 5 * @param traitValue The expecta value of the trait * @param traitKey the bytes32 encoded trait key for checking a trait on an ERC7496 token + * @return bytes the encoded extra data with added substandard */ function encodeSubstandard2( ZoneParameters memory zoneParameters, @@ -91,6 +97,7 @@ library SIP15Encoder { * @param identifier the tokenId of the token to be checked * @param traitKey the bytes32 encoded trait key for checking a trait on an ERC7496 token * @param traitValue the expected value of the trait. + * @return bytes the encoded extra data with added substandard */ function encodeSubstandard3( uint8 comparisonEnum, @@ -111,6 +118,7 @@ library SIP15Encoder { * @param identifiers the tokenId of the token to be checked * @param traitKey the bytes32 encoded trait key for checking a trait on an ERC7496 token * @param traitValue the expected value of the trait. + * @return bytes the encoded extra data with added substandard */ function encodeSubstandard4( uint8 comparisonEnum, @@ -124,7 +132,15 @@ library SIP15Encoder { /** * @notice Encode extraData for SIP15-substandard-5, which specifies a single tokenIdentifier - * @param comparisonStruct the struct of comparison data + * @param comparisonStruct the struct of comparison data with the following values: + * - uint8[] comparisonEnums the array of comparison enums for each trait key and expected value, must be the same length as the trait keys and values. + * - address token the address of the token whose traits will be checked + * - address traits the address that contains the ERC7496 traits. this is useful if you have an erc712 with traits availible at a + * different address leave as address(0) if the traits can be retreived from the same address as the token + * - uint256 identifier the identifier of the token to be checked; + * - bytes32[] traitValues the array of expected trait values + * - bytes32[] traitKeys the encoded trait keys ; + * @return bytes the encoded extra data with added substandard */ function encodeSubstandard5(Substandard5Comparison memory comparisonStruct) internal pure returns (bytes memory) { return abi.encodePacked(uint8(0x05), abi.encode(comparisonStruct)); diff --git a/test/e2e/SetUp.sol b/test/e2e/SetUp.sol index 96dad1f..bc68bb4 100644 --- a/test/e2e/SetUp.sol +++ b/test/e2e/SetUp.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.24; -import {DeployForTest, ODTest, COLLAT, DEBT, TKN} from '@opendollar/test/e2e/Common.t.sol'; +import {DeployForTest, ODTest, TKN} from '@opendollar/test/e2e/Common.t.sol'; import {ERC20ForTest} from '@opendollar/test/mocks/ERC20ForTest.sol'; import {ISAFEEngine} from '@opendollar/interfaces/ISAFEEngine.sol'; import {BaseOrderTest} from 'seaport/test/foundry/utils/BaseOrderTest.sol'; diff --git a/test/e2e/TestTransferValidationSIP15ZoneOffererTest.t.sol b/test/e2e/TestTransferValidationSIP15ZoneOffererTest.t.sol index 0d2accd..06e9535 100644 --- a/test/e2e/TestTransferValidationSIP15ZoneOffererTest.t.sol +++ b/test/e2e/TestTransferValidationSIP15ZoneOffererTest.t.sol @@ -7,14 +7,13 @@ import { CriteriaResolver, Fulfillment, FulfillmentComponent, - OrderParameters, ItemType, OfferItem, Order, OrderComponents, OrderType } from 'seaport-types/src/lib/ConsiderationStructs.sol'; -import {DeployForTest, ODTest, COLLAT, DEBT, TKN} from '@opendollar/test/e2e/Common.t.sol'; +import {ODTest, COLLAT, DEBT, TKN} from '@opendollar/test/e2e/Common.t.sol'; import {UnavailableReason} from 'seaport-sol/src/SpaceEnums.sol'; import {BaseOrderTest} from 'seaport/test/foundry/utils/BaseOrderTest.sol'; @@ -49,7 +48,6 @@ import {SIP15ZoneEventsAndErrors} from '../../src/interfaces/SIP15ZoneEventsAndE import {SIP15Zone} from '../../src/contracts/SIP15Zone.sol'; import {SIP15Encoder, Substandard5Comparison} from '../../src/sips/SIP15Encoder.sol'; import {Math, RAY, WAD} from '@opendollar/libraries/Math.sol'; -import 'forge-std/console2.sol'; contract TestTransferValidationSIP15ZoneOffererTest is SetUp { using Math for uint256;