@artblocks/contracts 1.3.1 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -10
- package/artifacts/contracts/AdminACLV0RoyaltyRegistry.sol/AdminACLV0RoyaltyRegistry.json +193 -0
- package/artifacts/contracts/AdminACLV0RoyaltyRegistry.sol/IRoyaltyRegistry.json +35 -0
- package/artifacts/contracts/AdminACLV1.sol/AdminACLV1.json +2 -2
- package/artifacts/contracts/BytecodeStorageReaders/BytecodeStorageReaderContractV2.sol/BytecodeStorageReaderContractV2.json +2 -2
- package/artifacts/contracts/BytecodeStorageReaders/BytecodeStorageReaderContractV2_Web3Call.sol/BytecodeStorageReaderContractV2_Web3Call.json +2 -2
- package/artifacts/contracts/BytecodeStorageV2Writer.sol/BytecodeStorageV2Writer.json +2 -2
- package/artifacts/contracts/DependencyRegistryV0.sol/DependencyRegistryV0.json +210 -2
- package/artifacts/contracts/GenArt721CoreV3_Curated.sol/GenArt721CoreV3_Curated.json +235 -20
- package/artifacts/contracts/GenArt721CoreV3_Curated_Flex.sol/GenArt721CoreV3_Curated_Flex.json +3197 -0
- package/artifacts/contracts/GenArt721CoreV3_Explorations_Flex.sol/GenArt721CoreV3_Explorations_Flex.json +3192 -0
- package/artifacts/contracts/OwnedCreate2FactoryV0.sol/OwnedCreate2FactoryV0.json +2 -2
- package/artifacts/contracts/archive/GenArt721CoreV3.sol/GenArt721CoreV3.json +27 -2
- package/artifacts/contracts/archive/GenArt721CoreV3_Explorations.sol/GenArt721CoreV3_Explorations.json +27 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterDAExp/MinterDAExpV2.sol/MinterDAExpV2.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterDAExp/MinterDAExpV3.sol/MinterDAExpV3.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterDAExp/MinterDAExpV4.sol/MinterDAExpV4.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterDAExpSettlement/MinterDAExpSettlementV0.sol/MinterDAExpSettlementV0.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterDAExpSettlement/MinterDAExpSettlementV1.sol/MinterDAExpSettlementV1.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterDAExpSettlement/MinterDAExpSettlementV2.sol/MinterDAExpSettlementV2.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterDALin/MinterDALinV2.sol/MinterDALinV2.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterDALin/MinterDALinV3.sol/MinterDALinV3.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterDALin/MinterDALinV4.sol/MinterDALinV4.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterHolder/MinterHolderV1.sol/MinterHolderV1.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterHolder/MinterHolderV2.sol/MinterHolderV2.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterHolder/MinterHolderV3.sol/MinterHolderV3.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterHolder/MinterHolderV4.sol/MinterHolderV4.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterMerkle/MinterMerkleV1.sol/MinterMerkleV1.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterMerkle/MinterMerkleV2.sol/MinterMerkleV2.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterMerkle/MinterMerkleV3.sol/MinterMerkleV3.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterMerkle/MinterMerkleV4.sol/MinterMerkleV4.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterMerkle/MinterMerkleV5.sol/MinterMerkleV5.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterPolyptych/MinterPolyptychV0.sol/IGenArt721CoreContractV3WithRandomizer.json +25 -0
- package/artifacts/contracts/archive/minter-suite/Minters/MinterPolyptych/MinterPolyptychV0.sol/MinterPolyptychV0.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterSEA/MinterSEAV0.sol/MinterSEAV0.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterSetPrice/MinterSetPriceV2.sol/MinterSetPriceV2.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterSetPrice/MinterSetPriceV3.sol/MinterSetPriceV3.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterSetPrice/MinterSetPriceV4.sol/MinterSetPriceV4.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterSetPriceERC20/MinterSetPriceERC20V2.sol/MinterSetPriceERC20V2.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterSetPriceERC20/MinterSetPriceERC20V3.sol/MinterSetPriceERC20V3.json +2 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterSetPriceERC20/MinterSetPriceERC20V4.sol/MinterSetPriceERC20V4.json +2 -2
- package/artifacts/contracts/engine/V3/EngineFactoryV0.sol/EngineFactoryV0.json +28 -2
- package/artifacts/contracts/engine/V3/GenArt721CoreV3_Engine.sol/GenArt721CoreV3_Engine.json +239 -20
- package/artifacts/contracts/engine/V3/GenArt721CoreV3_Engine_Flex.sol/GenArt721CoreV3_Engine_Flex.json +267 -48
- package/artifacts/contracts/engine/V3/forks/GenArt721CoreV3_Engine_Flex_PROOF.sol/GenArt721CoreV3_Engine_Flex_PROOF.json +27 -2
- package/artifacts/contracts/engine/V3/forks/PROHIBITION/AdminACLV0_PROHIBITION.sol/AdminACLV0_PROHIBITION.json +2 -2
- package/artifacts/contracts/engine/V3/forks/PROHIBITION/GenArt721CoreV3_Engine_Flex_PROHIBITION.sol/GenArt721CoreV3_Engine_Flex_PROHIBITION.json +27 -2
- package/artifacts/contracts/engine/V3/forks/PROHIBITION/interfaces/IGenArt721CoreContractV3_Engine_Flex_PROHIBITION.sol/IGenArt721CoreContractV3_Engine_Flex_PROHIBITION.json +25 -0
- package/artifacts/contracts/engine/V3/transfer-hooks/AbstractTransferHook.sol/AbstractTransferHook.json +79 -0
- package/artifacts/contracts/engine/V3/transfer-hooks/OwnerHistoryTransferHook.sol/OwnerHistoryTransferHook.json +315 -0
- package/artifacts/contracts/generator/GenArt721GeneratorV0.sol/GenArt721GeneratorV0.json +2 -2
- package/artifacts/contracts/interfaces/v0.8.x/IClaimMinter.sol/IClaimMinter.json +189 -0
- package/artifacts/contracts/interfaces/v0.8.x/IDependencyRegistryV0.sol/IDependencyRegistryV0.json +149 -0
- package/artifacts/contracts/interfaces/v0.8.x/IEngineFactoryV0.sol/IEngineFactoryV0.json +26 -0
- package/artifacts/contracts/interfaces/v0.8.x/IGenArt721CoreContractV3.sol/IGenArt721CoreContractV3.json +25 -0
- package/artifacts/contracts/interfaces/v0.8.x/IGenArt721CoreContractV3_Base.sol/IGenArt721CoreContractV3_Base.json +25 -0
- package/artifacts/contracts/interfaces/v0.8.x/IGenArt721CoreContractV3_Engine.sol/IGenArt721CoreContractV3_Engine.json +123 -0
- package/artifacts/contracts/interfaces/v0.8.x/IGenArt721CoreContractV3_Engine_Flex.sol/IGenArt721CoreContractV3_Engine_Flex.json +123 -0
- package/artifacts/contracts/interfaces/v0.8.x/IGenArt721CoreContractV3_Engine_Flex_PreV3p2.sol/IGenArt721CoreContractV3_Engine_Flex_PreV3p2.json +25 -0
- package/artifacts/contracts/interfaces/v0.8.x/IGenArt721CoreContractV3_Engine_PreV3p2.sol/IGenArt721CoreContractV3_Engine_PreV3p2.json +25 -0
- package/artifacts/contracts/interfaces/v0.8.x/IOwnerHistoryTransferHook.sol/IOwnerHistoryTransferHook.json +299 -0
- package/artifacts/contracts/interfaces/v0.8.x/IPMPV0.sol/IPMPV0.json +7 -1
- package/artifacts/contracts/interfaces/v0.8.x/ISRHooks.sol/ISRHooks.json +432 -0
- package/artifacts/contracts/interfaces/v0.8.x/ISeaDropShimForContract.sol/ISeaDropShimForContract.json +0 -13
- package/artifacts/contracts/interfaces/v0.8.x/ISharedMinterTieredAllowV0.sol/ISharedMinterTieredAllowV0.json +94 -0
- package/artifacts/contracts/interfaces/v0.8.x/ITransferHook.sol/ITransferHook.json +63 -0
- package/artifacts/contracts/libs/v0.8.x/AuthLib.sol/AuthLib.json +2 -2
- package/artifacts/contracts/libs/v0.8.x/BytecodeStorageV2.sol/BytecodeStorageReader.json +2 -2
- package/artifacts/contracts/libs/v0.8.x/BytecodeStorageV2.sol/BytecodeStorageWriter.json +2 -2
- package/artifacts/contracts/libs/v0.8.x/DependencyRegistryStorageLib.sol/DependencyRegistryStorageLib.json +2 -2
- package/artifacts/contracts/libs/v0.8.x/ENSLib.sol/ENSLib.json +10 -0
- package/artifacts/contracts/libs/v0.8.x/ENSLib.sol/IUniversalResolver.json +45 -0
- package/artifacts/contracts/libs/v0.8.x/EnumerableSetUint16.sol/EnumerableSetUint16.json +10 -0
- package/artifacts/contracts/libs/v0.8.x/FeistelWalkLib.sol/FeistelWalkLib.json +10 -0
- package/artifacts/contracts/libs/v0.8.x/ImmutableUint16Array.sol/ImmutableUint16Array.json +10 -0
- package/artifacts/contracts/libs/v0.8.x/V3EngineLib.sol/V3EngineLib.json +163 -0
- package/artifacts/contracts/libs/v0.8.x/V3FlexLib.sol/V3FlexLib.json +2 -2
- package/artifacts/contracts/libs/v0.8.x/V3TransferHookLib.sol/V3TransferHookLib.json +79 -0
- package/artifacts/contracts/libs/v0.8.x/minter-libs/MaxInvocationsLib.sol/MaxInvocationsLib.json +2 -2
- package/artifacts/contracts/libs/v0.8.x/minter-libs/OnChainAllowlistLib.sol/OnChainAllowlistLib.json +10 -0
- package/artifacts/contracts/libs/v0.8.x/minter-libs/PolyptychLib.sol/PolyptychLib.json +2 -2
- package/artifacts/contracts/libs/v0.8.x/minter-libs/RAMLib.sol/RAMLib.json +2 -2
- package/artifacts/contracts/libs/v0.8.x/minter-libs/SEALib.sol/SEALib.json +2 -2
- package/artifacts/contracts/libs/v0.8.x/minter-libs/SettlementExpLib.sol/SettlementExpLib.json +2 -2
- package/artifacts/contracts/libs/v0.8.x/minter-libs/SplitFundsLib.sol/SplitFundsLib.json +2 -2
- package/artifacts/contracts/minter-suite/MinterFilter/MinterFilterV1.sol/MinterFilterV1.json +2 -2
- package/artifacts/contracts/minter-suite/MinterFilter/MinterFilterV2.sol/MinterFilterV2.json +2 -2
- package/artifacts/contracts/minter-suite/Minters/MinterDAExpHolderV5.sol/MinterDAExpHolderV5.json +2 -2
- package/artifacts/contracts/minter-suite/Minters/MinterDAExpSettlementV3.sol/MinterDAExpSettlementV3.json +2 -2
- package/artifacts/contracts/minter-suite/Minters/MinterDAExpV5.sol/MinterDAExpV5.json +2 -2
- package/artifacts/contracts/minter-suite/Minters/MinterDALinHolderV5.sol/MinterDALinHolderV5.json +2 -2
- package/artifacts/contracts/minter-suite/Minters/MinterDALinV5.sol/MinterDALinV5.json +2 -2
- package/artifacts/contracts/minter-suite/Minters/MinterMinPriceMerkleV0.sol/MinterMinPriceMerkleV0.json +2 -2
- package/artifacts/contracts/minter-suite/Minters/MinterMinPriceV0.sol/MinterMinPriceV0.json +2 -2
- package/artifacts/contracts/minter-suite/Minters/MinterRAMV0.sol/MinterRAMV0.json +2 -2
- package/artifacts/contracts/minter-suite/Minters/MinterSEAV1.sol/MinterSEAV1.json +2 -2
- package/artifacts/contracts/minter-suite/Minters/MinterSetPriceERC20V5.sol/MinterSetPriceERC20V5.json +2 -2
- package/artifacts/contracts/minter-suite/Minters/MinterSetPriceHolderV5.sol/MinterSetPriceHolderV5.json +2 -2
- package/artifacts/contracts/minter-suite/Minters/MinterSetPriceMerkleV5.sol/MinterSetPriceMerkleV5.json +2 -2
- package/artifacts/contracts/minter-suite/Minters/MinterSetPriceOnChainAllowV0.sol/MinterSetPriceOnChainAllowV0.json +522 -0
- package/artifacts/contracts/minter-suite/Minters/MinterSetPricePolyptychERC20V5.sol/MinterSetPricePolyptychERC20V5.json +2 -2
- package/artifacts/contracts/minter-suite/Minters/MinterSetPricePolyptychV5.sol/MinterSetPricePolyptychV5.json +2 -2
- package/artifacts/contracts/minter-suite/Minters/MinterSetPriceTieredAllowV1.sol/MinterSetPriceTieredAllowV1.json +715 -0
- package/artifacts/contracts/minter-suite/Minters/MinterSetPriceV5.sol/MinterSetPriceV5.json +2 -2
- package/artifacts/contracts/minter-suite/Minters/MinterSlidingScaleV0.sol/MinterSlidingScaleV0.json +431 -0
- package/artifacts/contracts/minter-suite/Minters/one-off/ClaimMinter.sol/ClaimMinter.json +502 -0
- package/artifacts/contracts/minter-suite/Minters/one-off/MinterSetPriceTieredOnChainAllowV0.sol/MinterSetPriceTieredOnChainAllowV0.json +673 -0
- package/artifacts/contracts/minter-suite/Minters/one-off/MinterSetPriceV5_SingleCore.sol/MinterSetPriceV5_SingleCore.json +2 -2
- package/artifacts/contracts/minter-suite/Minters/one-off/SeaDropXArtBlocksShim.sol/SeaDropXArtBlocksShim.json +6 -19
- package/artifacts/contracts/mock/BytecodeV2TextCR_DMock.sol/BytecodeV2TextCR_DMock.json +2 -2
- package/artifacts/contracts/mock/DummySharedMinter.sol/DummySharedMinter.json +2 -2
- package/artifacts/contracts/mock/ENSLibMock.sol/ENSLibMock.json +30 -0
- package/artifacts/contracts/mock/EnumerableSetUint16Mock.sol/EnumerableSetUint16Mock.json +146 -0
- package/artifacts/contracts/mock/FeistelWalkLibMock.sol/FeistelWalkLibMock.json +142 -0
- package/artifacts/contracts/mock/ForceSendMock.sol/ForceSendMock.json +2 -2
- package/artifacts/contracts/mock/GenArt721CoreV3_Engine_IncorrectCoreType.sol/GenArt721CoreV3_Engine_IncorrectCoreType.json +2 -2
- package/artifacts/contracts/mock/ImmutableUint16ArrayMock.sol/ImmutableUint16ArrayMock.json +89 -0
- package/artifacts/contracts/mock/MockAdminACLV0_PROHIBITION.sol/MockAdminACLV0Events_PROHIBITION.json +2 -2
- package/artifacts/contracts/mock/MockGenArt721V3Core.sol/MockGenArt721V3Core.json +490 -0
- package/artifacts/contracts/mock/MockPMP.sol/MockPMP.json +523 -0
- package/artifacts/contracts/mock/MockPMPAugmentHook.sol/MockPMPAugmentHook.json +2 -2
- package/artifacts/contracts/mock/MockPMPConfigureHook.sol/MockPMPConfigureHook.json +2 -2
- package/artifacts/contracts/mock/MockTransferHook.sol/MockTransferHook.json +453 -0
- package/artifacts/contracts/mock/MockTransferHookTestHelpers.sol/MockBatchTransferrer.json +39 -0
- package/artifacts/contracts/mock/MockTransferHookTestHelpers.sol/MockForwardingERC721Receiver.json +71 -0
- package/artifacts/contracts/mock/MockTransferHookTestHelpers.sol/MockSpoofingCore.json +94 -0
- package/artifacts/contracts/mock/RandomizerV2_NoAssignMock.sol/RandomizerV2_NoAssignMock.json +2 -2
- package/artifacts/contracts/mock/ReentrancyBatchMockShared.sol/IBatchMinter.json +64 -0
- package/artifacts/contracts/mock/ReentrancyBatchMockShared.sol/ReentrancyBatchMockShared.json +113 -0
- package/artifacts/contracts/mock/RelayExecutorTestHelper.sol/MockTarget.json +74 -0
- package/artifacts/contracts/mock/RelayExecutorTestHelper.sol/RelayExecutorPartialRevertsTestHelper.json +138 -0
- package/artifacts/contracts/mock/RelayExecutorTestHelper.sol/RelayExecutorTestHelper.json +119 -0
- package/artifacts/contracts/randomizer/deprecated/PolyptychRandomizerV0.sol/BasicPolyptychRandomizerV0.json +2 -2
- package/artifacts/contracts/randomizer/deprecated/RandomizerV2.sol/BasicRandomizerV2.json +2 -2
- package/artifacts/contracts/randomizer/shared/SharedRandomizerV0.sol/SharedRandomizerV0.json +2 -2
- package/artifacts/contracts/relay/RelayExecutor.sol/RelayExecutor.json +101 -0
- package/artifacts/contracts/relay/RelayExecutorPartialReverts.sol/RelayExecutorPartialReverts.json +120 -0
- package/artifacts/contracts/royalty-registry/GenArt721RoyaltyOverrideSplits.sol/GenArt721RoyaltyOverrideSplits.json +263 -0
- package/artifacts/contracts/utils/MintMulticallUtil.sol/IMinterSetPriceV5.json +40 -0
- package/artifacts/contracts/utils/MintMulticallUtil.sol/MintMulticallUtil.json +163 -0
- package/artifacts/contracts/web3call/PMPV0.sol/PMPV0.json +9 -3
- package/artifacts/contracts/web3call/PMPV1.sol/PMPV1.json +648 -0
- package/artifacts/contracts/web3call/augment-hooks/InjectBaseGasFee.sol/InjectBaseGasFee.json +2 -2
- package/artifacts/contracts/web3call/augment-hooks/InjectBlockHeight.sol/InjectBlockHeight.json +83 -0
- package/artifacts/contracts/web3call/augment-hooks/InjectBlockHeightAndArtistProjectOverrides.sol/InjectBlockHeightAndArtistProjectOverrides.json +226 -0
- package/artifacts/contracts/web3call/augment-hooks/InjectBlockHeightAndNumOwnedProjectTokens.sol/InjectBlockHeightAndNumOwnedProjectTokens.json +182 -0
- package/artifacts/contracts/web3call/augment-hooks/InjectBlockHeightProjectInvocationsAndArtistProjectOverrides.sol/InjectBlockHeightProjectInvocationsAndArtistProjectOverrides.json +226 -0
- package/artifacts/contracts/web3call/augment-hooks/InjectBlockTimestamp.sol/InjectBlockTimestamp.json +83 -0
- package/artifacts/contracts/web3call/augment-hooks/InjectBytesPerToken.sol/InjectBytesPerToken.json +358 -0
- package/artifacts/contracts/web3call/augment-hooks/InjectChromieSquiggleFloorPrice.sol/InjectChromieSquiggleFloorPrice.json +2 -2
- package/artifacts/contracts/web3call/augment-hooks/InjectIsNounsDaoMember.sol/InjectIsNounsDaoMember.json +2 -2
- package/artifacts/contracts/web3call/augment-hooks/InjectIsProjectFullyMinted.sol/InjectIsProjectFullyMinted.json +2 -2
- package/artifacts/contracts/web3call/augment-hooks/InjectPolyptychTokenHash.sol/InjectPolyptychTokenHash.json +2 -2
- package/artifacts/contracts/web3call/augment-hooks/InjectTokenHashSeed.sol/InjectTokenHashSeed.json +2 -2
- package/artifacts/contracts/web3call/augment-hooks/InjectTokenOwner.sol/InjectTokenOwner.json +2 -2
- package/artifacts/contracts/web3call/augment-hooks/InjectTokenOwnerEthBalance.sol/InjectTokenOwnerEthBalance.json +2 -2
- package/artifacts/contracts/web3call/augment-hooks/InjectUSDCTotalSupply.sol/InjectUSDCTotalSupply.json +2 -2
- package/artifacts/contracts/web3call/augment-hooks/SRHooks.sol/SRHooks.json +899 -0
- package/artifacts/contracts/web3call/combined-hooks/LiftHooks.sol/IGenArt721V0_Minimal.json +30 -0
- package/artifacts/contracts/web3call/combined-hooks/LiftHooks.sol/IRelic.json +35 -0
- package/artifacts/contracts/web3call/combined-hooks/LiftHooks.sol/LiftHooks.json +256 -0
- package/artifacts/contracts/web3call/configure-hooks/{abstractPMPConfigureHook.sol → AbstractPMPConfigureHook.sol}/AbstractPMPConfigureHook.json +1 -1
- package/artifacts/contracts/web3call/configure-hooks/PMPConfigureLockHook.sol/PMPConfigureLockHook.json +195 -0
- package/contracts/AdminACLV0RoyaltyRegistry.sol +142 -0
- package/contracts/DependencyRegistryV0.sol +143 -13
- package/contracts/GenArt721CoreV3_Curated.sol +1 -1
- package/contracts/GenArt721CoreV3_Curated_Flex.sol +173 -0
- package/contracts/GenArt721CoreV3_Explorations_Flex.sol +159 -0
- package/contracts/engine/V3/EngineFactoryV0.sol +20 -1
- package/contracts/engine/V3/GenArt721CoreV3_Engine.sol +286 -299
- package/contracts/engine/V3/GenArt721CoreV3_Engine_Flex.sol +292 -301
- package/contracts/engine/V3/transfer-hooks/AbstractTransferHook.sol +101 -0
- package/contracts/engine/V3/transfer-hooks/OwnerHistoryTransferHook.sol +291 -0
- package/contracts/generator/GenArt721GeneratorV0.sol +145 -47
- package/contracts/helpers/ERC1967ProxyImport.sol +5 -0
- package/contracts/interfaces/v0.8.x/IArtblocksRoyaltyOverride.sol +1 -1
- package/contracts/interfaces/v0.8.x/IClaimMinter.sol +70 -0
- package/contracts/interfaces/v0.8.x/IDependencyRegistryV0.sol +95 -0
- package/contracts/interfaces/v0.8.x/IEngineFactoryV0.sol +15 -0
- package/contracts/interfaces/v0.8.x/IGenArt721CoreContractV3_Base.sol +21 -2
- package/contracts/interfaces/v0.8.x/IGenArt721CoreContractV3_Engine.sol +72 -0
- package/contracts/interfaces/v0.8.x/IOwnerHistoryTransferHook.sol +119 -0
- package/contracts/interfaces/v0.8.x/IPMPV0.sol +5 -3
- package/contracts/interfaces/v0.8.x/ISRHooks.sol +229 -0
- package/contracts/interfaces/v0.8.x/ISeaDropShimForContract.sol +0 -6
- package/contracts/interfaces/v0.8.x/ISharedMinterTieredAllowV0.sol +69 -0
- package/contracts/interfaces/v0.8.x/ITransferHook.sol +48 -0
- package/contracts/libs/v0.8.x/DependencyRegistryStorageLib.sol +12 -0
- package/contracts/libs/v0.8.x/ENSLib.sol +85 -0
- package/contracts/libs/v0.8.x/EnumerableSetUint16.sol +429 -0
- package/contracts/libs/v0.8.x/FeistelWalkLib.sol +221 -0
- package/contracts/libs/v0.8.x/ImmutableUint16Array.sol +201 -0
- package/contracts/libs/v0.8.x/V3EngineLib.sol +490 -0
- package/contracts/libs/v0.8.x/V3TransferHookLib.sol +251 -0
- package/contracts/libs/v0.8.x/minter-libs/OnChainAllowlistLib.sol +165 -0
- package/contracts/minter-suite/Minters/MinterSetPriceOnChainAllowV0.sol +632 -0
- package/contracts/minter-suite/Minters/MinterSetPriceTieredAllowV1.sol +871 -0
- package/contracts/minter-suite/Minters/MinterSlidingScaleV0.sol +493 -0
- package/contracts/minter-suite/Minters/one-off/ClaimMinter.sol +595 -0
- package/contracts/minter-suite/Minters/one-off/MinterSetPriceTieredOnChainAllowV0.sol +894 -0
- package/contracts/minter-suite/Minters/one-off/SeaDropXArtBlocksShim.sol +59 -41
- package/contracts/mock/ENSLibMock.sol +25 -0
- package/contracts/mock/EnumerableSetUint16Mock.sol +88 -0
- package/contracts/mock/FeistelWalkLibMock.sol +81 -0
- package/contracts/mock/ImmutableUint16ArrayMock.sol +62 -0
- package/contracts/mock/MockGenArt721V3Core.sol +416 -0
- package/contracts/mock/MockPMP.sol +287 -0
- package/contracts/mock/MockTransferHook.sol +160 -0
- package/contracts/mock/MockTransferHookTestHelpers.sol +96 -0
- package/contracts/mock/ReentrancyBatchMockShared.sol +53 -0
- package/contracts/mock/RelayExecutorTestHelper.sol +44 -0
- package/contracts/relay/RelayExecutor.sol +61 -0
- package/contracts/relay/RelayExecutorPartialReverts.sol +79 -0
- package/contracts/royalty-registry/GenArt721RoyaltyOverrideSplits.sol +130 -0
- package/contracts/utils/MintMulticallUtil.sol +103 -0
- package/contracts/web3call/PMPV0.sol +92 -98
- package/contracts/web3call/PMPV1.sol +1204 -0
- package/contracts/web3call/augment-hooks/AbstractPMPAugmentHook.sol +1 -1
- package/contracts/web3call/augment-hooks/InjectBaseGasFee.sol +1 -1
- package/contracts/web3call/augment-hooks/InjectBlockHeight.sol +57 -0
- package/contracts/web3call/augment-hooks/InjectBlockHeightAndArtistProjectOverrides.sol +310 -0
- package/contracts/web3call/augment-hooks/InjectBlockHeightAndNumOwnedProjectTokens.sol +141 -0
- package/contracts/web3call/augment-hooks/InjectBlockHeightProjectInvocationsAndArtistProjectOverrides.sol +326 -0
- package/contracts/web3call/augment-hooks/InjectBlockTimestamp.sol +57 -0
- package/contracts/web3call/augment-hooks/InjectBytesPerToken.sol +279 -0
- package/contracts/web3call/augment-hooks/InjectIsProjectFullyMinted.sol +1 -1
- package/contracts/web3call/augment-hooks/InjectTokenHashSeed.sol +1 -1
- package/contracts/web3call/augment-hooks/InjectTokenOwner.sol +1 -1
- package/contracts/web3call/augment-hooks/InjectTokenOwnerEthBalance.sol +1 -1
- package/contracts/web3call/augment-hooks/SRHooks.sol +1722 -0
- package/contracts/web3call/combined-hooks/LiftHooks.sol +304 -0
- package/contracts/web3call/configure-hooks/{abstractPMPConfigureHook.sol → AbstractPMPConfigureHook.sol} +1 -1
- package/contracts/web3call/configure-hooks/PMPConfigureLockHook.sol +107 -0
- package/package.json +40 -25
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
// SPDX-License-Identifier: LGPL-3.0-only
|
|
2
|
+
// Created By: Art Blocks Inc.
|
|
3
|
+
|
|
4
|
+
pragma solidity ^0.8.0;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @title EnumerableSetUint16
|
|
8
|
+
* @author Art Blocks Inc.
|
|
9
|
+
* @notice Gas-optimized enumerable set library for uint16 values with assembly optimizations.
|
|
10
|
+
* @dev This library efficiently packs uint16 values into shared uint256 storage slots,
|
|
11
|
+
* storing up to 16 uint16 values per slot. This significantly reduces gas costs compared
|
|
12
|
+
* to OpenZeppelin's EnumerableSet.UintSet which stores each value in its own slot.
|
|
13
|
+
*
|
|
14
|
+
* The library maintains:
|
|
15
|
+
* - A packed array where each uint256 slot contains up to 16 uint16 values (stored as value+1)
|
|
16
|
+
* - An index mapping for O(1) lookups (maps value -> packed position)
|
|
17
|
+
*
|
|
18
|
+
* Values are stored as (value + 1) to distinguish empty slots (0) from actual values.
|
|
19
|
+
* This means the maximum storable value is 65534 (not 65535).
|
|
20
|
+
*
|
|
21
|
+
* Count is derived on-demand by examining the last slot to find the highest populated position.
|
|
22
|
+
* This eliminates an SSTORE operation on every add/remove, significantly reducing gas costs.
|
|
23
|
+
*
|
|
24
|
+
* Assembly is used extensively for:
|
|
25
|
+
* - Efficient bit manipulation operations
|
|
26
|
+
* - Optimized storage access patterns
|
|
27
|
+
* - Reduced memory operations
|
|
28
|
+
* - Binary search for finding highest offset
|
|
29
|
+
*
|
|
30
|
+
* Interface is compatible with OpenZeppelin's EnumerableSet.UintSet, but specifically
|
|
31
|
+
* for uint16 values.
|
|
32
|
+
*/
|
|
33
|
+
library EnumerableSetUint16 {
|
|
34
|
+
/**
|
|
35
|
+
* @dev Structure to hold the set data.
|
|
36
|
+
*
|
|
37
|
+
* Storage layout:
|
|
38
|
+
* - _values: Array of uint256 where each element packs 16 uint16 values (stored as value+1)
|
|
39
|
+
* - _indexesPacked: Packed mapping where each uint256 contains 16 positions (16 bits each)
|
|
40
|
+
*
|
|
41
|
+
* Position encoding: 16 bits per position = (slotIndex << 4) | offsetInSlot + 1
|
|
42
|
+
* - Bits 0-11: slotIndex (supports up to 4096 slots = 65,536 values)
|
|
43
|
+
* - Bits 12-15: offsetInSlot (0-15)
|
|
44
|
+
* - +1 makes it 1-indexed so 0 means "not present"
|
|
45
|
+
*
|
|
46
|
+
* Packing in _indexesPacked:
|
|
47
|
+
* - Key: value >> 4 (bucket index - groups of 16 values)
|
|
48
|
+
* - Value: uint256 containing 16 packed 16-bit positions
|
|
49
|
+
* - Position in bucket: value & 0xF (determines which 16-bit segment)
|
|
50
|
+
*/
|
|
51
|
+
struct Uint16Set {
|
|
52
|
+
// Array of packed uint256 slots, each containing up to 16 uint16 values (as value+1)
|
|
53
|
+
uint256[] _values;
|
|
54
|
+
// Packed mapping: each uint256 holds 16 positions (16 bits each) for 16 consecutive values
|
|
55
|
+
// Bucket (value>>4) maps to uint256 with 16 positions at (value&0xF)*16 bits
|
|
56
|
+
mapping(uint16 => uint256) _indexesPacked;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @dev Add a value to a set. O(1).
|
|
61
|
+
* Returns true if the value was added to the set, that is if it was not
|
|
62
|
+
* already present.
|
|
63
|
+
* @param value The uint16 value to add. Must be < 65535 (max uint16 - 1).
|
|
64
|
+
*/
|
|
65
|
+
function add(Uint16Set storage set, uint16 value) internal returns (bool) {
|
|
66
|
+
require(
|
|
67
|
+
value < type(uint16).max,
|
|
68
|
+
"EnumerableSetUint16: value too large"
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
if (contains(set, value)) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
uint256 count = length(set);
|
|
76
|
+
uint256 slotIndex;
|
|
77
|
+
uint256 offsetInSlot;
|
|
78
|
+
|
|
79
|
+
assembly {
|
|
80
|
+
// slotIndex = count >> 4 (count / 16)
|
|
81
|
+
slotIndex := shr(4, count)
|
|
82
|
+
// offsetInSlot = count & 0xF (count % 16)
|
|
83
|
+
offsetInSlot := and(count, 0xF)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Ensure the slot exists
|
|
87
|
+
if (slotIndex >= set._values.length) {
|
|
88
|
+
set._values.push(0);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Pack the value+1 into the slot using assembly
|
|
92
|
+
assembly {
|
|
93
|
+
// Calculate storage slot for _values[slotIndex]
|
|
94
|
+
mstore(0x00, set.slot)
|
|
95
|
+
let valuesSlot := keccak256(0x00, 0x20)
|
|
96
|
+
let targetSlot := add(valuesSlot, slotIndex)
|
|
97
|
+
|
|
98
|
+
// Load current slot value
|
|
99
|
+
let slot := sload(targetSlot)
|
|
100
|
+
|
|
101
|
+
// Calculate shift amount: offsetInSlot * 16
|
|
102
|
+
let shiftAmount := shl(4, offsetInSlot)
|
|
103
|
+
|
|
104
|
+
// Create mask: 0xFFFF << shiftAmount
|
|
105
|
+
let mask := shl(shiftAmount, 0xFFFF)
|
|
106
|
+
|
|
107
|
+
// Clear the target position and insert value+1
|
|
108
|
+
// slot = (slot & ~mask) | ((value + 1) << shiftAmount)
|
|
109
|
+
slot := or(and(slot, not(mask)), shl(shiftAmount, add(value, 1)))
|
|
110
|
+
|
|
111
|
+
// Store back
|
|
112
|
+
sstore(targetSlot, slot)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Store the position (1-indexed) in packed format
|
|
116
|
+
// Position encodes: ((slotIndex << 4) | offsetInSlot) + 1
|
|
117
|
+
uint256 position;
|
|
118
|
+
assembly {
|
|
119
|
+
position := add(or(shl(4, slotIndex), offsetInSlot), 1)
|
|
120
|
+
}
|
|
121
|
+
_setPackedIndex(set._indexesPacked, value, position);
|
|
122
|
+
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* @dev Removes a value from a set. O(1).
|
|
128
|
+
* Returns true if the value was removed from the set, that is if it was
|
|
129
|
+
* present.
|
|
130
|
+
*/
|
|
131
|
+
function remove(
|
|
132
|
+
Uint16Set storage set,
|
|
133
|
+
uint16 value
|
|
134
|
+
) internal returns (bool) {
|
|
135
|
+
uint256 valueIndex = _getPackedIndex(set._indexesPacked, value);
|
|
136
|
+
|
|
137
|
+
if (valueIndex == 0) {
|
|
138
|
+
return false; // Value not in set
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
uint256 lastIndex = length(set) - 1;
|
|
142
|
+
uint256 valuePosition = valueIndex - 1;
|
|
143
|
+
|
|
144
|
+
// Calculate last slot position (used in both branches)
|
|
145
|
+
uint256 lastSlotIndex;
|
|
146
|
+
uint256 lastOffsetInSlot;
|
|
147
|
+
assembly {
|
|
148
|
+
lastSlotIndex := shr(4, lastIndex)
|
|
149
|
+
lastOffsetInSlot := and(lastIndex, 0xF)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (lastIndex != valuePosition) {
|
|
153
|
+
uint256 lastValuePlusOne;
|
|
154
|
+
|
|
155
|
+
assembly {
|
|
156
|
+
// Load last value
|
|
157
|
+
mstore(0x00, set.slot)
|
|
158
|
+
let valuesSlot := keccak256(0x00, 0x20)
|
|
159
|
+
let lastSlot := sload(add(valuesSlot, lastSlotIndex))
|
|
160
|
+
|
|
161
|
+
// Extract last value: (lastSlot >> (lastOffsetInSlot * 16)) & 0xFFFF
|
|
162
|
+
lastValuePlusOne := and(
|
|
163
|
+
shr(shl(4, lastOffsetInSlot), lastSlot),
|
|
164
|
+
0xFFFF
|
|
165
|
+
)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Move last value to the removed value's position
|
|
169
|
+
uint256 valueSlotIndex;
|
|
170
|
+
uint256 valueOffsetInSlot;
|
|
171
|
+
|
|
172
|
+
assembly {
|
|
173
|
+
valueSlotIndex := shr(4, valuePosition)
|
|
174
|
+
valueOffsetInSlot := and(valuePosition, 0xF)
|
|
175
|
+
|
|
176
|
+
// Calculate storage slot
|
|
177
|
+
mstore(0x00, set.slot)
|
|
178
|
+
let valuesSlot := keccak256(0x00, 0x20)
|
|
179
|
+
let targetSlot := add(valuesSlot, valueSlotIndex)
|
|
180
|
+
|
|
181
|
+
// Load current slot
|
|
182
|
+
let slot := sload(targetSlot)
|
|
183
|
+
|
|
184
|
+
// Calculate shift and mask
|
|
185
|
+
let shiftAmount := shl(4, valueOffsetInSlot)
|
|
186
|
+
let mask := shl(shiftAmount, 0xFFFF)
|
|
187
|
+
|
|
188
|
+
// Update slot: (slot & ~mask) | (lastValuePlusOne << shiftAmount)
|
|
189
|
+
slot := or(
|
|
190
|
+
and(slot, not(mask)),
|
|
191
|
+
shl(shiftAmount, lastValuePlusOne)
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
// Store back
|
|
195
|
+
sstore(targetSlot, slot)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Update the moved value's index
|
|
199
|
+
_setPackedIndex(
|
|
200
|
+
set._indexesPacked,
|
|
201
|
+
uint16(lastValuePlusOne - 1),
|
|
202
|
+
valueIndex
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Clear the last position
|
|
207
|
+
bool shouldPop;
|
|
208
|
+
|
|
209
|
+
assembly {
|
|
210
|
+
// Calculate storage slot
|
|
211
|
+
mstore(0x00, set.slot)
|
|
212
|
+
let valuesSlot := keccak256(0x00, 0x20)
|
|
213
|
+
let targetSlot := add(valuesSlot, lastSlotIndex)
|
|
214
|
+
|
|
215
|
+
// Load current slot
|
|
216
|
+
let slot := sload(targetSlot)
|
|
217
|
+
|
|
218
|
+
// Clear the position: slot & ~(0xFFFF << (lastOffsetInSlot * 16))
|
|
219
|
+
let shiftAmount := shl(4, lastOffsetInSlot)
|
|
220
|
+
let mask := shl(shiftAmount, 0xFFFF)
|
|
221
|
+
slot := and(slot, not(mask))
|
|
222
|
+
|
|
223
|
+
// Store back
|
|
224
|
+
sstore(targetSlot, slot)
|
|
225
|
+
|
|
226
|
+
// Check if we should pop: slot is zero
|
|
227
|
+
shouldPop := iszero(slot)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Pop the array if the last slot is now empty
|
|
231
|
+
if (shouldPop && lastSlotIndex == set._values.length - 1) {
|
|
232
|
+
set._values.pop();
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Delete the removed value's packed index
|
|
236
|
+
_setPackedIndex(set._indexesPacked, value, 0);
|
|
237
|
+
|
|
238
|
+
return true;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* @dev Returns true if the value is in the set. O(1).
|
|
243
|
+
*/
|
|
244
|
+
function contains(
|
|
245
|
+
Uint16Set storage set,
|
|
246
|
+
uint16 value
|
|
247
|
+
) internal view returns (bool) {
|
|
248
|
+
return _getPackedIndex(set._indexesPacked, value) != 0;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* @dev Returns the number of values in the set. O(1) amortized.
|
|
253
|
+
* Uses binary search to find the highest populated position in the last slot.
|
|
254
|
+
*/
|
|
255
|
+
function length(
|
|
256
|
+
Uint16Set storage set
|
|
257
|
+
) internal view returns (uint256 result) {
|
|
258
|
+
uint256 valuesLength = set._values.length;
|
|
259
|
+
|
|
260
|
+
if (valuesLength == 0) {
|
|
261
|
+
return 0;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
uint256 lastSlot = set._values[valuesLength - 1];
|
|
265
|
+
|
|
266
|
+
// Use binary search to find highest non-zero 16-bit segment
|
|
267
|
+
uint256 highestOffset;
|
|
268
|
+
assembly {
|
|
269
|
+
let slot := lastSlot
|
|
270
|
+
highestOffset := 0
|
|
271
|
+
|
|
272
|
+
// Binary search for highest non-zero segment
|
|
273
|
+
// Check upper half (bits 128-255)
|
|
274
|
+
let upper := shr(128, slot)
|
|
275
|
+
if gt(upper, 0) {
|
|
276
|
+
highestOffset := 8
|
|
277
|
+
slot := upper
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Check upper 4 positions of current 8-position range
|
|
281
|
+
upper := shr(64, slot)
|
|
282
|
+
if gt(upper, 0) {
|
|
283
|
+
highestOffset := add(highestOffset, 4)
|
|
284
|
+
slot := upper
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Check upper 2 positions of current 4-position range
|
|
288
|
+
upper := shr(32, slot)
|
|
289
|
+
if gt(upper, 0) {
|
|
290
|
+
highestOffset := add(highestOffset, 2)
|
|
291
|
+
slot := upper
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Check upper 1 position of current 2-position range
|
|
295
|
+
upper := shr(16, slot)
|
|
296
|
+
if gt(upper, 0) {
|
|
297
|
+
highestOffset := add(highestOffset, 1)
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Calculate total length: ((valuesLength - 1) * 16) + highestOffset + 1
|
|
302
|
+
return ((valuesLength - 1) << 4) + highestOffset + 1;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* @dev Returns the value stored at position `index` in the set. O(1).
|
|
307
|
+
*
|
|
308
|
+
* Note that there are no guarantees on the ordering of values inside the
|
|
309
|
+
* array, and it may change when more values are added or removed.
|
|
310
|
+
*
|
|
311
|
+
* Requirements:
|
|
312
|
+
* - `index` must be strictly less than {length}.
|
|
313
|
+
*/
|
|
314
|
+
function at(
|
|
315
|
+
Uint16Set storage set,
|
|
316
|
+
uint256 index
|
|
317
|
+
) internal view returns (uint16) {
|
|
318
|
+
require(
|
|
319
|
+
index < length(set),
|
|
320
|
+
"EnumerableSetUint16: index out of bounds"
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
uint256 result;
|
|
324
|
+
assembly {
|
|
325
|
+
// slotIndex = index >> 4
|
|
326
|
+
let slotIndex := shr(4, index)
|
|
327
|
+
// offsetInSlot = index & 0xF
|
|
328
|
+
let offsetInSlot := and(index, 0xF)
|
|
329
|
+
|
|
330
|
+
// Load slot value
|
|
331
|
+
mstore(0x00, set.slot)
|
|
332
|
+
let valuesSlot := keccak256(0x00, 0x20)
|
|
333
|
+
let slot := sload(add(valuesSlot, slotIndex))
|
|
334
|
+
|
|
335
|
+
// Extract value: (slot >> (offsetInSlot * 16)) & 0xFFFF - 1
|
|
336
|
+
result := sub(and(shr(shl(4, offsetInSlot), slot), 0xFFFF), 1)
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return uint16(result);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* @dev Returns an array containing all values in the set. O(N).
|
|
344
|
+
*
|
|
345
|
+
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive.
|
|
346
|
+
* This is designed to mostly be used by view accessors that are queried without any gas fees.
|
|
347
|
+
* Developers should keep in mind that this function has an unbounded cost, and using it as part
|
|
348
|
+
* of a state-changing function may render the function uncallable if the set grows to a point
|
|
349
|
+
* where copying to memory consumes too much gas to fit in a block.
|
|
350
|
+
*/
|
|
351
|
+
function values(
|
|
352
|
+
Uint16Set storage set
|
|
353
|
+
) internal view returns (uint256[] memory) {
|
|
354
|
+
uint256 count = length(set);
|
|
355
|
+
uint256[] memory result = new uint256[](count);
|
|
356
|
+
|
|
357
|
+
for (uint256 i = 0; i < count; i++) {
|
|
358
|
+
result[i] = at(set, i);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
return result;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* @dev Internal helper to get a packed index for a value.
|
|
366
|
+
* @param packed The packed index mapping.
|
|
367
|
+
* @param value The uint16 value to look up.
|
|
368
|
+
* @return position The position (1-indexed, 0 means not present).
|
|
369
|
+
*/
|
|
370
|
+
function _getPackedIndex(
|
|
371
|
+
mapping(uint16 => uint256) storage packed,
|
|
372
|
+
uint16 value
|
|
373
|
+
) private view returns (uint256 position) {
|
|
374
|
+
assembly {
|
|
375
|
+
// bucketIndex = value >> 4
|
|
376
|
+
let bucketIndex := shr(4, value)
|
|
377
|
+
// posInBucket = value & 0xF
|
|
378
|
+
let posInBucket := and(value, 0xF)
|
|
379
|
+
|
|
380
|
+
// Calculate storage slot for packed[bucketIndex]
|
|
381
|
+
mstore(0x00, bucketIndex)
|
|
382
|
+
mstore(0x20, packed.slot)
|
|
383
|
+
let bucketSlot := keccak256(0x00, 0x40)
|
|
384
|
+
|
|
385
|
+
// Load bucket
|
|
386
|
+
let bucket := sload(bucketSlot)
|
|
387
|
+
|
|
388
|
+
// Extract position: (bucket >> (posInBucket * 16)) & 0xFFFF
|
|
389
|
+
position := and(shr(shl(4, posInBucket), bucket), 0xFFFF)
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* @dev Internal helper to set a packed index for a value.
|
|
395
|
+
* @param packed The packed index mapping.
|
|
396
|
+
* @param value The uint16 value to set.
|
|
397
|
+
* @param position The position to store (1-indexed, 0 means remove).
|
|
398
|
+
*/
|
|
399
|
+
function _setPackedIndex(
|
|
400
|
+
mapping(uint16 => uint256) storage packed,
|
|
401
|
+
uint16 value,
|
|
402
|
+
uint256 position
|
|
403
|
+
) private {
|
|
404
|
+
assembly {
|
|
405
|
+
// bucketIndex = value >> 4
|
|
406
|
+
let bucketIndex := shr(4, value)
|
|
407
|
+
// posInBucket = value & 0xF
|
|
408
|
+
let posInBucket := and(value, 0xF)
|
|
409
|
+
|
|
410
|
+
// Calculate storage slot for packed[bucketIndex]
|
|
411
|
+
mstore(0x00, bucketIndex)
|
|
412
|
+
mstore(0x20, packed.slot)
|
|
413
|
+
let bucketSlot := keccak256(0x00, 0x40)
|
|
414
|
+
|
|
415
|
+
// Load current bucket
|
|
416
|
+
let bucket := sload(bucketSlot)
|
|
417
|
+
|
|
418
|
+
// Calculate shift and mask
|
|
419
|
+
let shiftAmount := shl(4, posInBucket)
|
|
420
|
+
let mask := shl(shiftAmount, 0xFFFF)
|
|
421
|
+
|
|
422
|
+
// Update bucket: (bucket & ~mask) | (position << shiftAmount)
|
|
423
|
+
bucket := or(and(bucket, not(mask)), shl(shiftAmount, position))
|
|
424
|
+
|
|
425
|
+
// Store back
|
|
426
|
+
sstore(bucketSlot, bucket)
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.20;
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @title FeistelWalkLib
|
|
6
|
+
* @author Art Blocks Inc.
|
|
7
|
+
* @notice Uniform once-over traversal of [0..N) via a seeded Feistel permutation.
|
|
8
|
+
* @dev Designed for off-chain eth_call sampling (e.g., pick K=100 from N≈10k).
|
|
9
|
+
* - No duplicates, full coverage if you iterate k=0..N-1
|
|
10
|
+
* - O(1) per index; O(K) to sample K items
|
|
11
|
+
* - Works for any N (uses cycle-walking from next power-of-two domain)
|
|
12
|
+
* - Not cryptographic; optimized for gas efficiency with good mixing
|
|
13
|
+
* Uses 2 Feistel rounds with 64-bit round keys (k0, k1) derived from the seed.
|
|
14
|
+
* Additional keys (k2, k3) reserved for potential future use.
|
|
15
|
+
*
|
|
16
|
+
* The Feistel domain is exactly 2^logM = M (the next power of two >= N) for both
|
|
17
|
+
* even and odd logM, achieved with an UNBALANCED split in `_feistelOnPow2Domain`
|
|
18
|
+
* (`a = logM/2`, `b = logM - a`, `a + b = logM`). This keeps M <= 2N, so the
|
|
19
|
+
* cycle-walk in-range probability is >= ~0.5 and a full traversal (k = 0..N-1) is
|
|
20
|
+
* a true permutation of [0..N) with no duplicates or drops.
|
|
21
|
+
*/
|
|
22
|
+
library FeistelWalkLib {
|
|
23
|
+
uint256 private constant MAX_CYCLE_WALKS = 32;
|
|
24
|
+
// -------------------------------------------------------------------------
|
|
25
|
+
// Public API
|
|
26
|
+
// -------------------------------------------------------------------------
|
|
27
|
+
|
|
28
|
+
/// @notice Immutable traversal plan (deterministic from (seed, N)).
|
|
29
|
+
/// @dev Build once per call, then stream with `index(plan, k)` or batch via `sample(plan, K)`.
|
|
30
|
+
struct Plan {
|
|
31
|
+
uint256 N; // pool size (>= 1)
|
|
32
|
+
uint256 M; // next power-of-two >= N (<= 2N)
|
|
33
|
+
uint256 logM; // log2(M) - precomputed to avoid repeated calculation
|
|
34
|
+
uint256 rounds; // Feistel rounds (2 for gas-efficient mixing)
|
|
35
|
+
uint64 k0; // Round key 0
|
|
36
|
+
uint64 k1; // Round key 1
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/// @notice Build a Feistel permutation plan over [0..N).
|
|
40
|
+
/// @param seed Arbitrary seed (domain-separate upstream if you like).
|
|
41
|
+
/// @param N Domain size; must be > 0.
|
|
42
|
+
function makePlan(
|
|
43
|
+
bytes32 seed,
|
|
44
|
+
uint256 N
|
|
45
|
+
) internal pure returns (Plan memory p) {
|
|
46
|
+
require(N > 0, "FeistelWalkLib:N=0");
|
|
47
|
+
p.N = N;
|
|
48
|
+
p.M = _nextPow2(N); // <= 2N
|
|
49
|
+
p.logM = _log2ceil(p.M); // precompute to avoid repeated calculation
|
|
50
|
+
p.rounds = 2; // 2 rounds provides good mixing with lower gas cost
|
|
51
|
+
|
|
52
|
+
// Derive round keys for 2-round Feistel
|
|
53
|
+
p.k0 = uint64(
|
|
54
|
+
uint256(keccak256(abi.encodePacked(seed, "feistel.k0", N)))
|
|
55
|
+
);
|
|
56
|
+
p.k1 = uint64(
|
|
57
|
+
uint256(keccak256(abi.encodePacked(seed, "feistel.k1", N)))
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/// @notice Stream the k-th index in the seeded permutation.
|
|
62
|
+
/// @dev Requires 0 <= k < N. O(1) arithmetic; bounded cycle-walk if N not power of two.
|
|
63
|
+
function index(
|
|
64
|
+
Plan memory p,
|
|
65
|
+
uint256 k
|
|
66
|
+
) internal pure returns (uint256 idx) {
|
|
67
|
+
require(k < p.N, "FeistelWalkLib:k>=N");
|
|
68
|
+
if (p.N == 1) return 0; // trivial domain
|
|
69
|
+
|
|
70
|
+
// Permute k into [0..N) using Feistel over [0..M) + cycle-walking
|
|
71
|
+
return _feistelPermuteRange(k, p.N, p.M, p.logM, p.rounds, p.k0, p.k1);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/// @notice Return up to K indices from the permutation (k = 0..K-1).
|
|
75
|
+
/// @dev If K > N, it clamps to N. Allocates an array of size K'.
|
|
76
|
+
function sample(
|
|
77
|
+
Plan memory p,
|
|
78
|
+
uint256 K
|
|
79
|
+
) internal pure returns (uint256[] memory out) {
|
|
80
|
+
if (K > p.N) K = p.N;
|
|
81
|
+
out = new uint256[](K);
|
|
82
|
+
unchecked {
|
|
83
|
+
for (uint256 i = 0; i < K; ++i) {
|
|
84
|
+
out[i] = index(p, i);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// -------------------------------------------------------------------------
|
|
90
|
+
// Internal: Feistel on arbitrary N via power-of-two domain + cycle-walk
|
|
91
|
+
// -------------------------------------------------------------------------
|
|
92
|
+
|
|
93
|
+
/// @dev Permute x∈[0..N) by embedding into [0..M) (M power of two), running Feistel,
|
|
94
|
+
/// then cycle-walking until result < N. With M < 2N, p = N/M ≥ ~0.5 in worst case.
|
|
95
|
+
/// Hard-cap at MAX_CYCLE_WALKS to guarantee bounded work; on overflow, return `x`.
|
|
96
|
+
function _feistelPermuteRange(
|
|
97
|
+
uint256 x,
|
|
98
|
+
uint256 N,
|
|
99
|
+
uint256 M,
|
|
100
|
+
uint256 logM,
|
|
101
|
+
uint256 rounds,
|
|
102
|
+
uint64 k0,
|
|
103
|
+
uint64 k1
|
|
104
|
+
) private pure returns (uint256) {
|
|
105
|
+
if (N == 1) return 0; // trivial domain
|
|
106
|
+
uint256 y = x;
|
|
107
|
+
unchecked {
|
|
108
|
+
for (uint256 i = 0; i < MAX_CYCLE_WALKS; ++i) {
|
|
109
|
+
uint256 z = _feistelOnPow2Domain(y, M, logM, rounds, k0, k1);
|
|
110
|
+
if (z < N) return z; // landed inside domain
|
|
111
|
+
y = z; // cycle-walk and try again
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Ultra-rare guard: deterministic in-domain fallback (keeps progress).
|
|
115
|
+
return x;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/// @dev Feistel permutation over [0..M) where M is a power of two.
|
|
119
|
+
/// Split into a low half (a bits) and a high half (b bits) with
|
|
120
|
+
/// a + b = logM, and apply the round function twice for good mixing.
|
|
121
|
+
/// Using an UNBALANCED split (a = logM/2, b = logM - a) keeps the domain
|
|
122
|
+
/// exactly 2^logM = M for both even and odd logM. A balanced split
|
|
123
|
+
/// (half = (logM + 1) / 2) would span 2*half = logM + 1 bits for odd logM
|
|
124
|
+
/// and therefore permute [0, 2M) instead of [0, M); the wider domain pushes
|
|
125
|
+
/// the cycle-walk past its cap for N just above a power of two and triggers
|
|
126
|
+
/// the identity `return x` fallback, breaking the bijection (duplicate /
|
|
127
|
+
/// missing elements). Each round masks its output to the width of the half
|
|
128
|
+
/// it writes, so every round is invertible and the whole map is a bijection
|
|
129
|
+
/// over [0, M). For even logM, a == b and this is identical to a balanced
|
|
130
|
+
/// split.
|
|
131
|
+
function _feistelOnPow2Domain(
|
|
132
|
+
uint256 x,
|
|
133
|
+
uint256 M,
|
|
134
|
+
uint256 logM,
|
|
135
|
+
uint256 /* rounds */,
|
|
136
|
+
uint64 k0,
|
|
137
|
+
uint64 k1
|
|
138
|
+
) private pure returns (uint256) {
|
|
139
|
+
if (M == 1) return 0; // degenerate
|
|
140
|
+
if (M == 2) {
|
|
141
|
+
// Special case: 2-element domain, use key to determine permutation
|
|
142
|
+
return ((k0 & 1) == 0) ? x : (1 - x);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Full assembly for maximum gas efficiency
|
|
146
|
+
uint256 result;
|
|
147
|
+
assembly {
|
|
148
|
+
// Unbalanced Feistel: low half is `a` bits, high half is `b` bits,
|
|
149
|
+
// with a + b = logM (so the domain is exactly 2^logM = M).
|
|
150
|
+
let a := div(logM, 2)
|
|
151
|
+
let b := sub(logM, a)
|
|
152
|
+
let maskA := sub(shl(a, 1), 1)
|
|
153
|
+
let maskB := sub(shl(b, 1), 1)
|
|
154
|
+
|
|
155
|
+
// Split into L (low, a bits) and R (high, b bits)
|
|
156
|
+
let L := and(x, maskA)
|
|
157
|
+
let R := and(shr(a, x), maskB)
|
|
158
|
+
|
|
159
|
+
// Round 0: R (b bits) -> a-bit register
|
|
160
|
+
let F := and(R, 0xFFFFFFFFFFFFFFFF)
|
|
161
|
+
F := xor(F, k0)
|
|
162
|
+
F := xor(F, shl(13, F))
|
|
163
|
+
F := xor(F, shr(7, F))
|
|
164
|
+
F := xor(F, shl(17, F))
|
|
165
|
+
F := xor(F, shr(5, F))
|
|
166
|
+
|
|
167
|
+
let newR := and(xor(L, F), maskA) // a bits
|
|
168
|
+
L := R // b bits
|
|
169
|
+
R := newR // a bits
|
|
170
|
+
|
|
171
|
+
// Round 1: R (a bits) -> b-bit register
|
|
172
|
+
F := and(R, 0xFFFFFFFFFFFFFFFF)
|
|
173
|
+
F := xor(F, xor(k1, 1))
|
|
174
|
+
F := xor(F, shl(13, F))
|
|
175
|
+
F := xor(F, shr(7, F))
|
|
176
|
+
F := xor(F, shl(17, F))
|
|
177
|
+
F := xor(F, shr(5, F))
|
|
178
|
+
|
|
179
|
+
newR := and(xor(L, F), maskB) // b bits
|
|
180
|
+
L := R // a bits
|
|
181
|
+
R := newR // b bits
|
|
182
|
+
|
|
183
|
+
// Recombine: R (b bits) high, L (a bits) low => a + b = logM bits
|
|
184
|
+
result := or(shl(a, R), L)
|
|
185
|
+
}
|
|
186
|
+
return result;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// -------------------------------------------------------------------------
|
|
190
|
+
// Internal: Bit helpers
|
|
191
|
+
// -------------------------------------------------------------------------
|
|
192
|
+
|
|
193
|
+
/// @dev Next power of two ≥ x. For x==0, returns 1.
|
|
194
|
+
function _nextPow2(uint256 x) private pure returns (uint256) {
|
|
195
|
+
if (x <= 1) return 1;
|
|
196
|
+
unchecked {
|
|
197
|
+
x -= 1;
|
|
198
|
+
x |= x >> 1;
|
|
199
|
+
x |= x >> 2;
|
|
200
|
+
x |= x >> 4;
|
|
201
|
+
x |= x >> 8;
|
|
202
|
+
x |= x >> 16;
|
|
203
|
+
x |= x >> 32;
|
|
204
|
+
x |= x >> 64;
|
|
205
|
+
x |= x >> 128;
|
|
206
|
+
return x + 1;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/// @dev ceil(log2(x)) for x≥1. (Number of bits to represent x-1.)
|
|
211
|
+
function _log2ceil(uint256 x) private pure returns (uint256 n) {
|
|
212
|
+
require(x > 0, "log2ceil(0)");
|
|
213
|
+
unchecked {
|
|
214
|
+
x -= 1;
|
|
215
|
+
while (x > 0) {
|
|
216
|
+
x >>= 1;
|
|
217
|
+
++n;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|