diff --git a/README.md b/README.md index e1a0e69..ea7690f 100644 --- a/README.md +++ b/README.md @@ -106,15 +106,24 @@ Returns the string `"FFD1"`. ## Testing -Simply do: +You can use the following commands for testing. ```sh -forge test +# run all tests +forge test -vvv + +# run a specific test +forge test -vvv --mc PolynomialTest +forge test -vvv --mc Huffd1Test ``` -It shall test both the polynomial utilities and the `huffd1` contract. +I use `-vvv` to see reverts in detail. + +## Remarks + +- This project was done for the [Huff hackathon](https://huff.sh/hackathon)! -## Further Works +- This is a very inefficient contract both in contract size and gas usage, and was done mostly for the nerd-snipability factors of using polynomials instead of mappings. - We can implement approvals with another polynomial too, but time did not permit. Also, there are many optimizations to do in many different places within the code. diff --git a/src/Huffd1.huff b/src/Huffd1.huff index 328ecda..f14e607 100644 --- a/src/Huffd1.huff +++ b/src/Huffd1.huff @@ -1,6 +1,8 @@ /// @title Huffd1 /// @notice SPDX-License-Identifier: MIT /// @author erhant +/// @notice An NFT where instead of mappings we use polynomials +/// over a finite field with a large prime order. /////////////////////////////////////////////////////////////////////////////// //// INCLUDES //// diff --git a/src/misc/ERC721.huff b/src/misc/ERC721.huff deleted file mode 100644 index d8a7c8b..0000000 --- a/src/misc/ERC721.huff +++ /dev/null @@ -1,563 +0,0 @@ -/// @title ERC721 -/// @notice SPDX-License-Identifier: MIT -/// @author asnared -/// @author kadenzipfel -/// @notice Modern and heavily gas golfed ERC-721 implementation -/// @notice Adapted from Solmate https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol - -// Imports -#include "../utils/CommonErrors.huff" -#include "../auth/NonPayable.huff" -#include "../data-structures/Hashmap.huff" - -// Interface -#define function name() nonpayable returns (string) -#define function symbol() nonpayable returns (string) -#define function tokenURI(uint256) nonpayable returns (string) - -#define function mint(address, uint256) payable returns () -#define function burn(uint256) nonpayable returns () - -#define function transfer(address,uint256) nonpayable returns () -#define function transferFrom(address,address,uint256) nonpayable returns () -#define function safeTransferFrom(address,address,uint256) nonpayable returns () -#define function safeTransferFrom(address,address,uint256,bytes) nonpayable returns () - -#define function approve(address,uint256) nonpayable returns () -#define function setApprovalForAll(address,bool) nonpayable returns () - -#define function getApproved(uint256) view returns (address) -#define function isApprovedForAll(address,address) view returns (bool) -#define function ownerOf(uint256) view returns (address) -#define function balanceOf(address) view returns (uint256) -#define function supportsInterface(bytes4) view returns (bool) - -// Events -#define event Transfer(address,address,uint256) -#define event Approval(address,address,uint256) -#define event ApprovalForAll(address,address,bool) - -// Storage Slots -#define constant OWNER_LOCATION = FREE_STORAGE_POINTER() -#define constant BALANCE_LOCATION = FREE_STORAGE_POINTER() -#define constant SINGLE_APPROVAL_LOCATION = FREE_STORAGE_POINTER() - -// Immutables offsets -#define constant NAME_OFFSET = 0x0000000000000000000000000000000000000000000000000000000000000080 -#define constant NAME_LENGTH_OFFSET = 0x00000000000000000000000000000000000000000000000000000000000000a0 -#define constant SYMBOL_OFFSET = 0x0000000000000000000000000000000000000000000000000000000000000020 -#define constant SYMBOL_LENGTH_OFFSET = 0x0000000000000000000000000000000000000000000000000000000000000040 - -/// >>>>>>>>>>>>>>>>>>>>> CONSTRUCTOR <<<<<<<<<<<<<<<<<<<<<< /// - -/// @notice Constructor -#define macro ERC721_CONSTRUCTOR() = takes (0) returns (0) { - // Constructor arguments: - // ?, name_size, name, ?, symbol_size, symbol - - // This constructor will return the runtime bytecode with all the - // constructor arguments concatenated at the end. - - // Copy the runtime bytecode with constructor argument concatenated. - 0xb // [offset] - constructor code size - dup1 // [offset, offset] - codesize // [total_size, offset, offset] - sub // [runtime_size, offset] - dup1 // [runtime_size, runtime_size, offset] - swap2 // [offset, runtime_size, runtime_size] - returndatasize // [return_offset, offset, runtime_size, runtime_size] - codecopy // [runtime_size] - - // Return the runtime bytecode. - returndatasize // [return_offset, runtime_size] - return // [] -} - -/// >>>>>>>>>>>>>>>>>>>>> VIEW FUNCTIONS <<<<<<<<<<<<<<<<<<<<<< /// - -/// @notice Name -/// @notice Returns the token name string -#define macro NAME() = takes (0) returns (0) { - NON_PAYABLE() // [] - _GET_IMMUTABLE(NAME_OFFSET, 0x00) // [name_value] - _GET_IMMUTABLE(NAME_LENGTH_OFFSET, 0x00) // [name_length, name_value] - 0x20 0x00 mstore // [name_length, name_value] - 0x20 mstore // [name_value] - 0x40 mstore // [] - 0x60 0x00 return // [] -} - -/// @notice Symbol -/// @notice Returns the symbol of the token -#define macro SYMBOL() = takes (0) returns (0) { - NON_PAYABLE() // [] - _GET_IMMUTABLE(SYMBOL_OFFSET, 0x00) // [symbol_value] - _GET_IMMUTABLE(SYMBOL_LENGTH_OFFSET, 0x00) // [symbol_length, symbol_value] - 0x20 0x00 mstore // [symbol_length, symbol_value] - 0x20 mstore // [symbol_value] - 0x40 mstore // [] - 0x60 0x00 return // [] -} - -/// @notice Balance Of -/// @notice Returns the balance of the given address -#define macro BALANCE_OF() = takes (0) returns (0) { - NON_PAYABLE() // [] - 0x04 calldataload // [account] - // revert if account is zero address - dup1 continue jumpi - ZERO_ADDRESS(0x00) - continue: - [BALANCE_LOCATION] LOAD_ELEMENT_FROM_KEYS(0x00) // [balance] - 0x00 mstore // [] - 0x20 0x00 return // [] -} - -/// @notice Owner Of -/// @notice Returns the owner of the given token id -#define macro OWNER_OF() = takes (0) returns (0) { - 0x04 calldataload // [tokenId] - [OWNER_LOCATION] LOAD_ELEMENT_FROM_KEYS(0x00) // [owner] - // revert if owner is zero address/not minted - dup1 continue jumpi - NOT_MINTED(0x00) - continue: - 0x00 mstore // [] - 0x20 0x00 return // [] -} - -/// @notice Is Approved For All -/// @notice Returns whether the given operator is approved for all tokens of the given owner -#define macro IS_APPROVED_FOR_ALL() = takes (0) returns (0) { - 0x24 calldataload // [to] - 0x04 calldataload // [from, to] - LOAD_ELEMENT_FROM_KEYS(0x00) // [value] - 0x00 mstore // [] - 0x20 0x00 return // [] -} - -/// @notice Get Approved -/// @notice Returns the approved address for the given token id -#define macro GET_APPROVED() = takes (0) returns (0) { - 0x04 calldataload // [tokenId] - [SINGLE_APPROVAL_LOCATION] // [approval_slot, tokenId] - LOAD_ELEMENT_FROM_KEYS(0x00) // [spender] - 0x00 mstore // [] - 0x20 0x00 return // [] -} - -/// @notice Token URI -#define macro TOKEN_URI() = takes (0) returns (0) { - 0x20 0x00 mstore - 0x00 0x20 mstore - 0x40 0x00 return -} - -/// @notice Checks if the given interface is supported -#define macro SUPPORTS_INTERFACE() = takes (0) returns (0) { - // grab interfaceId - 0x04 calldataload // [interfaceId] - 0xe0 shr // [right_aligned_interfaceId] - - // Check if erc165 interfaceId - dup1 // [interfaceId, interfaceId] - 0x01ffc9a7 eq // [is_erc165, interfaceId] - is_interface jumpi - - // Check if erc721 interfaceId - dup1 // [interfaceId, interfaceId] - 0x80ac58cd eq // [is_erc721, interfaceId] - is_interface jumpi - - // Check if erc721Metadata interfaceId - 0x5b5e139f eq // [is_erc721Metadata] - is_interface jumpi - - // Return false (0x00) - 0x00 mstore // [] - 0x20 0x00 return // [] - - // Return true (0x01) - is_interface: - pop // [] - 0x01 0x00 mstore // [] - 0x20 0x00 return // [] -} - -/// >>>>>>>>>>>>>>>>>>>>> INTERNAL FUNCTIONS <<<<<<<<<<<<<<<<<<<<<< /// - -/// @notice Mint -/// @notice Mints a new token -/// @dev The Mint function is payable -#define macro _MINT() = takes (2) returns (0) { - // Input stack: // [to, tokenId] - // Output stack: // [] - - // Check that the recipient is valid - dup1 iszero invalid_recipient jumpi // [to, tokenId] - - // Create the minting params - 0x00 dup3 // [tokenId, from (0x00), to, tokenId] - - // Check token ownership - [OWNER_LOCATION] LOAD_ELEMENT_FROM_KEYS(0x00) // [owner, from (0x00), to, tokenId] - unauthorized jumpi - - // Give tokens to the recipient. - TRANSFER_GIVE_TO() // [from (0x00), to, tokenId] - - // Emit the transfer event. - __EVENT_HASH(Transfer) // [sig, from (0x00), to, tokenId] - 0x00 0x00 log4 // [] - - // Continue Executing - cont jump - - invalid_recipient: - INVALID_RECIPIENT(0x00) - - unauthorized: - ALREADY_MINTED(0x00) - - cont: -} - -/// @notice Burn -/// @notice Burns the token with the given id -#define macro _BURN() = takes (1) returns (0) { - // Input stack: // [tokenId] - NON_PAYABLE() // [tokenId] - - dup1 // [tokenId, tokenId] - [OWNER_LOCATION] LOAD_ELEMENT_FROM_KEYS(0x00) // [owner, tokenId] - - // Check that the recipient is valid - dup1 iszero // [owner == 0, owner, tokenId] - not_minted jumpi // [owner, tokenId] - - // Create the burning params - 0x00 swap1 // [owner, to (0x00), tokenId] - - // Reduce the balance of owner by 1 - 0x01 dup2 // [owner, 1, owner, to, tokenId] - [BALANCE_LOCATION] LOAD_ELEMENT_FROM_KEYS(0x00) // [balance, 1, owner, to, tokenId] - sub dup2 // [owner, balance-1, owner, to, tokenId] - [BALANCE_LOCATION] - STORE_ELEMENT_FROM_KEYS(0x00) // [owner, to, tokenId] - - // Set the owner of the token to 0x00 - 0x00 dup4 [OWNER_LOCATION] // [slot, owner, 0x00, owner, to, tokenId] - STORE_ELEMENT_FROM_KEYS(0x00) // [owner, to, tokenId] - - // Set the approval of the token to 0x00 for the owner - 0x00 dup4 [SINGLE_APPROVAL_LOCATION] // [slot, owner, 0x00, owner, to, tokenId] - STORE_ELEMENT_FROM_KEYS(0x00) // [owner, to, tokenId] - - // Emit the transfer event. - __EVENT_HASH(Transfer) // [sig, owner, to (0x00), tokenId] - 0x00 0x00 // [0, 0, sig, owner, to (0x00), tokenId] - log4 // [] - - // Continue Executing - cont jump - - not_minted: - NOT_MINTED(0x00) - - cont: -} - -/// @notice Retrives an "immutable" from the runtime bytecode. -#define macro _GET_IMMUTABLE(offset_end, free_memory) = takes (0) returns (1) { - 0x20 // [size] - codesize sub // [offset_code, size] - // [offset_memory, offset_code, size] - codecopy // [] - mload // [value] -} - -/// >>>>>>>>>>>>>>>>>>>>> EXTERNAL FUNCTIONS <<<<<<<<<<<<<<<<<<<<<< /// - -/// @notice Approve -/// @notice Approves a spender for a specific token -#define macro APPROVE() = takes (0) returns (0) { - // Load the token owner - 0x24 calldataload dup1 // [tokenId, tokenId] - [OWNER_LOCATION] - LOAD_ELEMENT_FROM_KEYS(0x00) // [owner, tokenId] - dup1 caller eq // [is_sender_owner, owner, tokenId] - - // Check if approved for all - caller dup3 // [owner, msg.sender, is_sender_owner, owner, tokenId] - LOAD_ELEMENT_FROM_KEYS(0x00) // [is_approved_for_all, is_sender_owner, owner, tokenId]] - or cont jumpi // [owner, tokenId] - not_authorized jump - cont: - - // Store approval - 0x04 calldataload dup1 dup4 // [tokenId, spender, spender, owner, tokenId] - [SINGLE_APPROVAL_LOCATION] - STORE_ELEMENT_FROM_KEYS(0x00) // [spender, owner, tokenId] - swap1 // [owner, spender, tokenId] - - // Emit the approval event - __EVENT_HASH(Approval) // [sig, owner, spender, tokenId] - 0x00 0x00 log4 // [] - - stop - - not_authorized: - UNAUTHORIZED(0x00) -} - -/// @notice Set Approval For All -/// @notice Sets an operator as approved for all tokens of the caller -#define macro SET_APPROVAL_FOR_ALL() = takes (0) returns (0) { - // Store the operator as approved for all - 0x24 calldataload // [approved] - 0x04 calldataload // [operator, approved] - caller // [msg.sender, operator, approved] - STORE_ELEMENT_FROM_KEYS(0x00) // [] - - // Emit the ApprovalForAll event - 0x24 calldataload // [approved] - 0x04 calldataload // [operator, approved] - caller // [msg.sender, operator, approved] - __EVENT_HASH(ApprovalForAll) // [sig, owner, operator] - 0x00 0x00 // [0, 32, sig, owner, operator] - log4 // [] - - // Stop execution - stop -} - -/// @notice Transfer From -/// @notice Transfers a token from one address to another -#define macro TRANSFER_FROM() = takes (0) returns (0) { - // Setup the stack for the transfer function. - 0x44 calldataload // [tokenId] - 0x24 calldataload // [to, tokenId] - 0x04 calldataload // [from, to, tokenId] - - // Accounting Logic - TRANSFER_TAKE_FROM() // [from, to, tokenId] - TRANSFER_GIVE_TO() // [from, to, tokenId] - - // Emit the transfer event - __EVENT_HASH(Transfer) // [sig,from, to, tokenId] - 0x20 0x00 log4 // [] - - // Stop execution - stop -} - -/// @notice Safe Transfer From -#define macro SAFE_TRANSFER_FROM() = takes (0) returns (0) { - // Setup the stack for the transfer function. - 0x44 calldataload // [tokenId] - 0x24 calldataload // [to, tokenId] - 0x04 calldataload // [from, to, tokenId] - - TRANSFER_TAKE_FROM() // [from, to, tokenId] - TRANSFER_GIVE_TO() // [from, to, tokenId] - - // Emit the transfer event - __EVENT_HASH(Transfer) // [sig, from, to, tokenId] - 0x00 0x00 log4 // [] - - // Make sure we can transfer to the recipient - 0x24 calldataload // [to] - dup1 extcodesize // [to.code.length, to] - iszero safe jumpi // [to] - - // onERC721Received Selector - 0x150b7a02 dup1 // [onERC721Received, onERC721Received, to] - 0xE0 shl // [onERC721Received_shifted, onERC721Received, to] - - // Store the left-shifted selector for call - 0x20 mstore // [onERC721Received, to] - - // Store the msg.sender as the first arg - caller 0x24 mstore // [onERC721Received, to] - - // Store from as the second arg - 0x04 calldataload // [from, onERC721Received, to] - 0x44 mstore // [onERC721Received, to] - - // Id is the third arg - 0x44 calldataload // [tokenId, onERC721Received, to] - 0x64 mstore // [onERC721Received, to] - - // Blank bytes array as 4th arg (no data) - 0x80 0x84 mstore - 0x00 0xA4 mstore - - // Call address(to).onERC721Received(msg.sender, from, tokenId, "") - 0x20 // [retSize, onERC721Received, to] - 0x00 // [retOffset, retSize, onERC721Received, to] - 0xA4 // [argSize, retOffset, retSize, onERC721Received, to] - dup3 // [argOffset, argSize, retOffset, retSize, onERC721Received, to] - dup3 // [value, argOffset, argSize, retOffset, retSize, onERC721Received, to] - dup7 // [to, value, argOffset, argSize, retOffset, retSize, onERC721Received, to] - gas // [gas, to, value, argOffset, argSize, retOffset, retSize, onERC721Received, to] - call // [success, onERC721Received, to] - - // Revert if call isn't successful - cont jumpi // [onERC721Received, to] - 0x00 dup1 revert - cont: - - // Compare the return data to the onERC721Received selector - 0x00 mload 0xE0 shr // [response, onERC721Received, to] - eq safe jumpi // [to] - - // Revert if the return data is not accepted - UNSAFE_RECIPIENT(0x00) - - // Stop execution if safe - safe: - stop -} - -#define macro SAFE_TRANSFER_FROM_WITH_DATA() = takes (0) returns (0) { - // Setup the stack for the transfer function. - 0x44 calldataload // [tokenId] - 0x24 calldataload // [to, tokenId] - 0x04 calldataload // [from, to, tokenId] - - TRANSFER_TAKE_FROM() // [from, to, tokenId] - TRANSFER_GIVE_TO() // [from, to, tokenId] - - // Emit the transfer event. - __EVENT_HASH(Transfer) // [sig, from, to, tokenId] - 0x00 0x00 log4 // [] - - // Make sure we can transfer to the recipient - 0x24 calldataload // [to] - dup1 extcodesize // [to.code.length, to] - iszero safe jumpi // [to] - - // onERC721Received Selector - 0x150b7a02 dup1 // [onERC721Received, onERC721Received, to] - 0xE0 shl // [onERC721Received_shifted, onERC721Received, to] - - // Store the left-shifted selector for call - 0x20 mstore // [onERC721Received, to] - - // Store the msg.sender as the first arg - caller 0x24 mstore // [onERC721Received, to] - - // Store from as the second arg - 0x04 calldataload // [from, onERC721Received, to] - 0x44 mstore // [onERC721Received, to] - - // Id is the third arg - 0x44 calldataload // [tokenId, onERC721Received, to] - 0x64 mstore // [onERC721Received, to] - - 0x84 calldataload // [len(data), onERC721Received, to] - 0x05 shl // [len(data) * 0x20, onERC721Received, to] - 0x40 add // [len(data) * 0x20 + 0x40, onERC721Received, to] - dup1 // [len(data) * 0x20 + 0x40, len(data) * 0x20 + 0x40, onERC721received, to] - 0x64 // [0x64, len(data) * 0x20 + 0x40, len(data) * 0x20 + 0x40, onERC721received, to] - 0x84 // [0x20, 0x64, len(data) * 0x20 + 0x40, len(data) * 0x20 + 0x40, onERC721received, to] - calldatacopy // [len(bytes), onERC721received, to] - - // Call address(to).onERC721Received(msg.sender, from, tokenId, bytes) - 0x20 // [retSize, len(bytes), onERC721Received, to] - 0x00 // [retOffset, retSize, len(bytes), onERC721Received, to] - swap1 swap2 // [len(bytes), retOffset, retSize, onERC721Received, to] - 0x64 add // [argSize, retOffset, retSize, onERC721Received, to] - dup3 // [argOffset, argSize, retOffset, retSize, len(bytes), onERC721Received, to] - dup3 // [value, argOffset, argSize, retOffset, retSize, len(bytes), onERC721Received, to] - dup7 // [to, value, argOffset, argSize, retOffset, retSize, len(bytes), onERC721Received, to] - gas // [gas, to, value, argOffset, argSize, retOffset, retSize, len(bytes), onERC721Received, to] - call // [success, len(bytes), onERC721Received, to] - - // Revert if call isn't successful - cont jumpi // [len(bytes), onERC721Received, to] - 0x00 dup1 revert - cont: - - // Compare the return data to the onERC721Received selector - 0x00 mload 0xE0 shr // [response, onERC721Received, to] - eq safe jumpi // [to] - - // Revert if the return data is not accepted - UNSAFE_RECIPIENT(0x00) - - // Stop execution if safe - safe: - stop -} - -/// >>>>>>>>>>>>>>>>>>>>> INTERNAL HELPERS <<<<<<<<<<<<<<<<<<<<<< /// - -/// @notice Internal Macro to update Transfer from accounting -#define macro TRANSFER_TAKE_FROM() = takes (3) returns (3) { - // Input stack: [from, to, tokenId] - - // If from !== ownerOf[tokenId] revert with "WRONG_FROM" - dup1 dup4 // [tokenId, from, from, to, tokenId] - [OWNER_LOCATION] LOAD_ELEMENT_FROM_KEYS(0x00) // [owner, from, from, to, tokenId] - eq cont jumpi // [from, to, tokenId] - WRONG_FROM(0x00) - cont: - - // If to === address(0) revert with "INVALID_RECIPIENT" - dup2 continue jumpi // [from, to, tokenId] - INVALID_RECIPIENT(0x00) - continue: - - // Check if msg.sender == from - dup1 caller eq // [msg.sender == from, from, to, tokenId] - is_authorized jumpi // [from, to, tokenId] - - // Check if approved for all - caller dup2 // [from, msg.sender, from, to, tokenId] - LOAD_ELEMENT_FROM_KEYS(0x00) // [is_approved_for_all, from, to, tokenId] - is_authorized jumpi // [from, to, tokenId] - - // Check if approved for tokenId - dup3 // [tokenId, from, to, tokenId] - [SINGLE_APPROVAL_LOCATION] // [SINGLE_APPROVAL_LOCATION, tokenId, from, to, tokenId] - LOAD_ELEMENT_FROM_KEYS(0x00) // [address_approved_for_tokenId, from, to, tokenId] - caller eq is_authorized jumpi // [from, to, tokenId] - - // If msg.sender != from && !isApprovedForAll[from][msg.sender] && msg.sender != getApproved[id], - UNAUTHORIZED(0x00) - - is_authorized: - - // Update balance of from - 0x01 dup2 // [from, 1, from, to, tokenId] - [BALANCE_LOCATION] LOAD_ELEMENT_FROM_KEYS(0x00) // [balance, 1, from, to, tokenId] - sub dup2 // [from, balance-1, from, to, tokenId] - [BALANCE_LOCATION] - STORE_ELEMENT_FROM_KEYS(0x00) // [from, to, tokenId] -} - -/// @notice Internal Macro to update Transfer to accounting -#define macro TRANSFER_GIVE_TO() = takes (3) returns (3) { - // retrieve balance - // input stack: // [from, to, tokenId] - dup2 // [to, from, to, tokenId] - [BALANCE_LOCATION] // [balance_slot, to, from, to, tokenId] - LOAD_ELEMENT_FROM_KEYS(0x00) // [balance, from, to, tokenId] - 0x01 add // [balance+1, from, to, tokenId] - - // update balance - dup3 // [to, balance+1, from, to, tokenId] - [BALANCE_LOCATION] // [balance_slot, to, balance+1, from, to, tokenId] - STORE_ELEMENT_FROM_KEYS(0x00) // [from, to, tokenId] - - // update ownerOf - dup2 dup4 // [tokenId, to, from, to, tokenId] - [OWNER_LOCATION] // [owner_slot, tokenId, to, from, to, tokenId] - STORE_ELEMENT_FROM_KEYS(0x00) // [from, to, tokenId] - - // update approval - 0x00 dup4 // [tokenId, address(0), from, to, tokenId] - [SINGLE_APPROVAL_LOCATION] // [approval_slot, tokenId, address(0), from, to, tokenId] - STORE_ELEMENT_FROM_KEYS(0x00) // [from, to, tokenId] -} \ No newline at end of file diff --git a/src/misc/Codecopy.huff b/src/test/Codecopy.t.huff similarity index 100% rename from src/misc/Codecopy.huff rename to src/test/Codecopy.t.huff diff --git a/test/Polynomial.t.sol b/test/Polynomial.t.sol index b60a58d..3d6c649 100644 --- a/test/Polynomial.t.sol +++ b/test/Polynomial.t.sol @@ -9,7 +9,7 @@ contract PolynomialTest is Test { IPolynomial polynomial; uint256 constant TOTAL_SUPPLY = 3; uint256 constant ORDER = 13; - bool constant VERBOSE = false; + bool constant VERBOSE = true; function setUp() public { string memory code = vm.readFile("src/test/Polynomial.t.huff"); @@ -22,8 +22,9 @@ contract PolynomialTest is Test { for (uint256 tokenId = 0; tokenId < TOTAL_SUPPLY; ++tokenId) { uint256 eval = polynomial.eval(basis, tokenId); uint256 expected = basis == tokenId ? 1 : 0; + VERBOSE ? console.log(basis, ":", eval) : (); + assertEq(eval, expected); - VERBOSE ? console.log("BASIS(", basis, "):", eval) : (); } } } @@ -31,17 +32,14 @@ contract PolynomialTest is Test { function test_AddEval() public { for (uint256 basis1 = 0; basis1 < TOTAL_SUPPLY; ++basis1) { for (uint256 basis2 = 0; basis2 < TOTAL_SUPPLY; ++basis2) { + VERBOSE ? console.log("") : (); for (uint256 tokenId = 0; tokenId < TOTAL_SUPPLY; ++tokenId) { uint256 eval1 = polynomial.eval(basis1, tokenId); uint256 eval2 = polynomial.eval(basis2, tokenId); uint256 expected = (eval1 + eval2) % ORDER; - uint256 addEval = polynomial.addEval(basis1, basis2, tokenId); - // console.log("BASIS1:", basis1, "\tBASIS2:", basis2); - // console.log("EVAL1:", eval1, "\tEVAL2:", eval2); - // console.log("EXPECTED:", tokenId, "\tADDEVAL:", addEval); - // console.log("BASIS1 BASIS2 TOKEN:", basis1, basis2, tokenId); - // console.log(""); + VERBOSE ? console.log(basis1, basis2, tokenId, addEval) : (); + assertEq(addEval, expected); } } @@ -56,8 +54,9 @@ contract PolynomialTest is Test { uint256 eval = polynomial.eval(basis, tokenId); uint256 scaledEval = polynomial.scaleEval(basis, scale, tokenId); uint256 expected = basis == tokenId ? (eval * scale) % ORDER : 0; + VERBOSE ? console.log(basis, scale, ":", scaledEval) : (); + assertEq(scaledEval, expected); - VERBOSE ? console.log("BASIS(0) *", scale, "=", scaledEval) : (); } } } @@ -79,8 +78,9 @@ contract PolynomialTest is Test { VERBOSE ? console.log("") : (); for (uint256 tokenId = 0; tokenId < TOTAL_SUPPLY; ++tokenId) { uint256 expected = basisToAdd == tokenId ? scale % ORDER : 0; - assertEq(polynomial.evalStore(tokenId), expected); VERBOSE ? console.log(basis, tokenId, expected) : (); + + assertEq(polynomial.evalStore(tokenId), expected); } } } @@ -95,9 +95,3 @@ interface IPolynomial { function addStore(uint256 basis) external; function scaleStore(uint256 scale) external; } - -// function test_Foo() public { -// uint256 expected = 0xE; -// uint256 actual = 0xA; -// assertEq(actual, expected); -// }