@artblocks/contracts 1.1.0 → 1.2.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 +75 -7
- package/artifacts/contracts/AdminACLV0.sol/AdminACLV0.json +2 -2
- package/artifacts/contracts/AdminACLV1.sol/AdminACLV1.json +2 -2
- package/artifacts/contracts/DependencyRegistryV0.sol/DependencyRegistryV0.json +273 -155
- package/artifacts/contracts/archive/GenArt721CoreV3.sol/GenArt721CoreV3.json +2047 -0
- package/artifacts/contracts/archive/GenArt721CoreV3_Explorations.sol/GenArt721CoreV3_Explorations.json +2021 -0
- package/artifacts/contracts/{minter-suite → archive/minter-suite}/Minters/MinterBase_v0_1_1.sol/MinterBase.json +1 -1
- 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/{minter-suite/Minters → archive/minter-suite/Minters/MinterDAExp}/MinterDAExpV4.sol/MinterDAExpV4.json +3 -3
- 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/{minter-suite/Minters → archive/minter-suite/Minters/MinterDAExpSettlement}/MinterDAExpSettlementV2.sol/MinterDAExpSettlementV2.json +3 -3
- 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/{minter-suite/Minters → archive/minter-suite/Minters/MinterDALin}/MinterDALinV4.sol/MinterDALinV4.json +3 -3
- 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/{minter-suite/Minters → archive/minter-suite/Minters/MinterHolder}/MinterHolderV4.sol/MinterHolderV4.json +3 -3
- 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/{minter-suite/Minters → archive/minter-suite/Minters/MinterMerkle}/MinterMerkleV5.sol/MinterMerkleV5.json +3 -3
- package/artifacts/contracts/{minter-suite/Minters → archive/minter-suite/Minters/MinterPolyptych}/MinterPolyptychV0.sol/IGenArt721CoreContractV3WithRandomizer.json +31 -63
- package/artifacts/contracts/{minter-suite/Minters → archive/minter-suite/Minters/MinterPolyptych}/MinterPolyptychV0.sol/MinterPolyptychV0.json +3 -3
- package/artifacts/contracts/{minter-suite/Minters → archive/minter-suite/Minters/MinterSEA}/MinterSEAV0.sol/MinterSEAV0.json +3 -3
- 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/{minter-suite/Minters → archive/minter-suite/Minters/MinterSetPrice}/MinterSetPriceV4.sol/MinterSetPriceV4.json +3 -3
- package/artifacts/contracts/archive/minter-suite/Minters/MinterSetPriceERC20/MinterSetPriceERC20V0.sol/MinterSetPriceERC20V0.json +65 -2
- package/artifacts/contracts/archive/minter-suite/Minters/MinterSetPriceERC20/MinterSetPriceERC20V1.sol/MinterSetPriceERC20V1.json +65 -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 +807 -0
- package/artifacts/contracts/engine/V2/GenArt721MinterBurner_PBAB.sol/GenArt721MinterBurner_PBAB.json +65 -2
- package/artifacts/contracts/engine/V2/GenArt721Minter_PBAB.sol/GenArt721Minter_PBAB.json +65 -2
- package/artifacts/contracts/engine/V3/EngineFactoryV0.sol/EngineFactoryV0.json +606 -0
- package/artifacts/contracts/engine/V3/GenArt721CoreV3_Engine.sol/GenArt721CoreV3_Engine.json +567 -206
- package/artifacts/contracts/engine/V3/GenArt721CoreV3_Engine_Flex.sol/GenArt721CoreV3_Engine_Flex.json +787 -224
- package/artifacts/contracts/engine/V3/forks/GenArt721CoreV3_Engine_Flex_PROOF.sol/GenArt721CoreV3_Engine_Flex_PROOF.json +38 -8
- 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 +38 -8
- package/artifacts/contracts/engine/V3/forks/PROHIBITION/interfaces/IGenArt721CoreContractV3_Engine_Flex_PROHIBITION.sol/IGenArt721CoreContractV3_Engine_Flex_PROHIBITION.json +36 -68
- package/artifacts/contracts/interfaces/v0.8.x/IAdminACLV0_Extended.sol/IAdminACLV0_Extended.json +140 -0
- package/artifacts/contracts/interfaces/v0.8.x/IBytecodeStorageReaderV2.sol/IBytecodeStorageReaderV2.json +130 -0
- package/artifacts/contracts/interfaces/v0.8.x/IDependencyRegistryV0.sol/IDependencyRegistryV0.json +58 -45
- package/artifacts/contracts/interfaces/v0.8.x/IEngineFactoryV0.sol/IEngineFactoryV0.json +283 -0
- package/artifacts/contracts/interfaces/v0.8.x/IFilteredMinterDAExpSettlementV0.sol/IFilteredMinterDAExpSettlementV0.json +12 -12
- package/artifacts/contracts/interfaces/v0.8.x/IFilteredMinterDAExpSettlementV1.sol/IFilteredMinterDAExpSettlementV1.json +12 -12
- package/artifacts/contracts/interfaces/v0.8.x/IGenArt721CoreContractV3.sol/IGenArt721CoreContractV3.json +30 -62
- package/artifacts/contracts/interfaces/v0.8.x/IGenArt721CoreContractV3_Base.sol/IGenArt721CoreContractV3_Base.json +30 -62
- package/artifacts/contracts/interfaces/v0.8.x/IGenArt721CoreContractV3_Engine.sol/IGenArt721CoreContractV3_Engine.json +170 -104
- package/artifacts/contracts/interfaces/v0.8.x/IGenArt721CoreContractV3_Engine_Flex.sol/IGenArt721CoreContractV3_Engine_Flex.json +170 -104
- package/artifacts/contracts/interfaces/v0.8.x/IGenArt721CoreContractV3_Engine_Flex_PreV3p2.sol/IGenArt721CoreContractV3_Engine_Flex_PreV3p2.json +1028 -0
- package/artifacts/contracts/interfaces/v0.8.x/IGenArt721CoreContractV3_Engine_PreV3p2.sol/IGenArt721CoreContractV3_Engine_PreV3p2.json +741 -0
- package/artifacts/contracts/interfaces/v0.8.x/IGenArt721CoreContractV3_ProjectFinance.sol/IGenArt721CoreContractV3_ProjectFinance.json +87 -0
- package/artifacts/contracts/interfaces/v0.8.x/IGenArt721Minter_PBAB.sol/IGenArt721Minter_PBAB.json +279 -0
- package/artifacts/contracts/interfaces/v0.8.x/IPseudorandomAtomic.sol/IPseudorandomAtomic.json +1 -1
- package/artifacts/contracts/interfaces/v0.8.x/ISharedMinterDAExpSettlementV0.sol/ISharedMinterDAExpSettlementV0.json +18 -0
- package/artifacts/contracts/interfaces/v0.8.x/ISharedMinterRAMV0.sol/ISharedMinterRAMV0.json +62 -0
- package/artifacts/contracts/interfaces/v0.8.x/ISharedMinterRequired.sol/ISharedMinterRequired.json +37 -0
- package/artifacts/contracts/interfaces/v0.8.x/ISharedMinterSEAV0.sol/ISharedMinterSEAV0.json +1 -1
- package/artifacts/contracts/interfaces/v0.8.x/ISplitAtomicFactoryV0.sol/ISplitAtomicFactoryV0.json +170 -0
- package/artifacts/contracts/interfaces/v0.8.x/ISplitAtomicV0.sol/ISplitAtomicV0.json +126 -0
- package/artifacts/contracts/interfaces/v0.8.x/ISplitProviderV0.sol/ISplitProviderV0.json +98 -0
- package/artifacts/contracts/interfaces/v0.8.x/integration-refs/splits-0x-v2/ISplitFactoryV2.sol/ISplitFactoryV2.json +123 -0
- package/artifacts/contracts/libs/integration-refs/delegation-registry/DelegationRegistry.sol/DelegationRegistry.json +2 -2
- package/artifacts/contracts/libs/integration-refs/gnosis-safe/GnosisSafeMock.sol/GnosisSafeMock.json +2 -2
- package/artifacts/contracts/libs/integration-refs/gnosis-safe/GnosisSafeProxyFactoryMock.sol/GnosisSafeProxyFactoryMock.json +2 -2
- package/artifacts/contracts/libs/integration-refs/gnosis-safe/MultiSendMock.sol/MultiSendMock.json +2 -2
- package/artifacts/contracts/libs/integration-refs/weth9/weth9.sol/WETH9_.json +2 -2
- package/artifacts/contracts/libs/v0.8.x/ABHelpers.sol/ABHelpers.json +2 -2
- package/artifacts/contracts/libs/v0.8.x/AuthLib.sol/AuthLib.json +2 -2
- package/artifacts/contracts/libs/v0.8.x/BitMap.sol/BitMaps256.json +10 -0
- package/artifacts/contracts/libs/v0.8.x/BytecodeStorageV0.sol/BytecodeStorage.json +2 -2
- package/artifacts/contracts/libs/v0.8.x/BytecodeStorageV1.sol/BytecodeStorageReader.json +2 -2
- package/artifacts/contracts/libs/v0.8.x/BytecodeStorageV1.sol/BytecodeStorageWriter.json +2 -2
- package/artifacts/contracts/libs/v0.8.x/BytecodeStorageV2.sol/BytecodeStorageReader.json +214 -0
- package/artifacts/contracts/libs/v0.8.x/BytecodeStorageV2.sol/BytecodeStorageWriter.json +10 -0
- package/artifacts/contracts/libs/v0.8.x/Bytes32Strings.sol/Bytes32Strings.json +2 -2
- package/artifacts/contracts/libs/v0.8.x/DependencyRegistryStorageLib.sol/DependencyRegistryStorageLib.json +10 -0
- package/artifacts/contracts/libs/v0.8.x/ERC721_PackedHashSeed.sol/ERC721_PackedHashSeed.json +2 -2
- package/artifacts/contracts/libs/v0.8.x/ERC721_PackedHashSeedV1.sol/ERC721_PackedHashSeedV1.json +444 -0
- package/artifacts/contracts/libs/v0.8.x/PackedBools.sol/PackedBools.json +10 -0
- package/artifacts/contracts/libs/v0.8.x/SSTORE2.sol/SSTORE2.json +2 -2
- package/artifacts/contracts/libs/v0.8.x/V3FlexLib.sol/V3FlexLib.json +208 -0
- package/artifacts/contracts/libs/v0.8.x/minter-libs/DAExpLib.sol/DAExpLib.json +2 -2
- package/artifacts/contracts/libs/v0.8.x/minter-libs/DALib.sol/DALib.json +2 -2
- package/artifacts/contracts/libs/v0.8.x/minter-libs/DALinLib.sol/DALinLib.json +2 -2
- package/artifacts/contracts/libs/v0.8.x/minter-libs/GenericMinterEventsLib.sol/GenericMinterEventsLib.json +2 -2
- package/artifacts/contracts/libs/v0.8.x/minter-libs/MaxInvocationsLib.sol/MaxInvocationsLib.json +2 -2
- package/artifacts/contracts/libs/v0.8.x/minter-libs/MerkleLib.sol/MerkleLib.json +2 -2
- 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 +398 -0
- package/artifacts/contracts/libs/v0.8.x/minter-libs/SEALib.sol/SEALib.json +2 -2
- package/artifacts/contracts/libs/v0.8.x/minter-libs/SetPriceLib.sol/SetPriceLib.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/libs/v0.8.x/minter-libs/TokenHolderLib.sol/TokenHolderLib.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/MinterRAMV0.sol/MinterRAMV0.json +1374 -0
- package/artifacts/contracts/minter-suite/Minters/MinterSEAV1.sol/MinterSEAV1.json +7 -7
- 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/MinterSetPricePolyptychERC20V5.sol/MinterSetPricePolyptychERC20V5.json +2 -2
- package/artifacts/contracts/minter-suite/Minters/MinterSetPricePolyptychV5.sol/MinterSetPricePolyptychV5.json +2 -2
- package/artifacts/contracts/minter-suite/Minters/MinterSetPriceV5.sol/MinterSetPriceV5.json +2 -2
- package/artifacts/contracts/minter-suite/Minters/one-off/MinterSetPriceV5_SingleCore.sol/MinterSetPriceV5_SingleCore.json +417 -0
- package/artifacts/contracts/mock/BytecodeV2LibCallsMock.sol/BytecodeV2LibCallsMock.json +154 -0
- package/artifacts/contracts/mock/BytecodeV2TextCR_DMock.sol/BytecodeV2TextCR_DMock.json +428 -0
- package/artifacts/contracts/mock/DummySharedMinter.sol/DummySharedMinter.json +2 -2
- package/artifacts/contracts/mock/ERC20Mock.sol/ERC20Mock.json +2 -2
- package/artifacts/contracts/mock/ForceSendMock.sol/ForceSendMock.json +24 -0
- package/artifacts/contracts/mock/GenArt721CoreV3_Engine_IncorrectCoreType.sol/GenArt721CoreV3_Engine_IncorrectCoreType.json +2 -2
- package/artifacts/contracts/mock/Mock0xSplitsV2PullFactory.sol/Mock0xSplitsV2PullFactory.json +149 -0
- package/artifacts/contracts/mock/Mock0xSplitsV2Splitter.sol/Mock0xSplitsV2Splitter.json +99 -0
- package/artifacts/contracts/mock/MockAdminACLV0.sol/MockAdminACLV0Events.json +20 -2
- package/artifacts/contracts/mock/MockAdminACLV0_PROHIBITION.sol/MockAdminACLV0Events_PROHIBITION.json +20 -2
- package/artifacts/contracts/mock/RandomizerV2_NoAssignMock.sol/RandomizerV2_NoAssignMock.json +2 -2
- package/artifacts/contracts/mock/ReentrancyGenArt721MinterMock.sol/ReentrancyGenArt721MinterMock.json +100 -0
- package/artifacts/contracts/mock/ReentrancyHolderMock.sol/ReentrancyHolderMock.json +2 -2
- package/artifacts/contracts/mock/ReentrancyHolderMockShared.sol/ReentrancyHolderMockShared.json +2 -2
- package/artifacts/contracts/mock/ReentrancyMerkleMock.sol/ReentrancyMerkleMock.json +2 -2
- package/artifacts/contracts/mock/ReentrancyMerkleMockShared.sol/ReentrancyMerkleMockShared.json +2 -2
- package/artifacts/contracts/mock/ReentrancyMock.sol/ReentrancyMock.json +2 -2
- package/artifacts/contracts/mock/ReentrancyMockShared.sol/ReentrancyMockShared.json +2 -2
- package/artifacts/contracts/mock/ReentrancySEAMock.sol/ReentrancySEAAutoBidderMock.json +2 -2
- package/artifacts/contracts/mock/ReentrancySEAMockShared.sol/ReentrancySEAAutoBidderMockShared.json +2 -2
- package/artifacts/contracts/mock/ReentrancySplitterMocks.sol/ReentrancySplitterDrainETHMock.json +54 -0
- package/artifacts/contracts/mock/ReentrancySplitterMocks.sol/ReentrancySplitterSendETHMock.json +54 -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/primitive/PseudorandomAtomicBasic.sol/PseudorandomAtomic.json +2 -2
- package/artifacts/contracts/randomizer/shared/SharedRandomizerV0.sol/SharedRandomizerV0.json +2 -2
- package/artifacts/contracts/split/SplitAtomicFactoryV0.sol/SplitAtomicFactoryV0.json +203 -0
- package/artifacts/contracts/split/SplitAtomicV0.sol/SplitAtomicV0.json +168 -0
- package/artifacts/contracts/split/split-provider/SplitProviderV0.sol/SplitProviderV0.json +141 -0
- package/contracts/AdminACLV0.sol +6 -2
- package/contracts/AdminACLV1.sol +2 -2
- package/contracts/DependencyRegistryV0.sol +687 -408
- package/contracts/{GenArt721CoreV3.sol → archive/GenArt721CoreV3.sol} +56 -20
- package/contracts/{explorations → archive}/GenArt721CoreV3_Explorations.sol +49 -13
- package/contracts/{minter-suite → archive/minter-suite}/Minters/MinterBase_v0_1_1.sol +4 -4
- package/contracts/{minter-suite/Minters → archive/minter-suite/Minters/MinterDAExp}/MinterDAExpV4.sol +4 -4
- package/contracts/archive/minter-suite/Minters/MinterDAExpSettlement/MinterDAExpSettlementV0.sol +4 -4
- package/contracts/archive/minter-suite/Minters/MinterDAExpSettlement/MinterDAExpSettlementV1.sol +5 -5
- package/contracts/{minter-suite/Minters → archive/minter-suite/Minters/MinterDAExpSettlement}/MinterDAExpSettlementV2.sol +8 -8
- package/contracts/{minter-suite/Minters → archive/minter-suite/Minters/MinterDALin}/MinterDALinV4.sol +4 -4
- package/contracts/{minter-suite/Minters → archive/minter-suite/Minters/MinterHolder}/MinterHolderV4.sol +5 -5
- package/contracts/{minter-suite/Minters → archive/minter-suite/Minters/MinterMerkle}/MinterMerkleV5.sol +5 -5
- package/contracts/{minter-suite/Minters → archive/minter-suite/Minters/MinterPolyptych}/MinterPolyptychV0.sol +7 -7
- package/contracts/{minter-suite/Minters → archive/minter-suite/Minters/MinterSEA}/MinterSEAV0.sol +13 -13
- package/contracts/{minter-suite/Minters → archive/minter-suite/Minters/MinterSetPrice}/MinterSetPriceV4.sol +4 -4
- package/contracts/archive/minter-suite/Minters/MinterSetPriceERC20/MinterSetPriceERC20V0.sol +82 -10
- package/contracts/archive/minter-suite/Minters/MinterSetPriceERC20/MinterSetPriceERC20V1.sol +82 -10
- package/contracts/{minter-suite/Minters → archive/minter-suite/Minters/MinterSetPriceERC20}/MinterSetPriceERC20V4.sol +88 -21
- package/contracts/engine/V2/GenArt721MinterBurner_PBAB.sol +81 -22
- package/contracts/engine/V2/GenArt721Minter_PBAB.sol +80 -22
- package/contracts/engine/V3/EngineFactoryV0.sol +419 -0
- package/contracts/engine/V3/GenArt721CoreV3_Engine.sol +894 -488
- package/contracts/engine/V3/GenArt721CoreV3_Engine_Flex.sol +1054 -650
- package/contracts/engine/V3/forks/GenArt721CoreV3_Engine_Flex_PROOF.sol +3 -3
- package/contracts/engine/V3/forks/PROHIBITION/GenArt721CoreV3_Engine_Flex_PROHIBITION.sol +1 -1
- package/contracts/engine/V3/forks/PROHIBITION/interfaces/IGenArt721CoreContractV3_Engine_Flex_PROHIBITION.sol +2 -2
- package/contracts/interfaces/v0.8.x/IAdminACLV0_Extended.sol +20 -0
- package/contracts/interfaces/v0.8.x/IBytecodeStorageReaderV2.sol +23 -0
- package/contracts/interfaces/v0.8.x/IDependencyRegistryV0.sol +47 -45
- package/contracts/interfaces/v0.8.x/IEngineFactoryV0.sol +124 -0
- package/contracts/interfaces/v0.8.x/IFilteredMinterDAExpSettlementV0.sol +1 -3
- package/contracts/interfaces/v0.8.x/IFilteredMinterDAExpSettlementV1.sol +1 -3
- package/contracts/interfaces/v0.8.x/IFilteredMinterDAExpV1.sol +1 -3
- package/contracts/interfaces/v0.8.x/IFilteredMinterDALinV1.sol +1 -3
- package/contracts/interfaces/v0.8.x/IFilteredMinterHolderV2.sol +1 -3
- package/contracts/interfaces/v0.8.x/IFilteredMinterMerkleV2.sol +1 -3
- package/contracts/interfaces/v0.8.x/IGenArt721CoreContractV3_Base.sol +115 -11
- package/contracts/interfaces/v0.8.x/IGenArt721CoreContractV3_Engine.sol +84 -8
- package/contracts/interfaces/v0.8.x/IGenArt721CoreContractV3_Engine_Flex.sol +26 -8
- package/contracts/interfaces/v0.8.x/IGenArt721CoreContractV3_Engine_Flex_PreV3p2.sol +141 -0
- package/contracts/interfaces/v0.8.x/IGenArt721CoreContractV3_Engine_PreV3p2.sol +78 -0
- package/contracts/interfaces/v0.8.x/IGenArt721CoreContractV3_ProjectFinance.sol +47 -0
- package/contracts/interfaces/v0.8.x/IGenArt721Minter_PBAB.sol +91 -0
- package/contracts/interfaces/v0.8.x/IPseudorandomAtomic.sol +1 -3
- package/contracts/interfaces/v0.8.x/ISharedMinterDAExpSettlementV0.sol +19 -0
- package/contracts/interfaces/v0.8.x/ISharedMinterRAMV0.sol +23 -0
- package/contracts/interfaces/v0.8.x/ISharedMinterRequired.sol +20 -0
- package/contracts/interfaces/v0.8.x/ISharedMinterSEAV0.sol +1 -4
- package/contracts/interfaces/v0.8.x/ISharedMinterV0.sol +12 -6
- package/contracts/interfaces/v0.8.x/ISplitAtomicFactoryV0.sol +81 -0
- package/contracts/interfaces/v0.8.x/ISplitAtomicV0.sol +72 -0
- package/contracts/interfaces/v0.8.x/ISplitProviderV0.sol +49 -0
- package/contracts/interfaces/v0.8.x/integration-refs/splits-0x-v2/ISplitFactoryV2.sol +62 -0
- package/contracts/libs/v0.8.x/ABHelpers.sol +18 -4
- package/contracts/libs/v0.8.x/BitMap.sol +112 -0
- package/contracts/libs/v0.8.x/BytecodeStorageV2.sol +593 -0
- package/contracts/libs/v0.8.x/DependencyRegistryStorageLib.sol +90 -0
- package/contracts/libs/v0.8.x/ERC721_PackedHashSeedV1.sol +591 -0
- package/contracts/libs/v0.8.x/PackedBools.sol +42 -0
- package/contracts/libs/v0.8.x/V3FlexLib.sol +591 -0
- package/contracts/libs/v0.8.x/minter-libs/DAExpLib.sol +10 -12
- package/contracts/libs/v0.8.x/minter-libs/DALinLib.sol +4 -9
- package/contracts/libs/v0.8.x/minter-libs/GenericMinterEventsLib.sol +44 -44
- package/contracts/libs/v0.8.x/minter-libs/MaxInvocationsLib.sol +64 -63
- package/contracts/libs/v0.8.x/minter-libs/MerkleLib.sol +14 -10
- package/contracts/libs/v0.8.x/minter-libs/RAMLib.sol +2927 -0
- package/contracts/libs/v0.8.x/minter-libs/SEALib.sol +60 -62
- package/contracts/libs/v0.8.x/minter-libs/SetPriceLib.sol +4 -8
- package/contracts/libs/v0.8.x/minter-libs/SettlementExpLib.sol +92 -89
- package/contracts/libs/v0.8.x/minter-libs/SplitFundsLib.sol +21 -15
- package/contracts/libs/v0.8.x/minter-libs/TokenHolderLib.sol +5 -4
- package/contracts/minter-suite/MinterFilter/MinterFilterV2.sol +16 -10
- package/contracts/minter-suite/Minters/MinterDAExpHolderV5.sol +2 -2
- package/contracts/minter-suite/Minters/MinterDAExpSettlementV3.sol +19 -15
- package/contracts/minter-suite/Minters/MinterDAExpV5.sol +2 -2
- package/contracts/minter-suite/Minters/MinterDALinHolderV5.sol +2 -2
- package/contracts/minter-suite/Minters/MinterDALinV5.sol +2 -2
- package/contracts/minter-suite/Minters/MinterRAMV0.sol +1205 -0
- package/contracts/minter-suite/Minters/MinterSEAV1.sol +21 -32
- package/contracts/minter-suite/Minters/MinterSetPriceERC20V5.sol +17 -8
- package/contracts/minter-suite/Minters/MinterSetPriceHolderV5.sol +2 -2
- package/contracts/minter-suite/Minters/MinterSetPriceMerkleV5.sol +2 -2
- package/contracts/minter-suite/Minters/MinterSetPricePolyptychERC20V5.sol +23 -9
- package/contracts/minter-suite/Minters/MinterSetPricePolyptychV5.sol +2 -2
- package/contracts/minter-suite/Minters/MinterSetPriceV5.sol +2 -2
- package/contracts/minter-suite/Minters/one-off/MinterSetPriceV5_SingleCore.sol +446 -0
- package/contracts/mock/BytecodeV2LibCallsMock.sol +128 -0
- package/contracts/mock/BytecodeV2TextCR_DMock.sol +316 -0
- package/contracts/mock/ForceSendMock.sol +22 -0
- package/contracts/mock/Mock0xSplitsV2PullFactory.sol +75 -0
- package/contracts/mock/Mock0xSplitsV2Splitter.sol +47 -0
- package/contracts/mock/MockAdminACLV0.sol +21 -0
- package/contracts/mock/MockAdminACLV0_PROHIBITION.sol +21 -0
- package/contracts/mock/ReentrancyGenArt721MinterMock.sol +47 -0
- package/contracts/mock/ReentrancySplitterMocks.sol +67 -0
- package/contracts/randomizer/primitive/PseudorandomAtomicBasic.sol +1 -1
- package/contracts/randomizer/shared/SharedRandomizerV0.sol +1 -1
- package/contracts/split/SplitAtomicFactoryV0.sol +121 -0
- package/contracts/split/SplitAtomicV0.sol +265 -0
- package/contracts/split/split-provider/SplitProviderV0.sol +201 -0
- package/package.json +62 -34
- package/artifacts/contracts/GenArt721CoreV3.sol/GenArt721CoreV3.json +0 -1965
- package/artifacts/contracts/explorations/GenArt721CoreV3_Explorations.sol/GenArt721CoreV3_Explorations.json +0 -1939
- package/artifacts/contracts/minter-suite/Minters/MinterSetPriceERC20V4.sol/MinterSetPriceERC20V4.json +0 -768
- package/artifacts/contracts/royalty-registry/GenArt721RoyaltyOverride.sol/GenArt721RoyaltyOverride.json +0 -208
- package/artifacts/contracts/royalty-registry/GenArt721RoyaltyOverride_PBAB.sol/GenArt721RoyaltyOverride_PBAB.json +0 -301
- package/contracts/archive/readme.md +0 -16
- package/contracts/engine/README.md +0 -21
- package/contracts/royalty-registry/GenArt721RoyaltyOverride.sol +0 -168
- package/contracts/royalty-registry/GenArt721RoyaltyOverride_PBAB.sol +0 -221
|
@@ -0,0 +1,2927 @@
|
|
|
1
|
+
// SPDX-License-Identifier: LGPL-3.0-only
|
|
2
|
+
// Created By: Art Blocks Inc.
|
|
3
|
+
|
|
4
|
+
pragma solidity ^0.8.0;
|
|
5
|
+
|
|
6
|
+
import {IMinterFilterV1} from "../../../interfaces/v0.8.x/IMinterFilterV1.sol";
|
|
7
|
+
|
|
8
|
+
import {BitMaps256} from "../BitMap.sol";
|
|
9
|
+
import {PackedBools} from "../PackedBools.sol";
|
|
10
|
+
import {ABHelpers} from "../ABHelpers.sol";
|
|
11
|
+
import {SplitFundsLib} from "./SplitFundsLib.sol";
|
|
12
|
+
import {MaxInvocationsLib} from "./MaxInvocationsLib.sol";
|
|
13
|
+
import {GenericMinterEventsLib} from "./GenericMinterEventsLib.sol";
|
|
14
|
+
|
|
15
|
+
import {IERC721} from "@openzeppelin-5.0/contracts/token/ERC721/IERC721.sol";
|
|
16
|
+
import {SafeCast} from "@openzeppelin-5.0/contracts/utils/math/SafeCast.sol";
|
|
17
|
+
import {Math} from "@openzeppelin-5.0/contracts/utils/math/Math.sol";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @title Art Blocks Ranked Auction Minter (RAM) Library
|
|
21
|
+
* @notice This library is designed for the Art Blocks platform. It includes
|
|
22
|
+
* Structs and functions that help with ranked auction minters.
|
|
23
|
+
* @author Art Blocks Inc.
|
|
24
|
+
*/
|
|
25
|
+
library RAMLib {
|
|
26
|
+
using SafeCast for uint256;
|
|
27
|
+
using BitMaps256 for uint256;
|
|
28
|
+
using PackedBools for uint256;
|
|
29
|
+
/**
|
|
30
|
+
* @notice Minimum auction length, in seconds, was updated to be the
|
|
31
|
+
* provided value.
|
|
32
|
+
* @param minAuctionDurationSeconds Minimum auction length, in seconds
|
|
33
|
+
*/
|
|
34
|
+
event MinAuctionDurationSecondsUpdated(uint256 minAuctionDurationSeconds);
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @notice Admin-controlled refund gas limit updated
|
|
38
|
+
* @param refundGasLimit Gas limit to use when refunding the previous
|
|
39
|
+
* highest bidder, prior to using fallback force-send to refund
|
|
40
|
+
*/
|
|
41
|
+
event MinterRefundGasLimitUpdated(uint24 refundGasLimit);
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @notice Number of slots used by this RAM minter
|
|
45
|
+
* @param numSlots Number of slots used by this RAM minter
|
|
46
|
+
*/
|
|
47
|
+
event NumSlotsUpdated(uint256 numSlots);
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @notice RAM auction buffer time parameters updated
|
|
51
|
+
* @param auctionBufferSeconds time period at end of auction when new bids
|
|
52
|
+
* can affect auction end time, updated to be this many seconds after the
|
|
53
|
+
* bid is placed.
|
|
54
|
+
* @param maxAuctionExtraSeconds maximum amount of time that can be added
|
|
55
|
+
* to the auction end time due to new bids.
|
|
56
|
+
*/
|
|
57
|
+
event AuctionBufferTimeParamsUpdated(
|
|
58
|
+
uint256 auctionBufferSeconds,
|
|
59
|
+
uint256 maxAuctionExtraSeconds
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @notice Admin minting constraint configuration updated
|
|
64
|
+
* @param coreContract Core contract address to update
|
|
65
|
+
* @param adminMintingConstraint enum representing admin minting constraint imposed on this contract
|
|
66
|
+
*/
|
|
67
|
+
event ContractConfigUpdated(
|
|
68
|
+
address indexed coreContract,
|
|
69
|
+
AdminMintingConstraint adminMintingConstraint
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @notice Auction parameters updated
|
|
74
|
+
* @param projectId Project Id to update
|
|
75
|
+
* @param coreContract Core contract address to update
|
|
76
|
+
* @param timestampStart Auction start timestamp
|
|
77
|
+
* @param timestampEnd Auction end timestamp
|
|
78
|
+
* @param basePrice Auction base price
|
|
79
|
+
* @param allowExtraTime Auction allows extra time
|
|
80
|
+
* @param adminArtistOnlyMintPeriodIfSellout Auction admin-artist-only mint period if
|
|
81
|
+
* sellout
|
|
82
|
+
* @param numTokensInAuction Number of tokens in auction
|
|
83
|
+
*/
|
|
84
|
+
event AuctionConfigUpdated(
|
|
85
|
+
uint256 indexed projectId,
|
|
86
|
+
address indexed coreContract,
|
|
87
|
+
uint256 timestampStart,
|
|
88
|
+
uint256 timestampEnd,
|
|
89
|
+
uint256 basePrice,
|
|
90
|
+
bool allowExtraTime,
|
|
91
|
+
bool adminArtistOnlyMintPeriodIfSellout,
|
|
92
|
+
uint256 numTokensInAuction
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* @notice Number of tokens in auction updated
|
|
97
|
+
* @dev okay to not index this event if prior to AuctionConfigUpdated, as
|
|
98
|
+
* the state value will be emitted in another future event
|
|
99
|
+
* @dev generic event not used due to additional indexing logic desired
|
|
100
|
+
* @param projectId Project Id to update
|
|
101
|
+
* @param coreContract Core contract address to update
|
|
102
|
+
* @param numTokensInAuction Number of tokens in auction
|
|
103
|
+
*/
|
|
104
|
+
event NumTokensInAuctionUpdated(
|
|
105
|
+
uint256 indexed projectId,
|
|
106
|
+
address indexed coreContract,
|
|
107
|
+
uint256 numTokensInAuction
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* @notice Auction timestamp end updated. Occurs when auction is extended
|
|
112
|
+
* due to new bids near the end of an auction, when the auction is
|
|
113
|
+
* configured to allow extra time.
|
|
114
|
+
* Also may occur when an admin extends the auction within the emergency
|
|
115
|
+
* extension time limit.
|
|
116
|
+
* @dev generic event not used due to additional indexing logic desired
|
|
117
|
+
* when event is encountered (want to understand what caused time
|
|
118
|
+
* extension)
|
|
119
|
+
* @param projectId Project Id to update
|
|
120
|
+
* @param coreContract Core contract address to update
|
|
121
|
+
* @param timestampEnd Auction end timestamp
|
|
122
|
+
*/
|
|
123
|
+
event AuctionTimestampEndUpdated(
|
|
124
|
+
uint256 indexed projectId,
|
|
125
|
+
address indexed coreContract,
|
|
126
|
+
uint256 timestampEnd
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* @notice Bid created in auction
|
|
131
|
+
* @param projectId Project Id to update
|
|
132
|
+
* @param coreContract Core contract address to update
|
|
133
|
+
* @param slotIndex Slot index of bid that was created
|
|
134
|
+
* @param bidId Bid Id that was created
|
|
135
|
+
* @param bidder Address of bidder
|
|
136
|
+
*/
|
|
137
|
+
event BidCreated(
|
|
138
|
+
uint256 indexed projectId,
|
|
139
|
+
address indexed coreContract,
|
|
140
|
+
uint256 slotIndex,
|
|
141
|
+
uint256 bidId,
|
|
142
|
+
address bidder
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* @notice Bid removed from auction because it was outbid.
|
|
147
|
+
* @param projectId Project Id to update
|
|
148
|
+
* @param coreContract Core contract address to update
|
|
149
|
+
* @param bidId Bid Id that was removed
|
|
150
|
+
*/
|
|
151
|
+
event BidRemoved(
|
|
152
|
+
uint256 indexed projectId,
|
|
153
|
+
address indexed coreContract,
|
|
154
|
+
uint256 bidId
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* @notice Bid topped up in auction
|
|
159
|
+
* @param projectId Project Id to update
|
|
160
|
+
* @param coreContract Core contract address to update
|
|
161
|
+
* @param bidId Bid Id that was topped up
|
|
162
|
+
* @param newSlotIndex New slot index of bid that was topped up
|
|
163
|
+
*/
|
|
164
|
+
event BidToppedUp(
|
|
165
|
+
uint256 indexed projectId,
|
|
166
|
+
address indexed coreContract,
|
|
167
|
+
uint256 bidId,
|
|
168
|
+
uint256 newSlotIndex
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* @notice Bid was settled, and any payment above the lowest winning bid,
|
|
173
|
+
* or base price if not a sellout, was refunded to the bidder.
|
|
174
|
+
* @param projectId Project Id to update
|
|
175
|
+
* @param coreContract Core contract address to update
|
|
176
|
+
* @param bidId ID of bid that was settled
|
|
177
|
+
*/
|
|
178
|
+
event BidSettled(
|
|
179
|
+
uint256 indexed projectId,
|
|
180
|
+
address indexed coreContract,
|
|
181
|
+
uint256 bidId
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* @notice A token was minted to the bidder for bid `bidId`. The tokenId is
|
|
186
|
+
* the token that was minted.
|
|
187
|
+
* @param projectId Project Id to update
|
|
188
|
+
* @param coreContract Core contract address to update
|
|
189
|
+
* @param bidId ID of bid that was settled
|
|
190
|
+
* @param tokenId Token Id that was minted
|
|
191
|
+
*
|
|
192
|
+
*/
|
|
193
|
+
event BidMinted(
|
|
194
|
+
uint256 indexed projectId,
|
|
195
|
+
address indexed coreContract,
|
|
196
|
+
uint256 bidId,
|
|
197
|
+
uint256 tokenId
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* @notice Bid was refunded, and the entire bid value was sent to the
|
|
202
|
+
* bidder.
|
|
203
|
+
* This only occurs if the minter encountered an unexpected error state
|
|
204
|
+
* due to operational issues, and the minter was unable to mint a token to
|
|
205
|
+
* the bidder.
|
|
206
|
+
* @param projectId Project Id to update
|
|
207
|
+
* @param coreContract Core contract address to update
|
|
208
|
+
* @param bidId ID of bid that was settled
|
|
209
|
+
*/
|
|
210
|
+
event BidRefunded(
|
|
211
|
+
uint256 indexed projectId,
|
|
212
|
+
address indexed coreContract,
|
|
213
|
+
uint256 bidId
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* @notice Token was directly purchased after an auction ended, and the
|
|
218
|
+
* token was minted to the buyer.
|
|
219
|
+
* @param projectId Project Id to update
|
|
220
|
+
* @param coreContract Core contract address to update
|
|
221
|
+
* @param tokenId Token Id that was minted
|
|
222
|
+
* @param to Address that the token was minted to
|
|
223
|
+
*/
|
|
224
|
+
event TokenPurchased(
|
|
225
|
+
uint256 indexed projectId,
|
|
226
|
+
address indexed coreContract,
|
|
227
|
+
uint256 tokenId,
|
|
228
|
+
address to
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
// position of RAM Lib storage, using a diamond storage pattern
|
|
232
|
+
// for this library
|
|
233
|
+
bytes32 constant RAM_LIB_STORAGE_POSITION = keccak256("ramlib.storage");
|
|
234
|
+
|
|
235
|
+
// generic event key constants
|
|
236
|
+
bytes32 internal constant CONFIG_AUCTION_REVENUES_COLLECTED =
|
|
237
|
+
"auctionRevenuesCollected";
|
|
238
|
+
bytes32 internal constant CONFIG_TIMESTAMP_END = "timestampEnd";
|
|
239
|
+
|
|
240
|
+
uint256 constant NUM_SLOTS = 512;
|
|
241
|
+
|
|
242
|
+
// pricing assumes maxPrice = minPrice * 2^8, pseudo-exponential curve
|
|
243
|
+
uint256 constant SLOTS_PER_PRICE_DOUBLE = NUM_SLOTS / 8; // 64 slots per double
|
|
244
|
+
|
|
245
|
+
// auction extension time constants
|
|
246
|
+
uint256 constant AUCTION_BUFFER_SECONDS = 5 minutes;
|
|
247
|
+
uint256 constant MAX_AUCTION_EXTRA_SECONDS = 1 hours;
|
|
248
|
+
// @dev store value in hours to improve storage packing
|
|
249
|
+
uint256 constant MAX_AUCTION_ADMIN_EMERGENCY_EXTENSION_HOURS = 72; // 72 hours
|
|
250
|
+
|
|
251
|
+
uint256 constant ADMIN_ARTIST_ONLY_MINT_TIME_SECONDS = 72 hours;
|
|
252
|
+
|
|
253
|
+
// packed bools constants for Bid struct
|
|
254
|
+
uint8 constant INDEX_IS_SETTLED = 0;
|
|
255
|
+
uint8 constant INDEX_IS_MINTED = 1;
|
|
256
|
+
uint8 constant INDEX_IS_REFUNDED = 2;
|
|
257
|
+
|
|
258
|
+
enum ProjectMinterStates {
|
|
259
|
+
PreAuction, // Pre-Auction, State A
|
|
260
|
+
LiveAuction, // Live-Auction, State B
|
|
261
|
+
PostAuctionSellOutAdminArtistMint, // Post-Auction, sell out, not all bids handled, admin-artist-only mint period, State C
|
|
262
|
+
PostAuctionOpenMint, // Post-Auction, not all bids handled, post-admin-artist-only mint period, State D
|
|
263
|
+
PostAuctionAllBidsHandled // Post-Auction, all bids handled, State E
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// project-specific parameters
|
|
267
|
+
struct RAMProjectConfig {
|
|
268
|
+
// mapping of all bids by Bid ID
|
|
269
|
+
mapping(uint256 bidId => Bid) bids;
|
|
270
|
+
// doubly linked list of bids for each slot
|
|
271
|
+
mapping(uint256 slot => uint256 headBidId) headBidIdBySlot;
|
|
272
|
+
mapping(uint256 slot => uint256 tailBidId) tailBidIdBySlot;
|
|
273
|
+
// --- slot metadata for efficiency ---
|
|
274
|
+
// two bitmaps with index set only if one or more active bids exist for
|
|
275
|
+
// the corresponding slot. The first bitmap (A) is for slots 0-255, the
|
|
276
|
+
// second bitmap (B) is for slots 256-511.
|
|
277
|
+
uint256 slotsBitmapA;
|
|
278
|
+
uint256 slotsBitmapB;
|
|
279
|
+
// minimum bitmap index with an active bid
|
|
280
|
+
// @dev set to 512 if no active bids
|
|
281
|
+
// @dev max uint16 >> max possible value of 512
|
|
282
|
+
uint16 minBidSlotIndex;
|
|
283
|
+
// maximum bitmap index with an active bid
|
|
284
|
+
// @dev set to 0 if no active bids
|
|
285
|
+
uint16 maxBidSlotIndex;
|
|
286
|
+
// --- bid auto-minting tracking ---
|
|
287
|
+
uint32 latestMintedBidId;
|
|
288
|
+
// --- error state bid auto-refund tracking ---
|
|
289
|
+
uint32 latestRefundedBidId;
|
|
290
|
+
// --- next bid ID ---
|
|
291
|
+
// nonce for generating new bid IDs on this project
|
|
292
|
+
// @dev allows for gt 4 billion bids, and max possible bids for a
|
|
293
|
+
// 1M token project is 1M * 512 slots = 512M bids < 4B max uint32
|
|
294
|
+
uint32 nextBidId;
|
|
295
|
+
// --- auction parameters ---
|
|
296
|
+
// number of tokens and related values
|
|
297
|
+
// @dev max uint24 is 16,777,215 > 1_000_000 max project size
|
|
298
|
+
uint24 numTokensInAuction;
|
|
299
|
+
uint24 numBids;
|
|
300
|
+
uint24 numBidsMintedTokens;
|
|
301
|
+
uint24 numBidsErrorRefunded;
|
|
302
|
+
// timing
|
|
303
|
+
// @dev max uint40 ~= 1.1e12 sec ~= 34 thousand years
|
|
304
|
+
uint40 timestampStart;
|
|
305
|
+
// @dev timestampOriginalEnd & timestampEnd are the same if not in extra time
|
|
306
|
+
uint40 timestampOriginalEnd;
|
|
307
|
+
uint40 timestampEnd;
|
|
308
|
+
// @dev max uint8 ~= 256 hours, which is gt max auction extension time of 72 hours
|
|
309
|
+
uint8 adminEmergencyExtensionHoursApplied;
|
|
310
|
+
bool allowExtraTime;
|
|
311
|
+
bool adminArtistOnlyMintPeriodIfSellout;
|
|
312
|
+
// pricing
|
|
313
|
+
// @dev max uint88 ~= 3e26 Wei = ~300 million ETH, which is well above
|
|
314
|
+
// the expected prices of any NFT mint in the foreseeable future.
|
|
315
|
+
uint88 basePrice;
|
|
316
|
+
// -- redundant backstops --
|
|
317
|
+
// Track per-project fund balance, in wei. This is used as a redundant
|
|
318
|
+
// backstop to prevent one project from draining the minter's balance
|
|
319
|
+
// of ETH from other projects, which is a worthwhile failsafe on this
|
|
320
|
+
// shared minter.
|
|
321
|
+
// @dev max uint120 > max basPrice * 256 * 1_000_000
|
|
322
|
+
// @dev while uint88 is gt max ETH supply, use uin120 to prevent reliance on
|
|
323
|
+
// max token supply
|
|
324
|
+
uint120 projectBalance;
|
|
325
|
+
// --- revenue collection state ---
|
|
326
|
+
bool revenuesCollected;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
struct Bid {
|
|
330
|
+
uint32 prevBidId;
|
|
331
|
+
uint32 nextBidId;
|
|
332
|
+
uint16 slotIndex;
|
|
333
|
+
address bidder;
|
|
334
|
+
// three bool values packed into a single uint8
|
|
335
|
+
// index 0 - isSettled (INDEX_IS_SETTLED)
|
|
336
|
+
// index 1 - isMinted (INDEX_IS_MINTED)
|
|
337
|
+
// index 2 - isRefunded (INDEX_IS_REFUNDED)
|
|
338
|
+
uint8 packedBools;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// contract-specific parameters
|
|
342
|
+
enum AdminMintingConstraint {
|
|
343
|
+
None,
|
|
344
|
+
AdminArtistOnlyMintPeriod,
|
|
345
|
+
NoAdminArtistOnlyMintPeriod
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Diamond storage pattern is used in this library
|
|
349
|
+
struct RAMLibStorage {
|
|
350
|
+
mapping(address coreContract => mapping(uint256 projectId => RAMProjectConfig)) RAMProjectConfigs;
|
|
351
|
+
mapping(address => AdminMintingConstraint) RAMAdminMintingConstraint;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* @notice Update a contract's requirements on if a post-auction
|
|
356
|
+
* admin-artist-only mint period is required or not, for and-on
|
|
357
|
+
* configured projects.
|
|
358
|
+
* @param coreContract The address of the core contract being configured
|
|
359
|
+
* @param adminMintingConstraint The AdminMintingConstraint setting for the contract
|
|
360
|
+
*/
|
|
361
|
+
function setContractConfig(
|
|
362
|
+
address coreContract,
|
|
363
|
+
AdminMintingConstraint adminMintingConstraint
|
|
364
|
+
) internal {
|
|
365
|
+
// set the contract admin minting constraint with the new constraint enum value
|
|
366
|
+
s().RAMAdminMintingConstraint[coreContract] = adminMintingConstraint;
|
|
367
|
+
// emit event
|
|
368
|
+
emit ContractConfigUpdated({
|
|
369
|
+
coreContract: coreContract,
|
|
370
|
+
adminMintingConstraint: adminMintingConstraint
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* @notice Function to add emergency auction hours to auction of
|
|
376
|
+
* project `projectId` on core contract `coreContract`.
|
|
377
|
+
* Protects against unexpected frontend downtime, etc.
|
|
378
|
+
* Reverts if called by anyone other than a contract admin.
|
|
379
|
+
* Reverts if project is not in a Live Auction.
|
|
380
|
+
* Reverts if auction is already in extra time.
|
|
381
|
+
* Reverts if adding more than the maximum number of emergency hours.
|
|
382
|
+
* @param projectId Project ID to add emergency auction hours to.
|
|
383
|
+
* @param coreContract Core contract address for the given project.
|
|
384
|
+
* @param emergencyHoursToAdd Number of emergency hours to add to the
|
|
385
|
+
* project's auction.
|
|
386
|
+
*/
|
|
387
|
+
function adminAddEmergencyAuctionHours(
|
|
388
|
+
uint256 projectId,
|
|
389
|
+
address coreContract,
|
|
390
|
+
uint8 emergencyHoursToAdd
|
|
391
|
+
) internal {
|
|
392
|
+
// load project config
|
|
393
|
+
RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({
|
|
394
|
+
projectId: projectId,
|
|
395
|
+
coreContract: coreContract
|
|
396
|
+
});
|
|
397
|
+
// CHECKS
|
|
398
|
+
// require auction in state B (Live Auction)
|
|
399
|
+
require(
|
|
400
|
+
getProjectMinterState(projectId, coreContract) ==
|
|
401
|
+
ProjectMinterStates.LiveAuction,
|
|
402
|
+
"Only live auction"
|
|
403
|
+
);
|
|
404
|
+
// require auction has not reached extra time
|
|
405
|
+
require(
|
|
406
|
+
RAMProjectConfig_.timestampOriginalEnd ==
|
|
407
|
+
RAMProjectConfig_.timestampEnd,
|
|
408
|
+
"Not allowed in extra time"
|
|
409
|
+
);
|
|
410
|
+
// require auction is not being extended beyond limit
|
|
411
|
+
uint8 newAdminEmergencyExtensionHours = RAMProjectConfig_
|
|
412
|
+
.adminEmergencyExtensionHoursApplied + emergencyHoursToAdd;
|
|
413
|
+
|
|
414
|
+
require(
|
|
415
|
+
newAdminEmergencyExtensionHours <=
|
|
416
|
+
MAX_AUCTION_ADMIN_EMERGENCY_EXTENSION_HOURS,
|
|
417
|
+
"Only emergency hours lt max"
|
|
418
|
+
);
|
|
419
|
+
// calculate auction end time
|
|
420
|
+
// @dev overflow automatically checked in solidity 0.8
|
|
421
|
+
uint40 newTimestampEnd = RAMProjectConfig_.timestampEnd +
|
|
422
|
+
emergencyHoursToAdd *
|
|
423
|
+
1 hours;
|
|
424
|
+
|
|
425
|
+
// EFFECTS
|
|
426
|
+
// update emergency hours applied
|
|
427
|
+
// @dev overflow automatically checked in solidity 0.8
|
|
428
|
+
RAMProjectConfig_
|
|
429
|
+
.adminEmergencyExtensionHoursApplied = newAdminEmergencyExtensionHours;
|
|
430
|
+
|
|
431
|
+
// update auction end time
|
|
432
|
+
// @dev update both original end timestamp and current end timestamp
|
|
433
|
+
// because this is not extra time, but rather an emergency extension
|
|
434
|
+
RAMProjectConfig_.timestampEnd = newTimestampEnd;
|
|
435
|
+
RAMProjectConfig_.timestampOriginalEnd = newTimestampEnd;
|
|
436
|
+
|
|
437
|
+
// emit event
|
|
438
|
+
emit AuctionTimestampEndUpdated({
|
|
439
|
+
projectId: projectId,
|
|
440
|
+
coreContract: coreContract,
|
|
441
|
+
timestampEnd: newTimestampEnd
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* @notice Function to set auction details on project `projectId` on core contract `coreContract`.
|
|
447
|
+
* Reverts if not currently in ProjectMinterState A.
|
|
448
|
+
* Reverts if base price does not meet the minimum.
|
|
449
|
+
* Reverts if not for future auction.
|
|
450
|
+
* Reverts if end time not greater than start time.
|
|
451
|
+
* Reverts if adminArtistOnlyMintPeriodIfSellout disagrees with the admin configured constraint.
|
|
452
|
+
* @param projectId Project ID to add emergency auction hours to.
|
|
453
|
+
* @param coreContract Core contract address for the given project.
|
|
454
|
+
* @param auctionTimestampStart New timestamp at which to start the auction.
|
|
455
|
+
* @param auctionTimestampEnd New timestamp at which to end the auction.
|
|
456
|
+
* @param basePrice Base price (or reserve price) of the auction, in Wei
|
|
457
|
+
* @param allowExtraTime Auction allows extra time
|
|
458
|
+
* @param adminArtistOnlyMintPeriodIfSellout Auction admin-artist-only mint period if
|
|
459
|
+
* sellout
|
|
460
|
+
*/
|
|
461
|
+
function setAuctionDetails(
|
|
462
|
+
uint256 projectId,
|
|
463
|
+
address coreContract,
|
|
464
|
+
uint40 auctionTimestampStart,
|
|
465
|
+
uint40 auctionTimestampEnd,
|
|
466
|
+
uint88 basePrice,
|
|
467
|
+
bool allowExtraTime,
|
|
468
|
+
bool adminArtistOnlyMintPeriodIfSellout
|
|
469
|
+
) internal {
|
|
470
|
+
// load project config
|
|
471
|
+
RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({
|
|
472
|
+
projectId: projectId,
|
|
473
|
+
coreContract: coreContract
|
|
474
|
+
});
|
|
475
|
+
// CHECKS
|
|
476
|
+
// require ProjectMinterState Pre-auction (State A)
|
|
477
|
+
require(
|
|
478
|
+
getProjectMinterState({
|
|
479
|
+
projectId: projectId,
|
|
480
|
+
coreContract: coreContract
|
|
481
|
+
}) == ProjectMinterStates.PreAuction,
|
|
482
|
+
"Only pre-auction"
|
|
483
|
+
);
|
|
484
|
+
// require base price >= 0.05 ETH
|
|
485
|
+
require(basePrice >= 0.05 ether, "Only base price gte 0.05 ETH");
|
|
486
|
+
// only future start time
|
|
487
|
+
require(
|
|
488
|
+
auctionTimestampStart > block.timestamp,
|
|
489
|
+
"Only future auctions"
|
|
490
|
+
);
|
|
491
|
+
|
|
492
|
+
// enforce contract-level constraints set by contract admin
|
|
493
|
+
AdminMintingConstraint RAMAdminMintingConstraint_ = getRAMAdminMintingConstraintValue({
|
|
494
|
+
coreContract: coreContract
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
if (
|
|
498
|
+
RAMAdminMintingConstraint_ ==
|
|
499
|
+
AdminMintingConstraint.AdminArtistOnlyMintPeriod
|
|
500
|
+
) {
|
|
501
|
+
require(
|
|
502
|
+
adminArtistOnlyMintPeriodIfSellout,
|
|
503
|
+
"Only admin-artist mint period"
|
|
504
|
+
);
|
|
505
|
+
} else if (
|
|
506
|
+
RAMAdminMintingConstraint_ ==
|
|
507
|
+
AdminMintingConstraint.NoAdminArtistOnlyMintPeriod
|
|
508
|
+
) {
|
|
509
|
+
require(
|
|
510
|
+
!adminArtistOnlyMintPeriodIfSellout,
|
|
511
|
+
"Only no admin-artist mint period"
|
|
512
|
+
);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// refresh max invocations to eliminate any stale state
|
|
516
|
+
MaxInvocationsLib.refreshMaxInvocations({
|
|
517
|
+
projectId: projectId,
|
|
518
|
+
coreContract: coreContract
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
// set auction details
|
|
522
|
+
RAMProjectConfig_.timestampStart = auctionTimestampStart;
|
|
523
|
+
RAMProjectConfig_.timestampEnd = auctionTimestampEnd;
|
|
524
|
+
RAMProjectConfig_.timestampOriginalEnd = auctionTimestampEnd;
|
|
525
|
+
RAMProjectConfig_.basePrice = basePrice;
|
|
526
|
+
RAMProjectConfig_.allowExtraTime = allowExtraTime;
|
|
527
|
+
RAMProjectConfig_
|
|
528
|
+
.adminArtistOnlyMintPeriodIfSellout = adminArtistOnlyMintPeriodIfSellout;
|
|
529
|
+
// refresh numTokensInAuction
|
|
530
|
+
uint256 numTokensInAuction = refreshNumTokensInAuction({
|
|
531
|
+
projectId: projectId,
|
|
532
|
+
coreContract: coreContract
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
// initialize min slot metadata to NUM_SLOTS (an invalid index) to represent NULL value
|
|
536
|
+
RAMProjectConfig_.minBidSlotIndex = uint16(NUM_SLOTS);
|
|
537
|
+
|
|
538
|
+
// emit state change event
|
|
539
|
+
emit AuctionConfigUpdated({
|
|
540
|
+
projectId: projectId,
|
|
541
|
+
coreContract: coreContract,
|
|
542
|
+
timestampStart: auctionTimestampStart,
|
|
543
|
+
timestampEnd: auctionTimestampEnd,
|
|
544
|
+
basePrice: basePrice,
|
|
545
|
+
allowExtraTime: allowExtraTime,
|
|
546
|
+
adminArtistOnlyMintPeriodIfSellout: adminArtistOnlyMintPeriodIfSellout,
|
|
547
|
+
numTokensInAuction: numTokensInAuction
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* @notice Reduces the auction length for project `projectId` on core
|
|
553
|
+
* contract `coreContract` to `auctionTimestampEnd`.
|
|
554
|
+
* Only allowed to be called during a live auction, and protects against
|
|
555
|
+
* the case of an accidental excessively long auction, which locks funds.
|
|
556
|
+
* Reverts if called by anyone other than the project's artist.
|
|
557
|
+
* Reverts if project is not in a Live Auction.
|
|
558
|
+
* Reverts if auction is not being reduced in length.
|
|
559
|
+
* Reverts if in extra time.
|
|
560
|
+
* Reverts if `auctionTimestampEnd` results in auction that is not at least
|
|
561
|
+
* `minimumAuctionDurationSeconds` in duration.
|
|
562
|
+
* Reverts if admin previously applied a time extension.
|
|
563
|
+
* @param projectId Project ID to reduce the auction length for.
|
|
564
|
+
* @param coreContract Core contract address for the given project.
|
|
565
|
+
* @param auctionTimestampEnd New timestamp at which to end the auction.
|
|
566
|
+
* @param minimumAuctionDurationSeconds Minimum auction duration, in seconds
|
|
567
|
+
*/
|
|
568
|
+
function reduceAuctionLength(
|
|
569
|
+
uint256 projectId,
|
|
570
|
+
address coreContract,
|
|
571
|
+
uint40 auctionTimestampEnd,
|
|
572
|
+
uint256 minimumAuctionDurationSeconds
|
|
573
|
+
) internal {
|
|
574
|
+
// load project config
|
|
575
|
+
RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({
|
|
576
|
+
projectId: projectId,
|
|
577
|
+
coreContract: coreContract
|
|
578
|
+
});
|
|
579
|
+
// CHECKS
|
|
580
|
+
// require auction state B, live auction
|
|
581
|
+
require(
|
|
582
|
+
getProjectMinterState(projectId, coreContract) ==
|
|
583
|
+
ProjectMinterStates.LiveAuction,
|
|
584
|
+
"Only live auction"
|
|
585
|
+
);
|
|
586
|
+
// require no previous admin extension time
|
|
587
|
+
require(
|
|
588
|
+
RAMProjectConfig_.adminEmergencyExtensionHoursApplied == 0,
|
|
589
|
+
"No previous admin extension"
|
|
590
|
+
);
|
|
591
|
+
// require not in extra time
|
|
592
|
+
require(
|
|
593
|
+
RAMProjectConfig_.timestampOriginalEnd ==
|
|
594
|
+
RAMProjectConfig_.timestampEnd,
|
|
595
|
+
"Not allowed in extra time"
|
|
596
|
+
);
|
|
597
|
+
// require reduction in auction length
|
|
598
|
+
require(
|
|
599
|
+
auctionTimestampEnd < RAMProjectConfig_.timestampEnd,
|
|
600
|
+
"Only reduce auction length"
|
|
601
|
+
);
|
|
602
|
+
// require meet minimum auction length requirement
|
|
603
|
+
require(
|
|
604
|
+
auctionTimestampEnd >
|
|
605
|
+
RAMProjectConfig_.timestampStart +
|
|
606
|
+
minimumAuctionDurationSeconds,
|
|
607
|
+
"Auction too short"
|
|
608
|
+
);
|
|
609
|
+
// require new end time in future
|
|
610
|
+
require(auctionTimestampEnd > block.timestamp, "Only future end time");
|
|
611
|
+
|
|
612
|
+
// set auction details
|
|
613
|
+
RAMProjectConfig_.timestampEnd = auctionTimestampEnd;
|
|
614
|
+
// also update original end for accurate extra time calculation
|
|
615
|
+
RAMProjectConfig_.timestampOriginalEnd = auctionTimestampEnd;
|
|
616
|
+
|
|
617
|
+
// emit state change event
|
|
618
|
+
emit AuctionTimestampEndUpdated({
|
|
619
|
+
projectId: projectId,
|
|
620
|
+
coreContract: coreContract,
|
|
621
|
+
timestampEnd: auctionTimestampEnd
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
/**
|
|
626
|
+
* @notice Update the number of tokens in the auction, based on the state
|
|
627
|
+
* of the core contract and the minter-local max invocations.
|
|
628
|
+
* @param projectId Project ID to update
|
|
629
|
+
* @param coreContract Core contract address to update
|
|
630
|
+
*/
|
|
631
|
+
function refreshNumTokensInAuction(
|
|
632
|
+
uint256 projectId,
|
|
633
|
+
address coreContract
|
|
634
|
+
) internal returns (uint256 numTokensInAuction) {
|
|
635
|
+
// load project config
|
|
636
|
+
RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({
|
|
637
|
+
projectId: projectId,
|
|
638
|
+
coreContract: coreContract
|
|
639
|
+
});
|
|
640
|
+
// @dev safe to cast - max uint24 is 16_777_215 > 1_000_000 max project size
|
|
641
|
+
numTokensInAuction = MaxInvocationsLib.getInvocationsAvailable({
|
|
642
|
+
projectId: projectId,
|
|
643
|
+
coreContract: coreContract
|
|
644
|
+
});
|
|
645
|
+
RAMProjectConfig_.numTokensInAuction = uint24(numTokensInAuction);
|
|
646
|
+
|
|
647
|
+
// emit event for state change
|
|
648
|
+
emit NumTokensInAuctionUpdated({
|
|
649
|
+
projectId: projectId,
|
|
650
|
+
coreContract: coreContract,
|
|
651
|
+
numTokensInAuction: numTokensInAuction
|
|
652
|
+
});
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
/**
|
|
656
|
+
* @notice Collects settlement for project `projectId` on core contract
|
|
657
|
+
* `coreContract` for all bids in `bidIds`.
|
|
658
|
+
* Reverts if project is not in a post-auction state.
|
|
659
|
+
* Reverts if bidder is not the bidder for all bids.
|
|
660
|
+
* Reverts if one or more bids has already been settled.
|
|
661
|
+
* Reverts if invalid bid is found.
|
|
662
|
+
* @param projectId Project ID of bid to collect settlement for
|
|
663
|
+
* @param coreContract Core contract address for the given project.
|
|
664
|
+
* @param bidIds IDs of bids to collect settlements for
|
|
665
|
+
* @param bidder Bidder address of bid to collect settlements for
|
|
666
|
+
* @param minterRefundGasLimit Gas limit to use when refunding the bidder.
|
|
667
|
+
*/
|
|
668
|
+
function collectSettlements(
|
|
669
|
+
uint256 projectId,
|
|
670
|
+
address coreContract,
|
|
671
|
+
uint32[] calldata bidIds,
|
|
672
|
+
address bidder,
|
|
673
|
+
uint256 minterRefundGasLimit
|
|
674
|
+
) internal {
|
|
675
|
+
// load project config
|
|
676
|
+
RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({
|
|
677
|
+
projectId: projectId,
|
|
678
|
+
coreContract: coreContract
|
|
679
|
+
});
|
|
680
|
+
// CHECKS
|
|
681
|
+
// @dev block scope to avoid stack too deep error
|
|
682
|
+
{
|
|
683
|
+
// require project minter state C or D (Post-Auction, Open Mint or Admin-Artist Mint Period)
|
|
684
|
+
ProjectMinterStates projectMinterState = getProjectMinterState({
|
|
685
|
+
projectId: projectId,
|
|
686
|
+
coreContract: coreContract
|
|
687
|
+
});
|
|
688
|
+
require(
|
|
689
|
+
projectMinterState ==
|
|
690
|
+
ProjectMinterStates.PostAuctionSellOutAdminArtistMint ||
|
|
691
|
+
projectMinterState ==
|
|
692
|
+
ProjectMinterStates.PostAuctionOpenMint,
|
|
693
|
+
"Only state C or D"
|
|
694
|
+
);
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
// get project price
|
|
698
|
+
uint256 projectPrice = _getProjectPrice({
|
|
699
|
+
RAMProjectConfig_: RAMProjectConfig_
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
// settle each input bid
|
|
703
|
+
// @dev already verified that input lengths match
|
|
704
|
+
uint256 inputBidsLength = bidIds.length;
|
|
705
|
+
// @dev overflow check optimization as of 0.8.22
|
|
706
|
+
for (uint256 i = 0; i < inputBidsLength; ++i) {
|
|
707
|
+
// settle the bid
|
|
708
|
+
_settleBidWithChecks({
|
|
709
|
+
RAMProjectConfig_: RAMProjectConfig_,
|
|
710
|
+
projectId: projectId,
|
|
711
|
+
coreContract: coreContract,
|
|
712
|
+
projectPrice: projectPrice,
|
|
713
|
+
bidId: bidIds[i],
|
|
714
|
+
bidder: bidder,
|
|
715
|
+
minterRefundGasLimit: minterRefundGasLimit
|
|
716
|
+
});
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
/**
|
|
721
|
+
* @notice Directly mint tokens to winners of project `projectId` on core
|
|
722
|
+
* contract `coreContract`.
|
|
723
|
+
* Does not guarantee an optimal ordering or handling of E1 state like
|
|
724
|
+
* `adminArtistAutoMintTokensToWinners` does while in State C.
|
|
725
|
+
* Skips over bids that have already been minted or refunded (front-running
|
|
726
|
+
* protection)
|
|
727
|
+
* Reverts if project is not in a post-auction state,
|
|
728
|
+
* post-admin-artist-only mint period (i.e. State D), with tokens available
|
|
729
|
+
* Reverts if bid does not exist at bidId.
|
|
730
|
+
* Reverts if msg.sender is not the bidder for all bids if
|
|
731
|
+
* requireSenderIsBidder is true.
|
|
732
|
+
* @param projectId Project ID to mint tokens on.
|
|
733
|
+
* @param coreContract Core contract address for the given project.
|
|
734
|
+
* @param bidIds IDs of bids to mint tokens for
|
|
735
|
+
* @param requireSenderIsBidder bool representing if the sender must be the
|
|
736
|
+
* bidder for all bids
|
|
737
|
+
* @param minterFilter Minter filter to use when minting tokens
|
|
738
|
+
* @param minterRefundGasLimit Gas limit to use when refunding the bidder.
|
|
739
|
+
*/
|
|
740
|
+
function directMintTokensToWinners(
|
|
741
|
+
uint256 projectId,
|
|
742
|
+
address coreContract,
|
|
743
|
+
uint32[] calldata bidIds,
|
|
744
|
+
bool requireSenderIsBidder,
|
|
745
|
+
IMinterFilterV1 minterFilter,
|
|
746
|
+
uint256 minterRefundGasLimit
|
|
747
|
+
) internal {
|
|
748
|
+
// load project config
|
|
749
|
+
RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({
|
|
750
|
+
projectId: projectId,
|
|
751
|
+
coreContract: coreContract
|
|
752
|
+
});
|
|
753
|
+
|
|
754
|
+
// get project price
|
|
755
|
+
uint256 projectPrice = _getProjectPrice({
|
|
756
|
+
RAMProjectConfig_: RAMProjectConfig_
|
|
757
|
+
});
|
|
758
|
+
|
|
759
|
+
// CHECKS
|
|
760
|
+
// @dev memoize length for gas efficiency
|
|
761
|
+
uint256 bidIdsLength = bidIds.length;
|
|
762
|
+
// @dev block scope to limit stack depth
|
|
763
|
+
{
|
|
764
|
+
// require project minter state D (Post-Auction,
|
|
765
|
+
// post-admin-artist-only, not all bids handled)
|
|
766
|
+
ProjectMinterStates projectMinterState = getProjectMinterState({
|
|
767
|
+
projectId: projectId,
|
|
768
|
+
coreContract: coreContract
|
|
769
|
+
});
|
|
770
|
+
require(
|
|
771
|
+
projectMinterState == ProjectMinterStates.PostAuctionOpenMint,
|
|
772
|
+
"Only post-auction open mint"
|
|
773
|
+
);
|
|
774
|
+
// require numTokensToMint does not exceed number of tokens
|
|
775
|
+
// owed.
|
|
776
|
+
// @dev must check this here to avoid minting more tokens than max
|
|
777
|
+
// invocations, which could potentially not revert if minter
|
|
778
|
+
// max invocations was limiting (+other unexpected conditions)
|
|
779
|
+
require(
|
|
780
|
+
bidIdsLength <=
|
|
781
|
+
_getNumTokensOwed({RAMProjectConfig_: RAMProjectConfig_}),
|
|
782
|
+
"tokens to mint gt tokens owed"
|
|
783
|
+
);
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
// main loop to mint tokens
|
|
787
|
+
for (uint256 i; i < bidIdsLength; ++i) {
|
|
788
|
+
// @dev current slot index and bid index in slot not memoized due
|
|
789
|
+
// to stack depth limitations
|
|
790
|
+
// get bid
|
|
791
|
+
uint256 currentBidId = bidIds[i];
|
|
792
|
+
Bid storage bid = RAMProjectConfig_.bids[currentBidId];
|
|
793
|
+
address bidderAddress = bid.bidder;
|
|
794
|
+
// CHECKS
|
|
795
|
+
// require bid exists
|
|
796
|
+
require(bidderAddress != address(0), "invalid Bid ID");
|
|
797
|
+
// if bid is already minted or refunded, skip to next bid
|
|
798
|
+
// @dev do not revert, since this could be due to front-running
|
|
799
|
+
if (
|
|
800
|
+
_getBidPackedBool(bid, INDEX_IS_MINTED) ||
|
|
801
|
+
_getBidPackedBool(bid, INDEX_IS_REFUNDED)
|
|
802
|
+
) {
|
|
803
|
+
continue;
|
|
804
|
+
}
|
|
805
|
+
// require sender is bidder if requireSenderIsBidder is true
|
|
806
|
+
if (requireSenderIsBidder) {
|
|
807
|
+
require(msg.sender == bidderAddress, "Only sender is bidder");
|
|
808
|
+
}
|
|
809
|
+
// EFFECTS
|
|
810
|
+
// @dev num bids minted tokens not memoized due to stack depth
|
|
811
|
+
// limitations
|
|
812
|
+
RAMProjectConfig_.numBidsMintedTokens++;
|
|
813
|
+
// Mint bid and settle if not already settled
|
|
814
|
+
_mintAndSettle({
|
|
815
|
+
projectId: projectId,
|
|
816
|
+
coreContract: coreContract,
|
|
817
|
+
projectPrice: projectPrice,
|
|
818
|
+
slotIndex: bid.slotIndex,
|
|
819
|
+
bidId: currentBidId,
|
|
820
|
+
minterFilter: minterFilter,
|
|
821
|
+
minterRefundGasLimit: minterRefundGasLimit
|
|
822
|
+
});
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
/**
|
|
827
|
+
* @notice Function that enables a contract admin or artist (checked by
|
|
828
|
+
* external function) to mint tokens to winners of project `projectId` on
|
|
829
|
+
* core contract `coreContract`.
|
|
830
|
+
* Automatically mints tokens to most-winning bids, in order from highest
|
|
831
|
+
* and earliest bid to lowest and latest bid.
|
|
832
|
+
* Settles bids as tokens are minted, if not already settled.
|
|
833
|
+
* Reverts if project is not in a post-auction state, admin-artist-only mint
|
|
834
|
+
* period (i.e. State C), with tokens available.
|
|
835
|
+
* to be minted.
|
|
836
|
+
* Reverts if number of tokens to mint is greater than the number of
|
|
837
|
+
* tokens available to be minted.
|
|
838
|
+
* @param projectId Project ID to mint tokens on.
|
|
839
|
+
* @param coreContract Core contract address for the given project.
|
|
840
|
+
* @param numTokensToMint Number of tokens to mint in this transaction.
|
|
841
|
+
* @param minterFilter Minter filter contract address
|
|
842
|
+
* @param minterRefundGasLimit Gas limit to use when settling bid if not already settled
|
|
843
|
+
*/
|
|
844
|
+
function adminArtistAutoMintTokensToWinners(
|
|
845
|
+
uint256 projectId,
|
|
846
|
+
address coreContract,
|
|
847
|
+
uint24 numTokensToMint,
|
|
848
|
+
IMinterFilterV1 minterFilter,
|
|
849
|
+
uint256 minterRefundGasLimit
|
|
850
|
+
) internal {
|
|
851
|
+
// load project config
|
|
852
|
+
RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({
|
|
853
|
+
projectId: projectId,
|
|
854
|
+
coreContract: coreContract
|
|
855
|
+
});
|
|
856
|
+
|
|
857
|
+
// get project price
|
|
858
|
+
uint256 projectPrice = _getProjectPrice({
|
|
859
|
+
RAMProjectConfig_: RAMProjectConfig_
|
|
860
|
+
});
|
|
861
|
+
|
|
862
|
+
// CHECKS
|
|
863
|
+
// @dev block scope to limit stack depth
|
|
864
|
+
{
|
|
865
|
+
// require project minter state C (Post-Auction, sell out, admin-artist-only,
|
|
866
|
+
// not all bids handled)
|
|
867
|
+
ProjectMinterStates projectMinterState = getProjectMinterState({
|
|
868
|
+
projectId: projectId,
|
|
869
|
+
coreContract: coreContract
|
|
870
|
+
});
|
|
871
|
+
require(
|
|
872
|
+
projectMinterState ==
|
|
873
|
+
ProjectMinterStates.PostAuctionSellOutAdminArtistMint,
|
|
874
|
+
"Only state C"
|
|
875
|
+
);
|
|
876
|
+
// require numTokensToMint does not exceed number of tokens
|
|
877
|
+
// owed
|
|
878
|
+
// @dev must check this here to avoid minting more tokens than max
|
|
879
|
+
// invocations, which could potentially not revert if minter
|
|
880
|
+
// max invocations was limiting (+other unexpected conditions)
|
|
881
|
+
require(
|
|
882
|
+
numTokensToMint <=
|
|
883
|
+
_getNumTokensOwed({RAMProjectConfig_: RAMProjectConfig_}),
|
|
884
|
+
"tokens to mint gt tokens owed"
|
|
885
|
+
);
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
// EFFECTS
|
|
889
|
+
// load values to memory for gas efficiency
|
|
890
|
+
uint256 currentLatestMintedBidId = RAMProjectConfig_.latestMintedBidId;
|
|
891
|
+
// @dev will be zero if no bids minted yet
|
|
892
|
+
uint256 currentLatestMintedBidSlotIndex = RAMProjectConfig_
|
|
893
|
+
.bids[currentLatestMintedBidId]
|
|
894
|
+
.slotIndex;
|
|
895
|
+
|
|
896
|
+
uint256 numNewTokensMinted; // = 0
|
|
897
|
+
|
|
898
|
+
// main loop to mint tokens
|
|
899
|
+
while (numNewTokensMinted < numTokensToMint) {
|
|
900
|
+
// EFFECTS
|
|
901
|
+
// STEP 1: scroll to next bid to be minted a token
|
|
902
|
+
// set latest minted bid indices to the bid to be minted a token
|
|
903
|
+
if (currentLatestMintedBidId == 0) {
|
|
904
|
+
// first mint, so need to initialize cursor values
|
|
905
|
+
// set bid to highest bid in the project, head of max bid slot
|
|
906
|
+
currentLatestMintedBidSlotIndex = RAMProjectConfig_
|
|
907
|
+
.maxBidSlotIndex;
|
|
908
|
+
currentLatestMintedBidId = RAMProjectConfig_.headBidIdBySlot[
|
|
909
|
+
currentLatestMintedBidSlotIndex
|
|
910
|
+
];
|
|
911
|
+
} else {
|
|
912
|
+
// scroll to next bid in current slot
|
|
913
|
+
// @dev scrolling to null is okay and handled below
|
|
914
|
+
currentLatestMintedBidId = RAMProjectConfig_
|
|
915
|
+
.bids[currentLatestMintedBidId]
|
|
916
|
+
.nextBidId;
|
|
917
|
+
// if scrolled off end of list, then find next slot with bids
|
|
918
|
+
if (currentLatestMintedBidId == 0) {
|
|
919
|
+
// past tail of current slot's linked list, so need to find next
|
|
920
|
+
// bid slot with bids
|
|
921
|
+
currentLatestMintedBidSlotIndex = _getMaxSlotWithBid({
|
|
922
|
+
RAMProjectConfig_: RAMProjectConfig_,
|
|
923
|
+
startSlotIndex: uint16(
|
|
924
|
+
currentLatestMintedBidSlotIndex - 1
|
|
925
|
+
)
|
|
926
|
+
});
|
|
927
|
+
// @dev no coverage on else branch because it is unreachable as used
|
|
928
|
+
require(
|
|
929
|
+
currentLatestMintedBidSlotIndex < NUM_SLOTS,
|
|
930
|
+
"slot with bid not found"
|
|
931
|
+
);
|
|
932
|
+
// current bid is now the head of the linked list
|
|
933
|
+
currentLatestMintedBidId = RAMProjectConfig_
|
|
934
|
+
.headBidIdBySlot[currentLatestMintedBidSlotIndex];
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
// @dev minter is in State C, so bid must not have been minted or
|
|
939
|
+
// refunded due to scrolling logic of admin mint and refund
|
|
940
|
+
// functions available for use while in State C. The bid may have
|
|
941
|
+
// been previously settled, however.
|
|
942
|
+
|
|
943
|
+
// Mint bid and settle if not already settled
|
|
944
|
+
// @dev scrolling logic in State C ensures bid **exists** is not yet minted
|
|
945
|
+
_mintAndSettle({
|
|
946
|
+
projectId: projectId,
|
|
947
|
+
coreContract: coreContract,
|
|
948
|
+
projectPrice: projectPrice,
|
|
949
|
+
slotIndex: currentLatestMintedBidSlotIndex,
|
|
950
|
+
bidId: currentLatestMintedBidId,
|
|
951
|
+
minterFilter: minterFilter,
|
|
952
|
+
minterRefundGasLimit: minterRefundGasLimit
|
|
953
|
+
});
|
|
954
|
+
|
|
955
|
+
// increment num new tokens minted
|
|
956
|
+
unchecked {
|
|
957
|
+
++numNewTokensMinted;
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
// finally, update auction metadata storage state from memoized values
|
|
962
|
+
// @dev safe to cast numNewTokensMinted to uint24
|
|
963
|
+
RAMProjectConfig_.numBidsMintedTokens += uint24(numNewTokensMinted);
|
|
964
|
+
// @dev safe to cast to uint32 because directly derived from bid ID
|
|
965
|
+
RAMProjectConfig_.latestMintedBidId = uint32(currentLatestMintedBidId);
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
/**
|
|
969
|
+
* @notice Directly refund bids for project `projectId` on core contract
|
|
970
|
+
* `coreContract` to resolve error state E1.
|
|
971
|
+
* Does not guarantee an optimal ordering or handling of E1 state like
|
|
972
|
+
* `autoRefundBidsToResolveE1` does while in State C.
|
|
973
|
+
* Skips over bids that have already been minted or refunded (front-running
|
|
974
|
+
* protection)
|
|
975
|
+
* Reverts if project is not in post-auction state,
|
|
976
|
+
* post-admin-artist-only mint period (i.e. State D).
|
|
977
|
+
* Reverts if project is not in error state E1.
|
|
978
|
+
* Reverts if length of bids to refund exceeds the number of bids that need
|
|
979
|
+
* to be refunded to resolve the error state E1.
|
|
980
|
+
* Reverts if bid does not exist at bidId.
|
|
981
|
+
* Reverts if msg.sender is not the bidder for all bids if
|
|
982
|
+
* requireSenderIsBidder is true.
|
|
983
|
+
* @param projectId Project ID to refunds bids for.
|
|
984
|
+
* @param coreContract Core contract address for the given project.
|
|
985
|
+
* @param bidIds IDs of bids to refund bid values for
|
|
986
|
+
* @param requireSenderIsBidder Require sender is bidder for all bids
|
|
987
|
+
* @param minterRefundGasLimit Gas limit to use when refunding the bidder.
|
|
988
|
+
*/
|
|
989
|
+
function directRefundBidsToResolveE1(
|
|
990
|
+
uint256 projectId,
|
|
991
|
+
address coreContract,
|
|
992
|
+
uint32[] calldata bidIds,
|
|
993
|
+
bool requireSenderIsBidder,
|
|
994
|
+
uint256 minterRefundGasLimit
|
|
995
|
+
) internal {
|
|
996
|
+
// CHECKS
|
|
997
|
+
// @dev memoize length for gas efficiency
|
|
998
|
+
uint256 bidIdsLength = bidIds.length;
|
|
999
|
+
// @dev block scope to limit stack depth
|
|
1000
|
+
{
|
|
1001
|
+
// require project minter state D (Post-Auction, post-admin-artist-only,
|
|
1002
|
+
// not all bids handled)
|
|
1003
|
+
ProjectMinterStates projectMinterState = getProjectMinterState({
|
|
1004
|
+
projectId: projectId,
|
|
1005
|
+
coreContract: coreContract
|
|
1006
|
+
});
|
|
1007
|
+
require(
|
|
1008
|
+
projectMinterState == ProjectMinterStates.PostAuctionOpenMint,
|
|
1009
|
+
"Only post-auction open mint"
|
|
1010
|
+
);
|
|
1011
|
+
// require is in state E1
|
|
1012
|
+
(bool isErrorE1_, uint256 numBidsToResolveE1, ) = isErrorE1FlagF1({
|
|
1013
|
+
projectId: projectId,
|
|
1014
|
+
coreContract: coreContract
|
|
1015
|
+
});
|
|
1016
|
+
require(isErrorE1_, "Only in state E1");
|
|
1017
|
+
// require numBidsToRefund does not exceed max number of bids
|
|
1018
|
+
// to resolve E1 error state
|
|
1019
|
+
require(
|
|
1020
|
+
bidIdsLength <= numBidsToResolveE1,
|
|
1021
|
+
"bids to refund gt available qty"
|
|
1022
|
+
);
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
// load project config
|
|
1026
|
+
RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({
|
|
1027
|
+
projectId: projectId,
|
|
1028
|
+
coreContract: coreContract
|
|
1029
|
+
});
|
|
1030
|
+
// get project price
|
|
1031
|
+
uint256 projectPrice = _getProjectPrice({
|
|
1032
|
+
RAMProjectConfig_: RAMProjectConfig_
|
|
1033
|
+
});
|
|
1034
|
+
|
|
1035
|
+
// @dev memoize for gas efficiency
|
|
1036
|
+
uint24 numRefundsIssued = 0;
|
|
1037
|
+
// main loop to refund tokens
|
|
1038
|
+
for (uint256 i; i < bidIdsLength; ++i) {
|
|
1039
|
+
// @dev current slot index and bid index in slot not memoized due
|
|
1040
|
+
// to stack depth limitations
|
|
1041
|
+
// get bid
|
|
1042
|
+
uint256 currentBidId = bidIds[i];
|
|
1043
|
+
Bid storage bid = RAMProjectConfig_.bids[currentBidId];
|
|
1044
|
+
// CHECKS
|
|
1045
|
+
// require bidder is non-zero address (i.e. bid exists)
|
|
1046
|
+
address bidderAddress = bid.bidder;
|
|
1047
|
+
require(bidderAddress != address(0), "invalid Bid ID");
|
|
1048
|
+
// if bid is already minted or refunded, skip to next bid
|
|
1049
|
+
// @dev do not revert, since this could be due to front-running
|
|
1050
|
+
if (
|
|
1051
|
+
_getBidPackedBool(bid, INDEX_IS_MINTED) ||
|
|
1052
|
+
_getBidPackedBool(bid, INDEX_IS_REFUNDED)
|
|
1053
|
+
) {
|
|
1054
|
+
continue;
|
|
1055
|
+
}
|
|
1056
|
+
// require sender is bidder if requireSenderIsBidder is true
|
|
1057
|
+
if (requireSenderIsBidder) {
|
|
1058
|
+
require(msg.sender == bidderAddress, "Only sender is bidder");
|
|
1059
|
+
}
|
|
1060
|
+
// EFFECTS
|
|
1061
|
+
// Settle and Refund the Bid
|
|
1062
|
+
_settleAndRefundBid({
|
|
1063
|
+
projectId: projectId,
|
|
1064
|
+
coreContract: coreContract,
|
|
1065
|
+
projectPrice: projectPrice,
|
|
1066
|
+
slotIndex: bid.slotIndex,
|
|
1067
|
+
bidId: currentBidId,
|
|
1068
|
+
minterRefundGasLimit: minterRefundGasLimit
|
|
1069
|
+
});
|
|
1070
|
+
numRefundsIssued++;
|
|
1071
|
+
}
|
|
1072
|
+
// update number of bids refunded
|
|
1073
|
+
RAMProjectConfig_.numBidsErrorRefunded += numRefundsIssued;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
/**
|
|
1077
|
+
* @notice Function to automatically refund the lowest winning bids for
|
|
1078
|
+
* project `projectId` on core contract `coreContract` to resolve error
|
|
1079
|
+
* state E1.
|
|
1080
|
+
* Reverts if project is not in post-auction state C.
|
|
1081
|
+
* Reverts if project is not in error state E1.
|
|
1082
|
+
* Reverts if numBidsToRefund exceeds the number of bids that need to be
|
|
1083
|
+
* refunded to resolve the error state E1.
|
|
1084
|
+
* @dev Recommend admin-only not for security, but rather to enable Admin
|
|
1085
|
+
* to be aware that an error state has been encountered while in post-
|
|
1086
|
+
* auction state C.
|
|
1087
|
+
* @param projectId Project ID to refunds bids for.
|
|
1088
|
+
* @param coreContract Core contract address for the given project.
|
|
1089
|
+
* @param numBidsToRefund Number of bids to refund in this call.
|
|
1090
|
+
* @param minterRefundGasLimit Gas limit to use when refunding the bidder.
|
|
1091
|
+
*/
|
|
1092
|
+
function autoRefundBidsToResolveE1(
|
|
1093
|
+
uint256 projectId,
|
|
1094
|
+
address coreContract,
|
|
1095
|
+
uint24 numBidsToRefund,
|
|
1096
|
+
uint256 minterRefundGasLimit
|
|
1097
|
+
) internal {
|
|
1098
|
+
// CHECKS
|
|
1099
|
+
// @dev block scope to limit stack depth
|
|
1100
|
+
{
|
|
1101
|
+
// require project minter state C (Post-Auction, admin-artist-only,
|
|
1102
|
+
// not all bids handled)
|
|
1103
|
+
ProjectMinterStates projectMinterState = getProjectMinterState({
|
|
1104
|
+
projectId: projectId,
|
|
1105
|
+
coreContract: coreContract
|
|
1106
|
+
});
|
|
1107
|
+
require(
|
|
1108
|
+
projectMinterState ==
|
|
1109
|
+
ProjectMinterStates.PostAuctionSellOutAdminArtistMint,
|
|
1110
|
+
"Only state C"
|
|
1111
|
+
);
|
|
1112
|
+
// require is in state E1
|
|
1113
|
+
(bool isErrorE1_, uint256 numBidsToResolveE1, ) = isErrorE1FlagF1({
|
|
1114
|
+
projectId: projectId,
|
|
1115
|
+
coreContract: coreContract
|
|
1116
|
+
});
|
|
1117
|
+
require(isErrorE1_, "Only in state E1");
|
|
1118
|
+
// require numBidsToRefund does not exceed max number of bids
|
|
1119
|
+
// to resolve E1 error state
|
|
1120
|
+
require(
|
|
1121
|
+
numBidsToRefund <= numBidsToResolveE1,
|
|
1122
|
+
"bids to refund gt available qty"
|
|
1123
|
+
);
|
|
1124
|
+
}
|
|
1125
|
+
// load project config
|
|
1126
|
+
RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({
|
|
1127
|
+
projectId: projectId,
|
|
1128
|
+
coreContract: coreContract
|
|
1129
|
+
});
|
|
1130
|
+
// get project price
|
|
1131
|
+
uint256 projectPrice = _getProjectPrice({
|
|
1132
|
+
RAMProjectConfig_: RAMProjectConfig_
|
|
1133
|
+
});
|
|
1134
|
+
|
|
1135
|
+
// EFFECTS
|
|
1136
|
+
// load values to memory for gas efficiency
|
|
1137
|
+
uint256 currentLatestRefundedBidId = RAMProjectConfig_
|
|
1138
|
+
.latestRefundedBidId;
|
|
1139
|
+
uint256 currentLatestRefundedBidSlotIndex = RAMProjectConfig_
|
|
1140
|
+
.bids[currentLatestRefundedBidId]
|
|
1141
|
+
.slotIndex;
|
|
1142
|
+
// settlement values
|
|
1143
|
+
uint256 numRefundsIssued; // = 0
|
|
1144
|
+
|
|
1145
|
+
// main loop to refund bids
|
|
1146
|
+
while (numRefundsIssued < numBidsToRefund) {
|
|
1147
|
+
// EFFECTS
|
|
1148
|
+
// STEP 1: Get next bid to be refunded
|
|
1149
|
+
// set latest refunded bid indices to the bid to be refunded
|
|
1150
|
+
if (currentLatestRefundedBidId == 0) {
|
|
1151
|
+
// first refund, so need to initialize cursor values
|
|
1152
|
+
// set bid to lowest bid in the project, tail of min bid slot
|
|
1153
|
+
currentLatestRefundedBidSlotIndex = RAMProjectConfig_
|
|
1154
|
+
.minBidSlotIndex;
|
|
1155
|
+
currentLatestRefundedBidId = RAMProjectConfig_.tailBidIdBySlot[
|
|
1156
|
+
currentLatestRefundedBidSlotIndex
|
|
1157
|
+
];
|
|
1158
|
+
} else {
|
|
1159
|
+
// scroll to previous bid in current slot
|
|
1160
|
+
// @dev scrolling to null is okay and handled below
|
|
1161
|
+
currentLatestRefundedBidId = RAMProjectConfig_
|
|
1162
|
+
.bids[currentLatestRefundedBidId]
|
|
1163
|
+
.prevBidId;
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
// if scrolled off end of list, then find next slot with bids
|
|
1167
|
+
if (currentLatestRefundedBidId == 0) {
|
|
1168
|
+
// past head of current slot's linked list, so need to find next
|
|
1169
|
+
// bid slot with bids
|
|
1170
|
+
// @dev not possible to not find next slot during auto-refund,
|
|
1171
|
+
// so no need to handle case where slot not found
|
|
1172
|
+
currentLatestRefundedBidSlotIndex = _getMinSlotWithBid({
|
|
1173
|
+
RAMProjectConfig_: RAMProjectConfig_,
|
|
1174
|
+
startSlotIndex: uint16(
|
|
1175
|
+
currentLatestRefundedBidSlotIndex + 1
|
|
1176
|
+
)
|
|
1177
|
+
});
|
|
1178
|
+
// current bid is now the tail of the linked list
|
|
1179
|
+
currentLatestRefundedBidId = RAMProjectConfig_.tailBidIdBySlot[
|
|
1180
|
+
currentLatestRefundedBidSlotIndex
|
|
1181
|
+
];
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
// @dev minter is in State C, so bid must not have been minted or
|
|
1185
|
+
// refunded due to scrolling logic of admin mint and refund
|
|
1186
|
+
// functions available for use while in State C. The bid may have
|
|
1187
|
+
// been previously settled, however.
|
|
1188
|
+
|
|
1189
|
+
// Settle & Refund the Bid
|
|
1190
|
+
_settleAndRefundBid({
|
|
1191
|
+
projectId: projectId,
|
|
1192
|
+
coreContract: coreContract,
|
|
1193
|
+
projectPrice: projectPrice,
|
|
1194
|
+
slotIndex: uint16(currentLatestRefundedBidSlotIndex),
|
|
1195
|
+
bidId: currentLatestRefundedBidId,
|
|
1196
|
+
minterRefundGasLimit: minterRefundGasLimit
|
|
1197
|
+
});
|
|
1198
|
+
// increment loop counter and current num bids refunded
|
|
1199
|
+
unchecked {
|
|
1200
|
+
++numRefundsIssued;
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
// finally, update auction metadata storage state from memoized values
|
|
1205
|
+
// @dev safe to cast currentNumBidsErrorRefunded to uint24
|
|
1206
|
+
RAMProjectConfig_.numBidsErrorRefunded += uint24(numRefundsIssued);
|
|
1207
|
+
// @dev safe to cast to uint32 because directly derived from bid ID
|
|
1208
|
+
RAMProjectConfig_.latestRefundedBidId = uint32(
|
|
1209
|
+
currentLatestRefundedBidId
|
|
1210
|
+
);
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
/**
|
|
1214
|
+
* @notice This withdraws project revenues for project `projectId` on core
|
|
1215
|
+
* contract `coreContract` to the artist and admin, only after all bids
|
|
1216
|
+
* have been minted+settled or refunded.
|
|
1217
|
+
* Note that the conditions described are the equivalent of project minter
|
|
1218
|
+
* State E.
|
|
1219
|
+
* @param projectId Project ID to withdraw revenues for.
|
|
1220
|
+
* @param coreContract Core contract address for the given project.
|
|
1221
|
+
*/
|
|
1222
|
+
function withdrawArtistAndAdminRevenues(
|
|
1223
|
+
uint256 projectId,
|
|
1224
|
+
address coreContract
|
|
1225
|
+
) internal {
|
|
1226
|
+
// load project config
|
|
1227
|
+
RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({
|
|
1228
|
+
projectId: projectId,
|
|
1229
|
+
coreContract: coreContract
|
|
1230
|
+
});
|
|
1231
|
+
|
|
1232
|
+
// CHECKS
|
|
1233
|
+
// require project minter state E (Post-Auction, all bids handled)
|
|
1234
|
+
ProjectMinterStates projectMinterState = getProjectMinterState({
|
|
1235
|
+
projectId: projectId,
|
|
1236
|
+
coreContract: coreContract
|
|
1237
|
+
});
|
|
1238
|
+
require(
|
|
1239
|
+
projectMinterState == ProjectMinterStates.PostAuctionAllBidsHandled,
|
|
1240
|
+
"Only state E"
|
|
1241
|
+
);
|
|
1242
|
+
// require revenues not already withdrawn
|
|
1243
|
+
require(
|
|
1244
|
+
!(RAMProjectConfig_.revenuesCollected),
|
|
1245
|
+
"Revenues already withdrawn"
|
|
1246
|
+
);
|
|
1247
|
+
|
|
1248
|
+
// EFFECTS
|
|
1249
|
+
// update state to indicate revenues withdrawn
|
|
1250
|
+
RAMProjectConfig_.revenuesCollected = true;
|
|
1251
|
+
|
|
1252
|
+
// get project price
|
|
1253
|
+
uint256 projectPrice = _getProjectPrice({
|
|
1254
|
+
RAMProjectConfig_: RAMProjectConfig_
|
|
1255
|
+
});
|
|
1256
|
+
// get netRevenues
|
|
1257
|
+
// @dev refunded bids do not count towards amount due because they
|
|
1258
|
+
// did not generate revenue
|
|
1259
|
+
uint256 netRevenues = projectPrice *
|
|
1260
|
+
RAMProjectConfig_.numBidsMintedTokens;
|
|
1261
|
+
|
|
1262
|
+
// update project balance
|
|
1263
|
+
// @dev reverts on underflow
|
|
1264
|
+
RAMProjectConfig_.projectBalance -= uint120(netRevenues);
|
|
1265
|
+
|
|
1266
|
+
// INTERACTIONS
|
|
1267
|
+
SplitFundsLib.splitRevenuesETHNoRefund({
|
|
1268
|
+
projectId: projectId,
|
|
1269
|
+
valueInWei: netRevenues,
|
|
1270
|
+
coreContract: coreContract
|
|
1271
|
+
});
|
|
1272
|
+
|
|
1273
|
+
emit GenericMinterEventsLib.ConfigValueSet({
|
|
1274
|
+
projectId: projectId,
|
|
1275
|
+
coreContract: coreContract,
|
|
1276
|
+
key: CONFIG_AUCTION_REVENUES_COLLECTED,
|
|
1277
|
+
value: true
|
|
1278
|
+
});
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
/**
|
|
1282
|
+
* @notice Function to mint tokens if an auction is over, but did not sell
|
|
1283
|
+
* out and tokens are still available to be minted.
|
|
1284
|
+
* @dev must be called within non-reentrant context
|
|
1285
|
+
* @param to Address to be the new token's owner.
|
|
1286
|
+
* @param projectId Project ID to mint a token on.
|
|
1287
|
+
* @param coreContract Core contract address for the given project.
|
|
1288
|
+
* @param minterFilter Minter filter to use when minting token.
|
|
1289
|
+
* @return tokenId Token ID of minted token
|
|
1290
|
+
*/
|
|
1291
|
+
function purchaseTo(
|
|
1292
|
+
address to,
|
|
1293
|
+
uint256 projectId,
|
|
1294
|
+
address coreContract,
|
|
1295
|
+
IMinterFilterV1 minterFilter
|
|
1296
|
+
) internal returns (uint256 tokenId) {
|
|
1297
|
+
// load project config
|
|
1298
|
+
RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({
|
|
1299
|
+
projectId: projectId,
|
|
1300
|
+
coreContract: coreContract
|
|
1301
|
+
});
|
|
1302
|
+
|
|
1303
|
+
// CHECKS
|
|
1304
|
+
// @dev block scope to limit stack depth
|
|
1305
|
+
{
|
|
1306
|
+
// require project minter state D, or E (Post-Auction)
|
|
1307
|
+
ProjectMinterStates projectMinterState = getProjectMinterState({
|
|
1308
|
+
projectId: projectId,
|
|
1309
|
+
coreContract: coreContract
|
|
1310
|
+
});
|
|
1311
|
+
require(
|
|
1312
|
+
projectMinterState == ProjectMinterStates.PostAuctionOpenMint ||
|
|
1313
|
+
projectMinterState ==
|
|
1314
|
+
ProjectMinterStates.PostAuctionAllBidsHandled,
|
|
1315
|
+
"Only state D or E"
|
|
1316
|
+
);
|
|
1317
|
+
// require Flag F1, i.e. at least one excess token available to be
|
|
1318
|
+
// minted
|
|
1319
|
+
// @dev this ensures minter and core contract max-invocations
|
|
1320
|
+
// constraints are not violated, as well as confirms that one
|
|
1321
|
+
// additional mint will not send the minter into an E1 state
|
|
1322
|
+
(, , uint256 numExcessInvocationsAvailable) = isErrorE1FlagF1({
|
|
1323
|
+
projectId: projectId,
|
|
1324
|
+
coreContract: coreContract
|
|
1325
|
+
});
|
|
1326
|
+
require(
|
|
1327
|
+
numExcessInvocationsAvailable > 0,
|
|
1328
|
+
"Reached max invocations"
|
|
1329
|
+
);
|
|
1330
|
+
}
|
|
1331
|
+
// require sufficient payment
|
|
1332
|
+
// since excess invocations are available, know not a sellout, so
|
|
1333
|
+
// project price is base price
|
|
1334
|
+
uint256 pricePerTokenInWei = RAMProjectConfig_.basePrice;
|
|
1335
|
+
require(
|
|
1336
|
+
msg.value == pricePerTokenInWei,
|
|
1337
|
+
"Only send auction reserve price"
|
|
1338
|
+
);
|
|
1339
|
+
|
|
1340
|
+
// EFFECTS
|
|
1341
|
+
// mint token
|
|
1342
|
+
tokenId = minterFilter.mint_joo({
|
|
1343
|
+
to: to,
|
|
1344
|
+
projectId: projectId,
|
|
1345
|
+
coreContract: coreContract,
|
|
1346
|
+
sender: msg.sender
|
|
1347
|
+
});
|
|
1348
|
+
|
|
1349
|
+
// @dev this minter specifically does not update max invocations has
|
|
1350
|
+
// been reached, since it must consider unminted bids when determining
|
|
1351
|
+
// if max invocations has been reached
|
|
1352
|
+
|
|
1353
|
+
// INTERACTIONS
|
|
1354
|
+
// split revenue from sale
|
|
1355
|
+
// @dev no refund because previously verified msg.value == pricePerTokenInWei
|
|
1356
|
+
// @dev no effect on project balance, splitting same amount received
|
|
1357
|
+
SplitFundsLib.splitRevenuesETHNoRefund({
|
|
1358
|
+
projectId: projectId,
|
|
1359
|
+
valueInWei: pricePerTokenInWei,
|
|
1360
|
+
coreContract: coreContract
|
|
1361
|
+
});
|
|
1362
|
+
|
|
1363
|
+
// emit event for state change
|
|
1364
|
+
emit TokenPurchased({
|
|
1365
|
+
projectId: projectId,
|
|
1366
|
+
coreContract: coreContract,
|
|
1367
|
+
tokenId: tokenId,
|
|
1368
|
+
to: to
|
|
1369
|
+
});
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
/**
|
|
1373
|
+
* @notice Place a new bid for a project.
|
|
1374
|
+
* Assumes check that minter is set for project on minter filter has
|
|
1375
|
+
* already been performed.
|
|
1376
|
+
* Reverts if project is not in state B (Live Auction).
|
|
1377
|
+
* Reverts if bid value is not equal to the slot value.
|
|
1378
|
+
* @param projectId Project Id to place bid for
|
|
1379
|
+
* @param coreContract Core contract address to place bid for
|
|
1380
|
+
* @param slotIndex Slot index to place bid at
|
|
1381
|
+
* @param bidder Bidder address
|
|
1382
|
+
* @param bidValue Bid value, in Wei (verified to align with slotIndex)
|
|
1383
|
+
* @param minterRefundGasLimit Gas limit to use when refunding the previous
|
|
1384
|
+
* highest bidder, prior to using fallback force-send to refund
|
|
1385
|
+
*/
|
|
1386
|
+
function placeBid(
|
|
1387
|
+
uint256 projectId,
|
|
1388
|
+
address coreContract,
|
|
1389
|
+
uint16 slotIndex,
|
|
1390
|
+
address bidder,
|
|
1391
|
+
uint256 bidValue,
|
|
1392
|
+
uint256 minterRefundGasLimit
|
|
1393
|
+
) internal {
|
|
1394
|
+
// load project config
|
|
1395
|
+
RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({
|
|
1396
|
+
projectId: projectId,
|
|
1397
|
+
coreContract: coreContract
|
|
1398
|
+
});
|
|
1399
|
+
// CHECKS
|
|
1400
|
+
// require project minter state B (Live Auction)
|
|
1401
|
+
require(
|
|
1402
|
+
getProjectMinterState(projectId, coreContract) ==
|
|
1403
|
+
ProjectMinterStates.LiveAuction,
|
|
1404
|
+
"Only live auction"
|
|
1405
|
+
);
|
|
1406
|
+
// require slot index not out of range
|
|
1407
|
+
// @dev slot index out of range is checked in slotIndexToBidValue
|
|
1408
|
+
// require bid value must equal slot value
|
|
1409
|
+
uint256 newBidRequiredValue = slotIndexToBidValue({
|
|
1410
|
+
basePrice: RAMProjectConfig_.basePrice,
|
|
1411
|
+
slotIndex: slotIndex
|
|
1412
|
+
});
|
|
1413
|
+
require(
|
|
1414
|
+
bidValue == newBidRequiredValue,
|
|
1415
|
+
"msg.value must equal slot value"
|
|
1416
|
+
);
|
|
1417
|
+
|
|
1418
|
+
// EFFECTS
|
|
1419
|
+
// add bid value to project balance
|
|
1420
|
+
RAMProjectConfig_.projectBalance += uint120(bidValue);
|
|
1421
|
+
// if first bid, refresh max invocations in case artist has reduced
|
|
1422
|
+
// the core contract's max invocations after the auction was configured
|
|
1423
|
+
// @dev this helps prevent E1 error state
|
|
1424
|
+
if (RAMProjectConfig_.numBids == 0) {
|
|
1425
|
+
// refresh max invocations
|
|
1426
|
+
MaxInvocationsLib.refreshMaxInvocations({
|
|
1427
|
+
projectId: projectId,
|
|
1428
|
+
coreContract: coreContract
|
|
1429
|
+
});
|
|
1430
|
+
// also refresh numTokensInAuction for RAM project config
|
|
1431
|
+
refreshNumTokensInAuction({
|
|
1432
|
+
projectId: projectId,
|
|
1433
|
+
coreContract: coreContract
|
|
1434
|
+
});
|
|
1435
|
+
}
|
|
1436
|
+
// require at least one token allowed in auction
|
|
1437
|
+
// @dev this case would revert in _removeMinBid, but prefer clean error
|
|
1438
|
+
// message here
|
|
1439
|
+
uint256 numTokensInAuction = RAMProjectConfig_.numTokensInAuction;
|
|
1440
|
+
require(numTokensInAuction > 0, "No tokens in auction");
|
|
1441
|
+
// determine if have reached max bids
|
|
1442
|
+
bool reachedMaxBids = RAMProjectConfig_.numBids >= numTokensInAuction;
|
|
1443
|
+
if (reachedMaxBids) {
|
|
1444
|
+
// remove + refund the minimum Bid
|
|
1445
|
+
uint256 removedBidValue = _removeMinBid({
|
|
1446
|
+
RAMProjectConfig_: RAMProjectConfig_,
|
|
1447
|
+
projectId: projectId,
|
|
1448
|
+
coreContract: coreContract,
|
|
1449
|
+
minterRefundGasLimit: minterRefundGasLimit
|
|
1450
|
+
});
|
|
1451
|
+
// require new bid is sufficiently greater than removed minimum bid
|
|
1452
|
+
require(
|
|
1453
|
+
_isSufficientOutbid({
|
|
1454
|
+
oldBidValue: removedBidValue,
|
|
1455
|
+
newBidValue: bidValue
|
|
1456
|
+
}),
|
|
1457
|
+
"Insufficient bid value"
|
|
1458
|
+
);
|
|
1459
|
+
|
|
1460
|
+
// apply auction extension time if needed
|
|
1461
|
+
bool timeExtensionNeeded = RAMProjectConfig_.allowExtraTime &&
|
|
1462
|
+
block.timestamp >
|
|
1463
|
+
RAMProjectConfig_.timestampEnd - AUCTION_BUFFER_SECONDS;
|
|
1464
|
+
if (timeExtensionNeeded) {
|
|
1465
|
+
// extend auction end time to no longer than
|
|
1466
|
+
// MAX_AUCTION_EXTRA_SECONDS after original end time
|
|
1467
|
+
RAMProjectConfig_.timestampEnd = uint40(
|
|
1468
|
+
Math.min(
|
|
1469
|
+
RAMProjectConfig_.timestampOriginalEnd +
|
|
1470
|
+
MAX_AUCTION_EXTRA_SECONDS,
|
|
1471
|
+
block.timestamp + AUCTION_BUFFER_SECONDS
|
|
1472
|
+
)
|
|
1473
|
+
);
|
|
1474
|
+
emit AuctionTimestampEndUpdated({
|
|
1475
|
+
projectId: projectId,
|
|
1476
|
+
coreContract: coreContract,
|
|
1477
|
+
timestampEnd: RAMProjectConfig_.timestampEnd
|
|
1478
|
+
});
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
// insert the new Bid
|
|
1482
|
+
_insertBid({
|
|
1483
|
+
RAMProjectConfig_: RAMProjectConfig_,
|
|
1484
|
+
projectId: projectId,
|
|
1485
|
+
coreContract: coreContract,
|
|
1486
|
+
slotIndex: slotIndex,
|
|
1487
|
+
bidder: bidder,
|
|
1488
|
+
bidId: 0 // zero triggers new bid ID to be assigned
|
|
1489
|
+
});
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
/**
|
|
1493
|
+
* @notice Top up bid for project `projectId` on core contract
|
|
1494
|
+
* `coreContract` for bid `bidId` to new slot index `newSlotIndex`.
|
|
1495
|
+
* Reverts if Bid ID has been kicked out of the auction or does not exist.
|
|
1496
|
+
* Reverts if bidder is not the bidder of the bid.
|
|
1497
|
+
* Reverts if project is not in a Live Auction.
|
|
1498
|
+
* Reverts if addedValue is not equal to difference in bid values between
|
|
1499
|
+
* new and old slots.
|
|
1500
|
+
* Reverts if new slot index is not greater than or equal to the current
|
|
1501
|
+
* slot index.
|
|
1502
|
+
* @param projectId Project ID to top up bid for.
|
|
1503
|
+
* @param coreContract Core contract address for the given project.
|
|
1504
|
+
* @param bidId ID of bid to top up.
|
|
1505
|
+
* @param newSlotIndex New slot index to move bid to.
|
|
1506
|
+
* @param bidder Bidder address
|
|
1507
|
+
* @param addedValue Value to add to the bid, in Wei
|
|
1508
|
+
*/
|
|
1509
|
+
function topUpBid(
|
|
1510
|
+
uint256 projectId,
|
|
1511
|
+
address coreContract,
|
|
1512
|
+
uint32 bidId,
|
|
1513
|
+
uint16 newSlotIndex,
|
|
1514
|
+
address bidder,
|
|
1515
|
+
uint256 addedValue
|
|
1516
|
+
) internal {
|
|
1517
|
+
// load project config
|
|
1518
|
+
RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({
|
|
1519
|
+
projectId: projectId,
|
|
1520
|
+
coreContract: coreContract
|
|
1521
|
+
});
|
|
1522
|
+
Bid storage bid = RAMProjectConfig_.bids[bidId];
|
|
1523
|
+
// memoize for gas efficiency
|
|
1524
|
+
uint16 oldSlotIndex = bid.slotIndex;
|
|
1525
|
+
// CHECKS
|
|
1526
|
+
{
|
|
1527
|
+
// require project minter state B (Live Auction)
|
|
1528
|
+
require(
|
|
1529
|
+
getProjectMinterState(projectId, coreContract) ==
|
|
1530
|
+
ProjectMinterStates.LiveAuction,
|
|
1531
|
+
"Only live auction"
|
|
1532
|
+
);
|
|
1533
|
+
// require new slot index not out of range
|
|
1534
|
+
// @dev slot index out of range is checked in slotIndexToBidValue
|
|
1535
|
+
// @dev give clean error message if bid is null or deleted
|
|
1536
|
+
require(bid.bidder != address(0), "Bid dne - were you outbid?");
|
|
1537
|
+
// require bidder owns referenced bid
|
|
1538
|
+
require(bid.bidder == bidder, "Only bidder of existing bid");
|
|
1539
|
+
// require correct added bid value
|
|
1540
|
+
uint256 oldBidValue = slotIndexToBidValue({
|
|
1541
|
+
basePrice: RAMProjectConfig_.basePrice,
|
|
1542
|
+
slotIndex: oldSlotIndex
|
|
1543
|
+
});
|
|
1544
|
+
uint256 newBidValue = slotIndexToBidValue({
|
|
1545
|
+
basePrice: RAMProjectConfig_.basePrice,
|
|
1546
|
+
slotIndex: newSlotIndex
|
|
1547
|
+
});
|
|
1548
|
+
// implicitly checks that newSlotIndex > oldSlotIndex, since
|
|
1549
|
+
// addedValue must be positive
|
|
1550
|
+
require(
|
|
1551
|
+
oldBidValue + addedValue == newBidValue,
|
|
1552
|
+
"incorrect added value"
|
|
1553
|
+
);
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
// EFFECTS
|
|
1557
|
+
// add the added value to project balance
|
|
1558
|
+
RAMProjectConfig_.projectBalance += uint120(addedValue);
|
|
1559
|
+
// eject bid from the linked list at oldSlotIndex
|
|
1560
|
+
_ejectBidFromSlot({
|
|
1561
|
+
RAMProjectConfig_: RAMProjectConfig_,
|
|
1562
|
+
slotIndex: oldSlotIndex,
|
|
1563
|
+
bidId: bidId
|
|
1564
|
+
});
|
|
1565
|
+
// insert the existing bid into newSlotIndex's linked list
|
|
1566
|
+
_insertBid({
|
|
1567
|
+
RAMProjectConfig_: RAMProjectConfig_,
|
|
1568
|
+
projectId: projectId,
|
|
1569
|
+
coreContract: coreContract,
|
|
1570
|
+
slotIndex: newSlotIndex,
|
|
1571
|
+
bidder: bidder,
|
|
1572
|
+
bidId: bidId
|
|
1573
|
+
});
|
|
1574
|
+
|
|
1575
|
+
// emit top-up event
|
|
1576
|
+
emit BidToppedUp({
|
|
1577
|
+
projectId: projectId,
|
|
1578
|
+
coreContract: coreContract,
|
|
1579
|
+
bidId: bidId,
|
|
1580
|
+
newSlotIndex: newSlotIndex
|
|
1581
|
+
});
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
/**
|
|
1585
|
+
* @notice Returns a storage pointer to the Bid struct and slot index of the lowest bid in the
|
|
1586
|
+
* project's auction, in Wei.
|
|
1587
|
+
* Reverts if no bids exist in the auction.
|
|
1588
|
+
* @param projectId Project ID to get the lowest bid value for
|
|
1589
|
+
* @param coreContract Core contract address for the given project
|
|
1590
|
+
* @return minBid Storage pointer to Bid struct of the lowest bid in
|
|
1591
|
+
* the auction
|
|
1592
|
+
* @return minSlotIndex Slot index of the lowest bid in the auction
|
|
1593
|
+
*/
|
|
1594
|
+
function getLowestBid(
|
|
1595
|
+
uint256 projectId,
|
|
1596
|
+
address coreContract
|
|
1597
|
+
) internal view returns (Bid storage minBid, uint16 minSlotIndex) {
|
|
1598
|
+
RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({
|
|
1599
|
+
projectId: projectId,
|
|
1600
|
+
coreContract: coreContract
|
|
1601
|
+
});
|
|
1602
|
+
// revert if no bids in auction
|
|
1603
|
+
require(RAMProjectConfig_.numBids > 0, "No bids in auction");
|
|
1604
|
+
// get min slot with a bid
|
|
1605
|
+
minSlotIndex = RAMProjectConfig_.minBidSlotIndex;
|
|
1606
|
+
// get the tail bid ID for the min slot
|
|
1607
|
+
uint256 tailBidId = RAMProjectConfig_.tailBidIdBySlot[minSlotIndex];
|
|
1608
|
+
minBid = RAMProjectConfig_.bids[tailBidId];
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1611
|
+
/**
|
|
1612
|
+
* @notice Returns the auction details for project `projectId` on core
|
|
1613
|
+
* contract `coreContract`.
|
|
1614
|
+
* @param projectId is an existing project ID.
|
|
1615
|
+
* @param coreContract is an existing core contract address.
|
|
1616
|
+
* @return auctionTimestampStart is the timestamp at which the auction
|
|
1617
|
+
* starts.
|
|
1618
|
+
* @return auctionTimestampEnd is the timestamp at which the auction ends.
|
|
1619
|
+
* @return basePrice is the resting price of the auction, in Wei.
|
|
1620
|
+
* @return numTokensInAuction is the number of tokens in the auction.
|
|
1621
|
+
* @return numBids is the number of bids in the auction.
|
|
1622
|
+
* @return numBidsMintedTokens is the number of bids that have been minted
|
|
1623
|
+
* into tokens.
|
|
1624
|
+
* @return numBidsErrorRefunded is the number of bids that have been
|
|
1625
|
+
* refunded due to an error state.
|
|
1626
|
+
* @return minBidSlotIndex is the index of the slot with the minimum bid
|
|
1627
|
+
* value.
|
|
1628
|
+
* @return allowExtraTime is a bool indicating if the auction is allowed to
|
|
1629
|
+
* have extra time.
|
|
1630
|
+
* @return adminArtistOnlyMintPeriodIfSellout is a bool indicating if an
|
|
1631
|
+
* admin-artist-only mint period is required if the auction sells out.
|
|
1632
|
+
* @return revenuesCollected is a bool indicating if the auction revenues
|
|
1633
|
+
* have been collected.
|
|
1634
|
+
* @return projectMinterState is the current state of the project minter.
|
|
1635
|
+
* @dev projectMinterState is a RAMLib.ProjectMinterStates enum value.
|
|
1636
|
+
*/
|
|
1637
|
+
function getAuctionDetails(
|
|
1638
|
+
uint256 projectId,
|
|
1639
|
+
address coreContract
|
|
1640
|
+
)
|
|
1641
|
+
internal
|
|
1642
|
+
view
|
|
1643
|
+
returns (
|
|
1644
|
+
uint256 auctionTimestampStart,
|
|
1645
|
+
uint256 auctionTimestampEnd,
|
|
1646
|
+
uint256 basePrice,
|
|
1647
|
+
uint256 numTokensInAuction,
|
|
1648
|
+
uint256 numBids,
|
|
1649
|
+
uint256 numBidsMintedTokens,
|
|
1650
|
+
uint256 numBidsErrorRefunded,
|
|
1651
|
+
uint256 minBidSlotIndex,
|
|
1652
|
+
bool allowExtraTime,
|
|
1653
|
+
bool adminArtistOnlyMintPeriodIfSellout,
|
|
1654
|
+
bool revenuesCollected,
|
|
1655
|
+
RAMLib.ProjectMinterStates projectMinterState
|
|
1656
|
+
)
|
|
1657
|
+
{
|
|
1658
|
+
// asign project minter state
|
|
1659
|
+
projectMinterState = getProjectMinterState({
|
|
1660
|
+
projectId: projectId,
|
|
1661
|
+
coreContract: coreContract
|
|
1662
|
+
});
|
|
1663
|
+
// get project config
|
|
1664
|
+
RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({
|
|
1665
|
+
projectId: projectId,
|
|
1666
|
+
coreContract: coreContract
|
|
1667
|
+
});
|
|
1668
|
+
// get auction details
|
|
1669
|
+
auctionTimestampStart = RAMProjectConfig_.timestampStart;
|
|
1670
|
+
auctionTimestampEnd = RAMProjectConfig_.timestampEnd;
|
|
1671
|
+
basePrice = RAMProjectConfig_.basePrice;
|
|
1672
|
+
numTokensInAuction = RAMProjectConfig_.numTokensInAuction;
|
|
1673
|
+
numBids = RAMProjectConfig_.numBids;
|
|
1674
|
+
numBidsMintedTokens = RAMProjectConfig_.numBidsMintedTokens;
|
|
1675
|
+
numBidsErrorRefunded = RAMProjectConfig_.numBidsErrorRefunded;
|
|
1676
|
+
minBidSlotIndex = RAMProjectConfig_.minBidSlotIndex;
|
|
1677
|
+
allowExtraTime = RAMProjectConfig_.allowExtraTime;
|
|
1678
|
+
adminArtistOnlyMintPeriodIfSellout = RAMProjectConfig_
|
|
1679
|
+
.adminArtistOnlyMintPeriodIfSellout;
|
|
1680
|
+
revenuesCollected = RAMProjectConfig_.revenuesCollected;
|
|
1681
|
+
}
|
|
1682
|
+
|
|
1683
|
+
/**
|
|
1684
|
+
* @notice Returns the price information for a given project.
|
|
1685
|
+
* If an auction is not configured, `isConfigured` will be false, and a
|
|
1686
|
+
* dummy price of zero is assigned to `tokenPriceInWei`.
|
|
1687
|
+
* If an auction is configured but still in a pre-auction state,
|
|
1688
|
+
* `isConfigured` will be true, and `tokenPriceInWei` will be the minimum
|
|
1689
|
+
* initial bid price for the next token auction.
|
|
1690
|
+
* If there is an active auction, `isConfigured` will be true, and
|
|
1691
|
+
* `tokenPriceInWei` will be the current minimum bid's value + min bid
|
|
1692
|
+
* increment due to the minter's increment percentage, rounded up to next
|
|
1693
|
+
* slot's bid value.
|
|
1694
|
+
* If there is an auction that has ended (no longer accepting bids), but
|
|
1695
|
+
* the project is configured, `isConfigured` will be true, and
|
|
1696
|
+
* `tokenPriceInWei` will be either the sellout price or the reserve price
|
|
1697
|
+
* of the auction if it did not sell out during its auction.
|
|
1698
|
+
* @param projectId Project ID to get price information for
|
|
1699
|
+
* @param coreContract Core contract address for the given project
|
|
1700
|
+
* @return isConfigured True if the project is configured, false otherwise
|
|
1701
|
+
* @return tokenPriceInWei Price of a token in Wei, if configured
|
|
1702
|
+
*/
|
|
1703
|
+
function getPriceInfo(
|
|
1704
|
+
uint256 projectId,
|
|
1705
|
+
address coreContract
|
|
1706
|
+
) internal view returns (bool isConfigured, uint256 tokenPriceInWei) {
|
|
1707
|
+
// get minter state
|
|
1708
|
+
RAMLib.ProjectMinterStates projectMinterState = getProjectMinterState({
|
|
1709
|
+
projectId: projectId,
|
|
1710
|
+
coreContract: coreContract
|
|
1711
|
+
});
|
|
1712
|
+
// load project config
|
|
1713
|
+
RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({
|
|
1714
|
+
projectId: projectId,
|
|
1715
|
+
coreContract: coreContract
|
|
1716
|
+
});
|
|
1717
|
+
// handle pre-auction State A
|
|
1718
|
+
if (projectMinterState == RAMLib.ProjectMinterStates.PreAuction) {
|
|
1719
|
+
isConfigured = RAMProjectConfig_.timestampStart > 0;
|
|
1720
|
+
// if not configured, leave tokenPriceInWei as 0
|
|
1721
|
+
if (isConfigured) {
|
|
1722
|
+
tokenPriceInWei = RAMProjectConfig_.basePrice;
|
|
1723
|
+
}
|
|
1724
|
+
} else {
|
|
1725
|
+
// values that apply to all live-auction and post-auction states
|
|
1726
|
+
isConfigured = true;
|
|
1727
|
+
bool isSellout = RAMProjectConfig_.numBids >=
|
|
1728
|
+
RAMProjectConfig_.numTokensInAuction;
|
|
1729
|
+
|
|
1730
|
+
// handle live-auction State B
|
|
1731
|
+
if (projectMinterState == RAMLib.ProjectMinterStates.LiveAuction) {
|
|
1732
|
+
if (isSellout) {
|
|
1733
|
+
// find next valid bid value
|
|
1734
|
+
// @dev okay if we extend past the maximum slot index value
|
|
1735
|
+
// for this view function
|
|
1736
|
+
(, tokenPriceInWei) = _findNextValidBidSlotIndexAndValue({
|
|
1737
|
+
projectId: projectId,
|
|
1738
|
+
coreContract: coreContract,
|
|
1739
|
+
startSlotIndex: RAMProjectConfig_.minBidSlotIndex
|
|
1740
|
+
});
|
|
1741
|
+
} else {
|
|
1742
|
+
// not sellout, so min bid is base price
|
|
1743
|
+
tokenPriceInWei = RAMProjectConfig_.basePrice;
|
|
1744
|
+
}
|
|
1745
|
+
} else {
|
|
1746
|
+
// handle post-auction States C, D, E
|
|
1747
|
+
if (isSellout) {
|
|
1748
|
+
// if sellout, return min bid price
|
|
1749
|
+
tokenPriceInWei = slotIndexToBidValue({
|
|
1750
|
+
basePrice: RAMProjectConfig_.basePrice,
|
|
1751
|
+
slotIndex: RAMProjectConfig_.minBidSlotIndex
|
|
1752
|
+
});
|
|
1753
|
+
} else {
|
|
1754
|
+
// not sellout, so return base price
|
|
1755
|
+
tokenPriceInWei = RAMProjectConfig_.basePrice;
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
/**
|
|
1762
|
+
* @notice Gets minimum next bid value in Wei and slot index for project `projectId`
|
|
1763
|
+
* on core contract `coreContract`.
|
|
1764
|
+
* If in a pre-auction state, reverts if unconfigured, otherwise returns
|
|
1765
|
+
* the minimum initial bid price for the upcoming auction.
|
|
1766
|
+
* If in an active auction, returns the minimum next bid's value and slot
|
|
1767
|
+
* index.
|
|
1768
|
+
* If in a post-auction state, reverts if auction was a sellout, otherwise
|
|
1769
|
+
* returns the auction's reserve price and slot index 0 (because tokens may
|
|
1770
|
+
* still be purchasable at the reserve price).
|
|
1771
|
+
* @param projectId Project ID to get the minimum next bid value for
|
|
1772
|
+
* @param coreContract Core contract address for the given project
|
|
1773
|
+
* @return minNextBidValueInWei minimum next bid value in Wei
|
|
1774
|
+
* @return minNextBidSlotIndex slot index of the minimum next bid
|
|
1775
|
+
*/
|
|
1776
|
+
function getMinimumNextBid(
|
|
1777
|
+
uint256 projectId,
|
|
1778
|
+
address coreContract
|
|
1779
|
+
)
|
|
1780
|
+
internal
|
|
1781
|
+
view
|
|
1782
|
+
returns (uint256 minNextBidValueInWei, uint256 minNextBidSlotIndex)
|
|
1783
|
+
{
|
|
1784
|
+
// get minter state
|
|
1785
|
+
RAMLib.ProjectMinterStates projectMinterState = getProjectMinterState({
|
|
1786
|
+
projectId: projectId,
|
|
1787
|
+
coreContract: coreContract
|
|
1788
|
+
});
|
|
1789
|
+
// load project config
|
|
1790
|
+
RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({
|
|
1791
|
+
projectId: projectId,
|
|
1792
|
+
coreContract: coreContract
|
|
1793
|
+
});
|
|
1794
|
+
// handle pre-auction State A
|
|
1795
|
+
if (projectMinterState == RAMLib.ProjectMinterStates.PreAuction) {
|
|
1796
|
+
bool isConfigured = RAMProjectConfig_.timestampStart > 0;
|
|
1797
|
+
if (!isConfigured) {
|
|
1798
|
+
// if not configured, revert
|
|
1799
|
+
revert("auction not configured");
|
|
1800
|
+
}
|
|
1801
|
+
// if configured, min next bid is base price at slot 0
|
|
1802
|
+
minNextBidValueInWei = RAMProjectConfig_.basePrice;
|
|
1803
|
+
minNextBidSlotIndex = 0;
|
|
1804
|
+
} else {
|
|
1805
|
+
// values that apply to all live-auction and post-auction states
|
|
1806
|
+
bool isSellout = RAMProjectConfig_.numBids >=
|
|
1807
|
+
RAMProjectConfig_.numTokensInAuction;
|
|
1808
|
+
|
|
1809
|
+
// handle live-auction State B
|
|
1810
|
+
if (projectMinterState == RAMLib.ProjectMinterStates.LiveAuction) {
|
|
1811
|
+
if (isSellout) {
|
|
1812
|
+
// find next valid bid slot index and value
|
|
1813
|
+
// @dev okay if we extend past the maximum slot index and value
|
|
1814
|
+
// for this view function
|
|
1815
|
+
(
|
|
1816
|
+
minNextBidSlotIndex,
|
|
1817
|
+
minNextBidValueInWei
|
|
1818
|
+
) = _findNextValidBidSlotIndexAndValue({
|
|
1819
|
+
projectId: projectId,
|
|
1820
|
+
coreContract: coreContract,
|
|
1821
|
+
startSlotIndex: RAMProjectConfig_.minBidSlotIndex
|
|
1822
|
+
});
|
|
1823
|
+
} else {
|
|
1824
|
+
// not sellout, so min bid is base price
|
|
1825
|
+
minNextBidValueInWei = RAMProjectConfig_.basePrice;
|
|
1826
|
+
minNextBidSlotIndex = 0;
|
|
1827
|
+
}
|
|
1828
|
+
} else {
|
|
1829
|
+
// handle post-auction States C, D, E
|
|
1830
|
+
if (isSellout) {
|
|
1831
|
+
// if sellout, revert
|
|
1832
|
+
revert("auction ended, sellout");
|
|
1833
|
+
} else {
|
|
1834
|
+
// not sellout, so return base price
|
|
1835
|
+
minNextBidValueInWei = RAMProjectConfig_.basePrice;
|
|
1836
|
+
minNextBidSlotIndex = 0;
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
/**
|
|
1843
|
+
* @notice Gets the project minter state of project `projectId` on core
|
|
1844
|
+
* contract `coreContract`.
|
|
1845
|
+
* @param projectId Project ID to get the minimum next bid value for
|
|
1846
|
+
* @param coreContract Core contract address for the given project
|
|
1847
|
+
* @return ProjectMinterStates enum representing the minter state.
|
|
1848
|
+
*/
|
|
1849
|
+
function getProjectMinterState(
|
|
1850
|
+
uint256 projectId,
|
|
1851
|
+
address coreContract
|
|
1852
|
+
) internal view returns (ProjectMinterStates) {
|
|
1853
|
+
RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({
|
|
1854
|
+
projectId: projectId,
|
|
1855
|
+
coreContract: coreContract
|
|
1856
|
+
});
|
|
1857
|
+
// State A: Pre-Auction
|
|
1858
|
+
// @dev load to memory for gas efficiency
|
|
1859
|
+
uint256 timestampStart = RAMProjectConfig_.timestampStart;
|
|
1860
|
+
// helper value(s) for readability
|
|
1861
|
+
bool auctionIsConfigured = timestampStart > 0;
|
|
1862
|
+
bool isPreAuction = block.timestamp < timestampStart;
|
|
1863
|
+
// confirm that auction is either not configured or is pre-auction
|
|
1864
|
+
if ((!auctionIsConfigured) || isPreAuction) {
|
|
1865
|
+
return ProjectMinterStates.PreAuction;
|
|
1866
|
+
}
|
|
1867
|
+
// State B: Live-Auction
|
|
1868
|
+
// @dev auction is configured due to previous State A return
|
|
1869
|
+
// helper value(s) for readability
|
|
1870
|
+
// @dev load to memory for gas efficiency
|
|
1871
|
+
uint256 timestampEnd = RAMProjectConfig_.timestampEnd;
|
|
1872
|
+
bool isPostAuction = block.timestamp > timestampEnd;
|
|
1873
|
+
// pre-auction is checked above
|
|
1874
|
+
if (!isPostAuction) {
|
|
1875
|
+
return ProjectMinterStates.LiveAuction;
|
|
1876
|
+
}
|
|
1877
|
+
// States C, D, E: Post-Auction
|
|
1878
|
+
// @dev auction is configured and post auction due to previous States A, B returns
|
|
1879
|
+
// all winners sent tokens means all bids have either been minted tokens or refunded if error state occurred
|
|
1880
|
+
bool allBidsHandled = RAMProjectConfig_.numBidsMintedTokens +
|
|
1881
|
+
RAMProjectConfig_.numBidsErrorRefunded ==
|
|
1882
|
+
RAMProjectConfig_.numBids;
|
|
1883
|
+
if (allBidsHandled) {
|
|
1884
|
+
// State E: Post-Auction, all bids handled
|
|
1885
|
+
return ProjectMinterStates.PostAuctionAllBidsHandled;
|
|
1886
|
+
}
|
|
1887
|
+
// @dev all bids are not handled due to previous State E return
|
|
1888
|
+
bool adminOnlyMintPeriod = RAMProjectConfig_
|
|
1889
|
+
// @dev if project is configured to have an admin-artist-only mint period
|
|
1890
|
+
.adminArtistOnlyMintPeriodIfSellout &&
|
|
1891
|
+
// @dev sellout if numBids >= numTokensInAuction
|
|
1892
|
+
RAMProjectConfig_.numBids >= RAMProjectConfig_.numTokensInAuction &&
|
|
1893
|
+
// @dev still in admin-artist-only mint period if current time < end time + admin-artist-only mint period
|
|
1894
|
+
block.timestamp <
|
|
1895
|
+
timestampEnd + ADMIN_ARTIST_ONLY_MINT_TIME_SECONDS;
|
|
1896
|
+
if (adminOnlyMintPeriod) {
|
|
1897
|
+
// State C: Post-Auction, sell out, not all bids handled, admin-artist-only mint period
|
|
1898
|
+
return ProjectMinterStates.PostAuctionSellOutAdminArtistMint;
|
|
1899
|
+
}
|
|
1900
|
+
// State D: Post-Auction, not all bids handled, post-admin-artist-only mint period
|
|
1901
|
+
// @dev states are mutually exclusive, so must be in final remaining state
|
|
1902
|
+
return ProjectMinterStates.PostAuctionOpenMint;
|
|
1903
|
+
}
|
|
1904
|
+
|
|
1905
|
+
/**
|
|
1906
|
+
* @notice Returns if project minter is in ERROR state E1, and the number
|
|
1907
|
+
* of bids that need to be refunded to resolve the error. Also returns the
|
|
1908
|
+
* number of excess invocations available, if any, indicating Flag F1.
|
|
1909
|
+
* E1: Tokens owed > invocations available
|
|
1910
|
+
* Occurs when: tokens are minted on different minter after auction begins,
|
|
1911
|
+
* or when core contract max invocations are reduced after auction begins.
|
|
1912
|
+
* Resolution: Admin must refund the lowest bids after auction ends.
|
|
1913
|
+
* @param projectId Project Id to query
|
|
1914
|
+
* @param coreContract Core contract address to query
|
|
1915
|
+
* @return isError True if in error state, false otherwise
|
|
1916
|
+
* @return numBidsToRefund Number of bids to refund to resolve error, 0 if
|
|
1917
|
+
* not in error state
|
|
1918
|
+
* @return numExcessInvocationsAvailable Number of excess invocations
|
|
1919
|
+
* available. Value above 0 indicates Flag F1.
|
|
1920
|
+
*/
|
|
1921
|
+
function isErrorE1FlagF1(
|
|
1922
|
+
uint256 projectId,
|
|
1923
|
+
address coreContract
|
|
1924
|
+
)
|
|
1925
|
+
internal
|
|
1926
|
+
view
|
|
1927
|
+
returns (
|
|
1928
|
+
bool isError,
|
|
1929
|
+
uint256 numBidsToRefund,
|
|
1930
|
+
uint256 numExcessInvocationsAvailable
|
|
1931
|
+
)
|
|
1932
|
+
{
|
|
1933
|
+
// get project config
|
|
1934
|
+
RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({
|
|
1935
|
+
projectId: projectId,
|
|
1936
|
+
coreContract: coreContract
|
|
1937
|
+
});
|
|
1938
|
+
// E1: Tokens owed > invocations available
|
|
1939
|
+
uint256 tokensOwed = _getNumTokensOwed({
|
|
1940
|
+
RAMProjectConfig_: RAMProjectConfig_
|
|
1941
|
+
});
|
|
1942
|
+
uint256 invocationsAvailable = MaxInvocationsLib
|
|
1943
|
+
.getInvocationsAvailable({
|
|
1944
|
+
projectId: projectId,
|
|
1945
|
+
coreContract: coreContract
|
|
1946
|
+
});
|
|
1947
|
+
// populate return values
|
|
1948
|
+
isError = tokensOwed > invocationsAvailable;
|
|
1949
|
+
numBidsToRefund = isError ? tokensOwed - invocationsAvailable : 0;
|
|
1950
|
+
// no excess invocations available if in error state, otherwise is the
|
|
1951
|
+
// difference between invocations available and tokens owed
|
|
1952
|
+
numExcessInvocationsAvailable = isError
|
|
1953
|
+
? 0
|
|
1954
|
+
: invocationsAvailable - tokensOwed;
|
|
1955
|
+
}
|
|
1956
|
+
|
|
1957
|
+
/**
|
|
1958
|
+
* @notice Returns the MaxInvocationsProjectConfig for a given project and
|
|
1959
|
+
* core contract, properly accounting for the auction state, unminted bids,
|
|
1960
|
+
* core contract invocations, and minter max invocations when determining
|
|
1961
|
+
* maxHasBeenInvoked
|
|
1962
|
+
* @param projectId Project Id to get config for
|
|
1963
|
+
* @param coreContract Core contract address to get config for
|
|
1964
|
+
* @return maxInvocationsProjectConfig max invocations project configuration
|
|
1965
|
+
*/
|
|
1966
|
+
function getMaxInvocationsProjectConfig(
|
|
1967
|
+
uint256 projectId,
|
|
1968
|
+
address coreContract
|
|
1969
|
+
)
|
|
1970
|
+
internal
|
|
1971
|
+
view
|
|
1972
|
+
returns (
|
|
1973
|
+
MaxInvocationsLib.MaxInvocationsProjectConfig
|
|
1974
|
+
memory maxInvocationsProjectConfig
|
|
1975
|
+
)
|
|
1976
|
+
{
|
|
1977
|
+
// get max invocations project config from MaxInvocationsLib
|
|
1978
|
+
maxInvocationsProjectConfig.maxInvocations = uint24(
|
|
1979
|
+
MaxInvocationsLib.getMaxInvocations({
|
|
1980
|
+
projectId: projectId,
|
|
1981
|
+
coreContract: coreContract
|
|
1982
|
+
})
|
|
1983
|
+
);
|
|
1984
|
+
maxInvocationsProjectConfig.maxHasBeenInvoked = getMaxHasBeenInvoked({
|
|
1985
|
+
projectId: projectId,
|
|
1986
|
+
coreContract: coreContract
|
|
1987
|
+
});
|
|
1988
|
+
}
|
|
1989
|
+
|
|
1990
|
+
/**
|
|
1991
|
+
* @notice Returns if project has reached maximum number of invocations for
|
|
1992
|
+
* a given project and core contract, properly accounting for the auction
|
|
1993
|
+
* state, unminted bids, core contract invocations, and minter max
|
|
1994
|
+
* invocations when determining maxHasBeenInvoked
|
|
1995
|
+
* @param projectId Project Id to get config for
|
|
1996
|
+
* @param coreContract Core contract address to get config for
|
|
1997
|
+
* @return maxHasBeenInvoked bool indicating if max invocations have been invoked
|
|
1998
|
+
*/
|
|
1999
|
+
function getMaxHasBeenInvoked(
|
|
2000
|
+
uint256 projectId,
|
|
2001
|
+
address coreContract
|
|
2002
|
+
) internal view returns (bool maxHasBeenInvoked) {
|
|
2003
|
+
// calculate if max has been invoked based on auction state
|
|
2004
|
+
ProjectMinterStates projectMinterState = getProjectMinterState({
|
|
2005
|
+
projectId: projectId,
|
|
2006
|
+
coreContract: coreContract
|
|
2007
|
+
});
|
|
2008
|
+
if (projectMinterState == ProjectMinterStates.PreAuction) {
|
|
2009
|
+
// pre-auction, true if numTokensInAuction == 0
|
|
2010
|
+
RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({
|
|
2011
|
+
projectId: projectId,
|
|
2012
|
+
coreContract: coreContract
|
|
2013
|
+
});
|
|
2014
|
+
if (RAMProjectConfig_.timestampStart > 0) {
|
|
2015
|
+
// if auction configured, look at num tokens in auction
|
|
2016
|
+
maxHasBeenInvoked = RAMProjectConfig_.numTokensInAuction == 0;
|
|
2017
|
+
} else {
|
|
2018
|
+
// if auction not configured, defer to max invocation lib
|
|
2019
|
+
maxHasBeenInvoked = MaxInvocationsLib.getMaxHasBeenInvoked({
|
|
2020
|
+
projectId: projectId,
|
|
2021
|
+
coreContract: coreContract
|
|
2022
|
+
});
|
|
2023
|
+
}
|
|
2024
|
+
} else if (projectMinterState == ProjectMinterStates.LiveAuction) {
|
|
2025
|
+
// live auction, set to true if num bids >= num tokens in auction
|
|
2026
|
+
RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({
|
|
2027
|
+
projectId: projectId,
|
|
2028
|
+
coreContract: coreContract
|
|
2029
|
+
});
|
|
2030
|
+
maxHasBeenInvoked =
|
|
2031
|
+
RAMProjectConfig_.numBids >=
|
|
2032
|
+
RAMProjectConfig_.numTokensInAuction;
|
|
2033
|
+
} else {
|
|
2034
|
+
// post auction, set to true if remaining excess invocations is zero
|
|
2035
|
+
(, , uint256 numExcessInvocationsAvailable) = isErrorE1FlagF1({
|
|
2036
|
+
projectId: projectId,
|
|
2037
|
+
coreContract: coreContract
|
|
2038
|
+
});
|
|
2039
|
+
maxHasBeenInvoked = numExcessInvocationsAvailable == 0;
|
|
2040
|
+
}
|
|
2041
|
+
}
|
|
2042
|
+
|
|
2043
|
+
/**
|
|
2044
|
+
* Returns balance of project `projectId` on core contract `coreContract`
|
|
2045
|
+
* on this minter contract.
|
|
2046
|
+
* @param projectId Project ID to get the balance for
|
|
2047
|
+
* @param coreContract Core contract address for the given project
|
|
2048
|
+
*/
|
|
2049
|
+
function getProjectBalance(
|
|
2050
|
+
uint256 projectId,
|
|
2051
|
+
address coreContract
|
|
2052
|
+
) internal view returns (uint256) {
|
|
2053
|
+
RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({
|
|
2054
|
+
projectId: projectId,
|
|
2055
|
+
coreContract: coreContract
|
|
2056
|
+
});
|
|
2057
|
+
return RAMProjectConfig_.projectBalance;
|
|
2058
|
+
}
|
|
2059
|
+
|
|
2060
|
+
/**
|
|
2061
|
+
* Loads the RAMProjectConfig for a given project and core
|
|
2062
|
+
* contract.
|
|
2063
|
+
* @param projectId Project Id to get config for
|
|
2064
|
+
* @param coreContract Core contract address to get config for
|
|
2065
|
+
*/
|
|
2066
|
+
function getRAMProjectConfig(
|
|
2067
|
+
uint256 projectId,
|
|
2068
|
+
address coreContract
|
|
2069
|
+
) internal view returns (RAMProjectConfig storage) {
|
|
2070
|
+
return s().RAMProjectConfigs[coreContract][projectId];
|
|
2071
|
+
}
|
|
2072
|
+
|
|
2073
|
+
/**
|
|
2074
|
+
* Loads the RAMAdminMintingConstraint for a given core contract.
|
|
2075
|
+
* @param coreContract Core contract address to get config for
|
|
2076
|
+
*/
|
|
2077
|
+
function getRAMAdminMintingConstraintValue(
|
|
2078
|
+
address coreContract
|
|
2079
|
+
) internal view returns (AdminMintingConstraint) {
|
|
2080
|
+
return s().RAMAdminMintingConstraint[coreContract];
|
|
2081
|
+
}
|
|
2082
|
+
|
|
2083
|
+
/**
|
|
2084
|
+
* @notice private helper function to mint a token.
|
|
2085
|
+
* @dev assumes all checks have been performed
|
|
2086
|
+
* @param projectId project ID to mint token for
|
|
2087
|
+
* @param coreContract core contract address for the given project
|
|
2088
|
+
* @param bidId bid ID of bid to mint token for
|
|
2089
|
+
* @param bidder bidder address of bid to mint token for
|
|
2090
|
+
* @param minterFilter minter filter contract address
|
|
2091
|
+
*/
|
|
2092
|
+
function _mintTokenForBid(
|
|
2093
|
+
uint256 projectId,
|
|
2094
|
+
address coreContract,
|
|
2095
|
+
uint32 bidId,
|
|
2096
|
+
address bidder,
|
|
2097
|
+
IMinterFilterV1 minterFilter
|
|
2098
|
+
) private {
|
|
2099
|
+
// mint token
|
|
2100
|
+
uint256 tokenId = minterFilter.mint_joo({
|
|
2101
|
+
to: bidder,
|
|
2102
|
+
projectId: projectId,
|
|
2103
|
+
coreContract: coreContract,
|
|
2104
|
+
sender: msg.sender
|
|
2105
|
+
});
|
|
2106
|
+
// emit event for state change
|
|
2107
|
+
emit BidMinted({
|
|
2108
|
+
projectId: projectId,
|
|
2109
|
+
coreContract: coreContract,
|
|
2110
|
+
bidId: bidId,
|
|
2111
|
+
tokenId: tokenId
|
|
2112
|
+
});
|
|
2113
|
+
}
|
|
2114
|
+
|
|
2115
|
+
/**
|
|
2116
|
+
* @notice private helper function to mint and settle bid if not already settled.
|
|
2117
|
+
* Assumes check that bidder for bid `bidId` is not null
|
|
2118
|
+
* @param projectId Project ID to mint token on.
|
|
2119
|
+
* @param coreContract Core contract address for the given project.
|
|
2120
|
+
* @param projectPrice Price of a token for the given project.
|
|
2121
|
+
* @param slotIndex Slot index of bid.
|
|
2122
|
+
* @param bidId ID of bid to settle.
|
|
2123
|
+
* @param minterFilter Minter filter contract address
|
|
2124
|
+
* @param minterRefundGasLimit Gas limit to use when settling bid, prior to using fallback force-send to refund
|
|
2125
|
+
*/
|
|
2126
|
+
function _mintAndSettle(
|
|
2127
|
+
uint256 projectId,
|
|
2128
|
+
address coreContract,
|
|
2129
|
+
uint256 projectPrice,
|
|
2130
|
+
uint256 slotIndex,
|
|
2131
|
+
uint256 bidId,
|
|
2132
|
+
IMinterFilterV1 minterFilter,
|
|
2133
|
+
uint256 minterRefundGasLimit
|
|
2134
|
+
) private {
|
|
2135
|
+
// load project config
|
|
2136
|
+
RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({
|
|
2137
|
+
projectId: projectId,
|
|
2138
|
+
coreContract: coreContract
|
|
2139
|
+
});
|
|
2140
|
+
Bid storage bid = RAMProjectConfig_.bids[bidId];
|
|
2141
|
+
// Mark bid as minted
|
|
2142
|
+
_setBidPackedBool({bid: bid, index: INDEX_IS_MINTED, value: true});
|
|
2143
|
+
|
|
2144
|
+
// Mint token for bid
|
|
2145
|
+
_mintTokenForBid({
|
|
2146
|
+
projectId: projectId,
|
|
2147
|
+
coreContract: coreContract,
|
|
2148
|
+
bidId: uint32(bidId),
|
|
2149
|
+
bidder: bid.bidder,
|
|
2150
|
+
minterFilter: minterFilter
|
|
2151
|
+
});
|
|
2152
|
+
|
|
2153
|
+
// Settle if not already settled
|
|
2154
|
+
// @dev collector could have previously settled bid, so need to
|
|
2155
|
+
// settle only if not already settled
|
|
2156
|
+
if (!(_getBidPackedBool(bid, INDEX_IS_SETTLED))) {
|
|
2157
|
+
_settleBid({
|
|
2158
|
+
RAMProjectConfig_: RAMProjectConfig_,
|
|
2159
|
+
projectId: projectId,
|
|
2160
|
+
coreContract: coreContract,
|
|
2161
|
+
projectPrice: projectPrice,
|
|
2162
|
+
slotIndex: slotIndex,
|
|
2163
|
+
bidId: uint32(bidId),
|
|
2164
|
+
minterRefundGasLimit: minterRefundGasLimit
|
|
2165
|
+
});
|
|
2166
|
+
}
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2169
|
+
/**
|
|
2170
|
+
* @notice Helper function to handle settling a bid.
|
|
2171
|
+
* Reverts if bidder is not the bid's bidder.
|
|
2172
|
+
* Reverts if bid has already been settled.
|
|
2173
|
+
* @param RAMProjectConfig_ RAMProjectConfig to update
|
|
2174
|
+
* @param projectId Project ID of bid to settle
|
|
2175
|
+
* @param coreContract Core contract address for the given project.
|
|
2176
|
+
* @param projectPrice Price of token on the project
|
|
2177
|
+
* @param bidId ID of bid to settle
|
|
2178
|
+
* @param bidder Bidder address of bid to settle
|
|
2179
|
+
* @param minterRefundGasLimit Gas limit to use when refunding the bidder.
|
|
2180
|
+
*/
|
|
2181
|
+
function _settleBidWithChecks(
|
|
2182
|
+
RAMProjectConfig storage RAMProjectConfig_,
|
|
2183
|
+
uint256 projectId,
|
|
2184
|
+
address coreContract,
|
|
2185
|
+
uint256 projectPrice,
|
|
2186
|
+
uint32 bidId,
|
|
2187
|
+
address bidder,
|
|
2188
|
+
uint256 minterRefundGasLimit
|
|
2189
|
+
) private {
|
|
2190
|
+
// CHECKS
|
|
2191
|
+
Bid storage bid = RAMProjectConfig_.bids[bidId];
|
|
2192
|
+
// require bidder is the bid's bidder
|
|
2193
|
+
require(bid.bidder == bidder, "Only bidder");
|
|
2194
|
+
// require bid is not yet settled
|
|
2195
|
+
require(
|
|
2196
|
+
!(_getBidPackedBool(bid, INDEX_IS_SETTLED)),
|
|
2197
|
+
"Only un-settled bid"
|
|
2198
|
+
);
|
|
2199
|
+
|
|
2200
|
+
_settleBid({
|
|
2201
|
+
RAMProjectConfig_: RAMProjectConfig_,
|
|
2202
|
+
projectId: projectId,
|
|
2203
|
+
coreContract: coreContract,
|
|
2204
|
+
slotIndex: bid.slotIndex,
|
|
2205
|
+
bidId: bidId,
|
|
2206
|
+
projectPrice: projectPrice,
|
|
2207
|
+
minterRefundGasLimit: minterRefundGasLimit
|
|
2208
|
+
});
|
|
2209
|
+
}
|
|
2210
|
+
|
|
2211
|
+
/**
|
|
2212
|
+
* @notice private helper function to handle settling a bid.
|
|
2213
|
+
* @dev assumes bid has not been previously settled, and that all other
|
|
2214
|
+
* checks have been performed.
|
|
2215
|
+
* @param RAMProjectConfig_ RAMProjectConfig to update
|
|
2216
|
+
* @param projectId Project ID of bid to settle
|
|
2217
|
+
* @param coreContract Core contract address for the given project.
|
|
2218
|
+
* @param slotIndex Slot index of bid to settle
|
|
2219
|
+
* @param bidId ID of bid to settle
|
|
2220
|
+
* @param projectPrice Price of token on the project
|
|
2221
|
+
* @param minterRefundGasLimit Gas limit to use when refunding the previous
|
|
2222
|
+
* highest bidder, prior to using fallback force-send to refund
|
|
2223
|
+
*/
|
|
2224
|
+
function _settleBid(
|
|
2225
|
+
RAMProjectConfig storage RAMProjectConfig_,
|
|
2226
|
+
uint256 projectId,
|
|
2227
|
+
address coreContract,
|
|
2228
|
+
uint256 slotIndex,
|
|
2229
|
+
uint32 bidId,
|
|
2230
|
+
uint256 projectPrice,
|
|
2231
|
+
uint256 minterRefundGasLimit
|
|
2232
|
+
) private {
|
|
2233
|
+
// @dev bid not passed as parameter to avoid stack too deep error in
|
|
2234
|
+
// functions that utilize this helper function
|
|
2235
|
+
Bid storage bid = RAMProjectConfig_.bids[bidId];
|
|
2236
|
+
// EFFECTS
|
|
2237
|
+
// update state
|
|
2238
|
+
_setBidPackedBool({bid: bid, index: INDEX_IS_SETTLED, value: true});
|
|
2239
|
+
// amount due = bid amount - project price
|
|
2240
|
+
uint256 amountDue = slotIndexToBidValue({
|
|
2241
|
+
basePrice: RAMProjectConfig_.basePrice,
|
|
2242
|
+
// @dev safe to cast to uint16
|
|
2243
|
+
slotIndex: uint16(slotIndex)
|
|
2244
|
+
}) - projectPrice;
|
|
2245
|
+
if (amountDue > 0) {
|
|
2246
|
+
// force-send settlement to bidder
|
|
2247
|
+
// @dev reverts on underflow
|
|
2248
|
+
RAMProjectConfig_.projectBalance -= uint120(amountDue);
|
|
2249
|
+
SplitFundsLib.forceSafeTransferETH({
|
|
2250
|
+
to: bid.bidder,
|
|
2251
|
+
amount: amountDue,
|
|
2252
|
+
minterRefundGasLimit: minterRefundGasLimit
|
|
2253
|
+
});
|
|
2254
|
+
}
|
|
2255
|
+
// emit event for state change
|
|
2256
|
+
emit BidSettled({
|
|
2257
|
+
projectId: projectId,
|
|
2258
|
+
coreContract: coreContract,
|
|
2259
|
+
bidId: bidId
|
|
2260
|
+
});
|
|
2261
|
+
}
|
|
2262
|
+
|
|
2263
|
+
/**
|
|
2264
|
+
* @notice private helper function to settle and refund bids to resolve E1 error state.
|
|
2265
|
+
* Assumes check that bidder for bid `bidId` is not null
|
|
2266
|
+
* @param projectId Project ID to refund bid for.
|
|
2267
|
+
* @param coreContract Core contract address for the given project.
|
|
2268
|
+
* @param projectPrice Price of a token for the given project.
|
|
2269
|
+
* @param slotIndex Slot index of bid.
|
|
2270
|
+
* @param bidId ID of bid to settle.
|
|
2271
|
+
* @param minterRefundGasLimit Gas limit to use when refunding bidder
|
|
2272
|
+
*/
|
|
2273
|
+
function _settleAndRefundBid(
|
|
2274
|
+
uint256 projectId,
|
|
2275
|
+
address coreContract,
|
|
2276
|
+
uint256 projectPrice,
|
|
2277
|
+
uint256 slotIndex,
|
|
2278
|
+
uint256 bidId,
|
|
2279
|
+
uint256 minterRefundGasLimit
|
|
2280
|
+
) private {
|
|
2281
|
+
// load project config
|
|
2282
|
+
RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({
|
|
2283
|
+
projectId: projectId,
|
|
2284
|
+
coreContract: coreContract
|
|
2285
|
+
});
|
|
2286
|
+
// load bid
|
|
2287
|
+
Bid storage bid = RAMProjectConfig_.bids[bidId];
|
|
2288
|
+
// @dev bidderAddress previously checked not null
|
|
2289
|
+
address bidderAddress = bid.bidder;
|
|
2290
|
+
// Settle and refund the Bid
|
|
2291
|
+
// Minimum value to send is the project price
|
|
2292
|
+
uint256 valueToSend = projectPrice;
|
|
2293
|
+
bool didSettleBid = false;
|
|
2294
|
+
|
|
2295
|
+
// if not isSettled, then settle the bid
|
|
2296
|
+
if (!_getBidPackedBool(bid, INDEX_IS_SETTLED)) {
|
|
2297
|
+
// mark bid as settled
|
|
2298
|
+
_setBidPackedBool({bid: bid, index: INDEX_IS_SETTLED, value: true});
|
|
2299
|
+
didSettleBid = true;
|
|
2300
|
+
// send entire bid value if not previously settled
|
|
2301
|
+
valueToSend = slotIndexToBidValue({
|
|
2302
|
+
basePrice: RAMProjectConfig_.basePrice,
|
|
2303
|
+
slotIndex: uint16(slotIndex)
|
|
2304
|
+
});
|
|
2305
|
+
}
|
|
2306
|
+
// mark bid as refunded
|
|
2307
|
+
_setBidPackedBool({bid: bid, index: INDEX_IS_REFUNDED, value: true});
|
|
2308
|
+
// INTERACTIONS
|
|
2309
|
+
// force-send refund to bidder
|
|
2310
|
+
// @dev reverts on underflow
|
|
2311
|
+
RAMProjectConfig_.projectBalance -= uint120(valueToSend);
|
|
2312
|
+
SplitFundsLib.forceSafeTransferETH({
|
|
2313
|
+
to: bidderAddress,
|
|
2314
|
+
amount: valueToSend,
|
|
2315
|
+
minterRefundGasLimit: minterRefundGasLimit
|
|
2316
|
+
});
|
|
2317
|
+
// emit event for state changes
|
|
2318
|
+
if (didSettleBid) {
|
|
2319
|
+
emit BidSettled({
|
|
2320
|
+
projectId: projectId,
|
|
2321
|
+
coreContract: coreContract,
|
|
2322
|
+
bidId: bidId
|
|
2323
|
+
});
|
|
2324
|
+
}
|
|
2325
|
+
emit BidRefunded({
|
|
2326
|
+
projectId: projectId,
|
|
2327
|
+
coreContract: coreContract,
|
|
2328
|
+
bidId: bidId
|
|
2329
|
+
});
|
|
2330
|
+
}
|
|
2331
|
+
|
|
2332
|
+
/**
|
|
2333
|
+
* @notice Helper function to get the price of a token on a project.
|
|
2334
|
+
* @dev Assumes project is configured, has a base price, and generally
|
|
2335
|
+
* makes sense to get a price for.
|
|
2336
|
+
* @param RAMProjectConfig_ RAMProjectConfig to query
|
|
2337
|
+
*/
|
|
2338
|
+
function _getProjectPrice(
|
|
2339
|
+
RAMProjectConfig storage RAMProjectConfig_
|
|
2340
|
+
) private view returns (uint256 projectPrice) {
|
|
2341
|
+
bool wasSellout = RAMProjectConfig_.numBids >=
|
|
2342
|
+
RAMProjectConfig_.numTokensInAuction;
|
|
2343
|
+
// price is lowest bid if sellout, otherwise base price
|
|
2344
|
+
projectPrice = wasSellout
|
|
2345
|
+
? slotIndexToBidValue({
|
|
2346
|
+
basePrice: RAMProjectConfig_.basePrice,
|
|
2347
|
+
slotIndex: RAMProjectConfig_.minBidSlotIndex
|
|
2348
|
+
})
|
|
2349
|
+
: RAMProjectConfig_.basePrice;
|
|
2350
|
+
}
|
|
2351
|
+
|
|
2352
|
+
/**
|
|
2353
|
+
* @notice Helper function to get the number of tokens owed for a given
|
|
2354
|
+
* project.
|
|
2355
|
+
* @param RAMProjectConfig_ RAMProjectConfig to query
|
|
2356
|
+
* @return tokensOwed The number of bids in a project minus the sum of tokens already
|
|
2357
|
+
* minted and bids that have been refunded due to an error state.
|
|
2358
|
+
*/
|
|
2359
|
+
function _getNumTokensOwed(
|
|
2360
|
+
RAMProjectConfig storage RAMProjectConfig_
|
|
2361
|
+
) private view returns (uint256 tokensOwed) {
|
|
2362
|
+
tokensOwed =
|
|
2363
|
+
RAMProjectConfig_.numBids -
|
|
2364
|
+
(RAMProjectConfig_.numBidsMintedTokens +
|
|
2365
|
+
RAMProjectConfig_.numBidsErrorRefunded);
|
|
2366
|
+
}
|
|
2367
|
+
|
|
2368
|
+
/**
|
|
2369
|
+
* @notice Inserts a bid into the project's RAMProjectConfig.
|
|
2370
|
+
* Assumes the bid is valid and may be inserted into the bucket-sort data
|
|
2371
|
+
* structure.
|
|
2372
|
+
* Creates a new bid if bidId is zero, otherwise moves an existing bid,
|
|
2373
|
+
* which is assumed to exist and be valid.
|
|
2374
|
+
* Emits BidCreated event if a new bid is created.
|
|
2375
|
+
* @dev assumes slot index is valid and < NUM_SLOTS
|
|
2376
|
+
* @param RAMProjectConfig_ RAM project config to insert bid into
|
|
2377
|
+
* @param projectId Project ID to insert bid for
|
|
2378
|
+
* @param coreContract Core contract address to insert bid for
|
|
2379
|
+
* @param slotIndex Slot index to insert bid at
|
|
2380
|
+
* @param bidder Bidder address
|
|
2381
|
+
* @param bidId Bid ID to insert, or zero if a new bid should be created
|
|
2382
|
+
*/
|
|
2383
|
+
function _insertBid(
|
|
2384
|
+
RAMProjectConfig storage RAMProjectConfig_,
|
|
2385
|
+
uint256 projectId,
|
|
2386
|
+
address coreContract,
|
|
2387
|
+
uint16 slotIndex,
|
|
2388
|
+
address bidder,
|
|
2389
|
+
uint32 bidId
|
|
2390
|
+
) private {
|
|
2391
|
+
// add the new Bid to tail of the slot's doubly linked list
|
|
2392
|
+
bool createNewBid = bidId == 0;
|
|
2393
|
+
if (createNewBid) {
|
|
2394
|
+
// prefix ++ to skip initial bid ID of zero (indicates null value)
|
|
2395
|
+
bidId = ++RAMProjectConfig_.nextBidId;
|
|
2396
|
+
}
|
|
2397
|
+
uint256 prevTailBidId = RAMProjectConfig_.tailBidIdBySlot[slotIndex];
|
|
2398
|
+
RAMProjectConfig_.bids[bidId] = Bid({
|
|
2399
|
+
prevBidId: uint32(prevTailBidId),
|
|
2400
|
+
nextBidId: 0, // null value at end of tail
|
|
2401
|
+
slotIndex: slotIndex,
|
|
2402
|
+
bidder: bidder,
|
|
2403
|
+
packedBools: 0 // all packed bools false
|
|
2404
|
+
});
|
|
2405
|
+
// update tail pointer to new bid
|
|
2406
|
+
RAMProjectConfig_.tailBidIdBySlot[slotIndex] = bidId;
|
|
2407
|
+
// update head pointer or next pointer of previous bid
|
|
2408
|
+
if (prevTailBidId == 0) {
|
|
2409
|
+
// first bid in slot, update head pointer
|
|
2410
|
+
RAMProjectConfig_.headBidIdBySlot[slotIndex] = bidId;
|
|
2411
|
+
} else {
|
|
2412
|
+
// update previous bid's next pointer
|
|
2413
|
+
RAMProjectConfig_.bids[prevTailBidId].nextBidId = bidId;
|
|
2414
|
+
}
|
|
2415
|
+
|
|
2416
|
+
// update number of active bids
|
|
2417
|
+
RAMProjectConfig_.numBids++;
|
|
2418
|
+
// update metadata if first bid for this slot
|
|
2419
|
+
// @dev assumes minting has not yet started
|
|
2420
|
+
if (prevTailBidId == 0) {
|
|
2421
|
+
// set the slot in the bitmap
|
|
2422
|
+
_setBitmapSlot({
|
|
2423
|
+
RAMProjectConfig_: RAMProjectConfig_,
|
|
2424
|
+
slotIndex: slotIndex
|
|
2425
|
+
});
|
|
2426
|
+
// update bitmap metadata - reduce min bid index if necessary
|
|
2427
|
+
if (slotIndex < RAMProjectConfig_.minBidSlotIndex) {
|
|
2428
|
+
RAMProjectConfig_.minBidSlotIndex = slotIndex;
|
|
2429
|
+
}
|
|
2430
|
+
// update bitmap metadata - increase max bid index if necessary
|
|
2431
|
+
if (slotIndex > RAMProjectConfig_.maxBidSlotIndex) {
|
|
2432
|
+
RAMProjectConfig_.maxBidSlotIndex = slotIndex;
|
|
2433
|
+
}
|
|
2434
|
+
}
|
|
2435
|
+
|
|
2436
|
+
if (createNewBid) {
|
|
2437
|
+
// emit state change event
|
|
2438
|
+
emit BidCreated({
|
|
2439
|
+
projectId: projectId,
|
|
2440
|
+
coreContract: coreContract,
|
|
2441
|
+
slotIndex: slotIndex,
|
|
2442
|
+
bidId: bidId,
|
|
2443
|
+
bidder: bidder
|
|
2444
|
+
});
|
|
2445
|
+
}
|
|
2446
|
+
}
|
|
2447
|
+
|
|
2448
|
+
/**
|
|
2449
|
+
* @notice Remove minimum bid from the project's RAMProjectConfig.
|
|
2450
|
+
* Reverts if no bids exist in slot RAMProjectConfig_.minBidSlotIndex.
|
|
2451
|
+
* @param RAMProjectConfig_ RAM project config to remove bid from
|
|
2452
|
+
* @param projectId Project ID to remove bid from
|
|
2453
|
+
* @param coreContract Core contract address for the given project
|
|
2454
|
+
* @param minterRefundGasLimit Gas limit to use when refunding the previous
|
|
2455
|
+
* highest bidder, prior to using fallback force-send to refund
|
|
2456
|
+
* @return removedBidAmount The value of the removed bid, in Wei
|
|
2457
|
+
*/
|
|
2458
|
+
function _removeMinBid(
|
|
2459
|
+
RAMProjectConfig storage RAMProjectConfig_,
|
|
2460
|
+
uint256 projectId,
|
|
2461
|
+
address coreContract,
|
|
2462
|
+
uint256 minterRefundGasLimit
|
|
2463
|
+
) private returns (uint256 removedBidAmount) {
|
|
2464
|
+
// get the minimum bid slot and bid id
|
|
2465
|
+
uint16 removedSlotIndex = RAMProjectConfig_.minBidSlotIndex;
|
|
2466
|
+
uint256 removedBidId = RAMProjectConfig_.tailBidIdBySlot[
|
|
2467
|
+
removedSlotIndex
|
|
2468
|
+
];
|
|
2469
|
+
// @dev no coverage on else branch because it is unreachable as used
|
|
2470
|
+
require(removedBidId > 0, "No bids");
|
|
2471
|
+
// record the previous min bidder
|
|
2472
|
+
Bid storage removedBid = RAMProjectConfig_.bids[removedBidId];
|
|
2473
|
+
address removedBidder = removedBid.bidder;
|
|
2474
|
+
// update the tail pointer of the slot's doubly linked list
|
|
2475
|
+
uint32 newTailBidId = removedBid.prevBidId;
|
|
2476
|
+
RAMProjectConfig_.tailBidIdBySlot[removedSlotIndex] = newTailBidId;
|
|
2477
|
+
|
|
2478
|
+
RAMProjectConfig_.numBids--;
|
|
2479
|
+
// update metadata if no more active bids for this slot
|
|
2480
|
+
if (newTailBidId == 0) {
|
|
2481
|
+
// update the head pointer of the slot's doubly linked list
|
|
2482
|
+
RAMProjectConfig_.headBidIdBySlot[removedSlotIndex] = 0;
|
|
2483
|
+
|
|
2484
|
+
// unset the slot in the bitmap
|
|
2485
|
+
// update minBidIndex, efficiently starting at minBidSlotIndex + 1
|
|
2486
|
+
_unsetBitmapSlot({
|
|
2487
|
+
RAMProjectConfig_: RAMProjectConfig_,
|
|
2488
|
+
slotIndex: removedSlotIndex
|
|
2489
|
+
});
|
|
2490
|
+
// @dev reverts if removedSlotIndex was the maximum slot 511,
|
|
2491
|
+
// preventing bids from being removed entirely from the last slot,
|
|
2492
|
+
// which is acceptable and non-impacting for this minter
|
|
2493
|
+
// @dev sets minBidSlotIndex to 512 if no more active bids, which
|
|
2494
|
+
// is desired behavior for this minter
|
|
2495
|
+
RAMProjectConfig_.minBidSlotIndex = _getMinSlotWithBid({
|
|
2496
|
+
RAMProjectConfig_: RAMProjectConfig_,
|
|
2497
|
+
startSlotIndex: removedSlotIndex + 1
|
|
2498
|
+
});
|
|
2499
|
+
} else {
|
|
2500
|
+
// if the removed bid was not the head, then unset the nextBidId pointer of the bid
|
|
2501
|
+
Bid storage newTailBid = RAMProjectConfig_.bids[newTailBidId];
|
|
2502
|
+
newTailBid.nextBidId = 0;
|
|
2503
|
+
}
|
|
2504
|
+
// refund the removed bidder
|
|
2505
|
+
removedBidAmount = slotIndexToBidValue({
|
|
2506
|
+
basePrice: RAMProjectConfig_.basePrice,
|
|
2507
|
+
slotIndex: removedSlotIndex
|
|
2508
|
+
});
|
|
2509
|
+
// @dev reverts on underflow
|
|
2510
|
+
RAMProjectConfig_.projectBalance -= uint120(removedBidAmount);
|
|
2511
|
+
|
|
2512
|
+
// delete the removed bid to prevent future claiming
|
|
2513
|
+
// @dev performed last to avoid pointing to deleted bid struct
|
|
2514
|
+
delete RAMProjectConfig_.bids[removedBidId];
|
|
2515
|
+
|
|
2516
|
+
SplitFundsLib.forceSafeTransferETH({
|
|
2517
|
+
to: removedBidder,
|
|
2518
|
+
amount: removedBidAmount,
|
|
2519
|
+
minterRefundGasLimit: minterRefundGasLimit
|
|
2520
|
+
});
|
|
2521
|
+
// emit state change event
|
|
2522
|
+
emit BidRemoved({
|
|
2523
|
+
projectId: projectId,
|
|
2524
|
+
coreContract: coreContract,
|
|
2525
|
+
bidId: removedBidId
|
|
2526
|
+
});
|
|
2527
|
+
}
|
|
2528
|
+
|
|
2529
|
+
/**
|
|
2530
|
+
* @notice Ejects a bid from the project's RAMProjectConfig.
|
|
2531
|
+
* Assumes the bid is valid (i.e. bid ID is a valid, active bid).
|
|
2532
|
+
* Does not refund the bidder, does not emit events, does not delete Bid.
|
|
2533
|
+
* @param RAMProjectConfig_ RAM project config to eject bid from
|
|
2534
|
+
* @param slotIndex Slot index to eject bid from
|
|
2535
|
+
* @param bidId ID of bid to eject
|
|
2536
|
+
*/
|
|
2537
|
+
function _ejectBidFromSlot(
|
|
2538
|
+
RAMProjectConfig storage RAMProjectConfig_,
|
|
2539
|
+
uint16 slotIndex,
|
|
2540
|
+
uint256 bidId
|
|
2541
|
+
) private {
|
|
2542
|
+
// get the bid to remove
|
|
2543
|
+
Bid storage removedBid = RAMProjectConfig_.bids[bidId];
|
|
2544
|
+
uint32 prevBidId = removedBid.prevBidId;
|
|
2545
|
+
uint32 nextBidId = removedBid.nextBidId;
|
|
2546
|
+
// update previous bid's next pointer
|
|
2547
|
+
if (prevBidId == 0) {
|
|
2548
|
+
// removed bid was the head bid
|
|
2549
|
+
RAMProjectConfig_.headBidIdBySlot[slotIndex] = nextBidId;
|
|
2550
|
+
} else {
|
|
2551
|
+
// removed bid was not the head bid
|
|
2552
|
+
RAMProjectConfig_.bids[prevBidId].nextBidId = nextBidId;
|
|
2553
|
+
}
|
|
2554
|
+
// update next bid's previous pointer
|
|
2555
|
+
if (nextBidId == 0) {
|
|
2556
|
+
// removed bid was the tail bid
|
|
2557
|
+
RAMProjectConfig_.tailBidIdBySlot[slotIndex] = prevBidId;
|
|
2558
|
+
} else {
|
|
2559
|
+
// removed bid was not the tail bid
|
|
2560
|
+
RAMProjectConfig_.bids[nextBidId].prevBidId = prevBidId;
|
|
2561
|
+
}
|
|
2562
|
+
|
|
2563
|
+
// decrement the number of active bids
|
|
2564
|
+
RAMProjectConfig_.numBids--;
|
|
2565
|
+
|
|
2566
|
+
// update metadata if no more active bids for this slot
|
|
2567
|
+
if (prevBidId == 0 && nextBidId == 0) {
|
|
2568
|
+
// unset the slot in the bitmap
|
|
2569
|
+
// update minBidIndex, efficiently starting at minBidSlotIndex + 1
|
|
2570
|
+
_unsetBitmapSlot({
|
|
2571
|
+
RAMProjectConfig_: RAMProjectConfig_,
|
|
2572
|
+
slotIndex: slotIndex
|
|
2573
|
+
});
|
|
2574
|
+
// @dev reverts if removedSlotIndex was the maximum slot 511,
|
|
2575
|
+
// preventing bids from being removed entirely from the last slot,
|
|
2576
|
+
// which is acceptable and non-impacting for this minter
|
|
2577
|
+
// @dev sets minBidSlotIndex to 512 if no more active bids, which
|
|
2578
|
+
// is desired behavior for this minter
|
|
2579
|
+
if (RAMProjectConfig_.minBidSlotIndex == slotIndex) {
|
|
2580
|
+
RAMProjectConfig_.minBidSlotIndex = _getMinSlotWithBid({
|
|
2581
|
+
RAMProjectConfig_: RAMProjectConfig_,
|
|
2582
|
+
startSlotIndex: slotIndex + 1
|
|
2583
|
+
});
|
|
2584
|
+
}
|
|
2585
|
+
}
|
|
2586
|
+
|
|
2587
|
+
// @dev do not refund, do not emit event, do not delete bid
|
|
2588
|
+
}
|
|
2589
|
+
|
|
2590
|
+
/**
|
|
2591
|
+
* @notice Helper function to handle setting slot in 512-bit bitmap
|
|
2592
|
+
* Reverts if slotIndex > 511
|
|
2593
|
+
* @param slotIndex Index of slot to set (between 0 and 511)
|
|
2594
|
+
* @param RAMProjectConfig_ RAMProjectConfig to update
|
|
2595
|
+
*/
|
|
2596
|
+
function _setBitmapSlot(
|
|
2597
|
+
RAMProjectConfig storage RAMProjectConfig_,
|
|
2598
|
+
uint256 slotIndex
|
|
2599
|
+
) private {
|
|
2600
|
+
// revert if slotIndex >= NUM_SLOTS, since this is an invalid input
|
|
2601
|
+
// @dev no coverage as slot index out of range checked in placeBid and implicitly in topUpBid
|
|
2602
|
+
require(slotIndex < NUM_SLOTS, "Only slot index lt NUM_SLOTS");
|
|
2603
|
+
// set the slot in the bitmap
|
|
2604
|
+
if (slotIndex < 256) {
|
|
2605
|
+
// @dev <256 conditional ensures no overflow when casting to uint8
|
|
2606
|
+
RAMProjectConfig_.slotsBitmapA = RAMProjectConfig_.slotsBitmapA.set(
|
|
2607
|
+
uint8(slotIndex)
|
|
2608
|
+
);
|
|
2609
|
+
} else {
|
|
2610
|
+
// @dev <512 results in no overflow when casting to uint8
|
|
2611
|
+
RAMProjectConfig_.slotsBitmapB = RAMProjectConfig_.slotsBitmapB.set(
|
|
2612
|
+
// @dev casting to uint8 intentional overflow instead of
|
|
2613
|
+
// subtracting 256 from slotIndex
|
|
2614
|
+
uint8(slotIndex)
|
|
2615
|
+
);
|
|
2616
|
+
}
|
|
2617
|
+
}
|
|
2618
|
+
|
|
2619
|
+
/**
|
|
2620
|
+
* @notice Helper function to handle unsetting slot in 512-bit bitmap
|
|
2621
|
+
* Reverts if slotIndex > 511
|
|
2622
|
+
* @param slotIndex Index of slot to set (between 0 and 511)
|
|
2623
|
+
* @param RAMProjectConfig_ RAMProjectConfig to update
|
|
2624
|
+
*/
|
|
2625
|
+
function _unsetBitmapSlot(
|
|
2626
|
+
RAMProjectConfig storage RAMProjectConfig_,
|
|
2627
|
+
uint256 slotIndex
|
|
2628
|
+
) private {
|
|
2629
|
+
// revert if slotIndex >= NUM_SLOTS, since this is an invalid input
|
|
2630
|
+
// @dev no coverage as slot index out of range checked in placeBid and implicitly in topUpBid
|
|
2631
|
+
require(slotIndex < NUM_SLOTS, "Only slot index lt NUM_SLOTS");
|
|
2632
|
+
// unset the slot in the bitmap
|
|
2633
|
+
if (slotIndex < 256) {
|
|
2634
|
+
// @dev <256 conditional ensures no overflow when casting to uint8
|
|
2635
|
+
RAMProjectConfig_.slotsBitmapA = RAMProjectConfig_
|
|
2636
|
+
.slotsBitmapA
|
|
2637
|
+
.unset(uint8(slotIndex));
|
|
2638
|
+
} else {
|
|
2639
|
+
// @dev <512 results in no overflow when casting to uint8
|
|
2640
|
+
RAMProjectConfig_.slotsBitmapB = RAMProjectConfig_
|
|
2641
|
+
.slotsBitmapB
|
|
2642
|
+
.unset(
|
|
2643
|
+
// @dev casting to uint8 intentional overflow instead of
|
|
2644
|
+
// subtracting 256 from slotIndex
|
|
2645
|
+
uint8(slotIndex)
|
|
2646
|
+
);
|
|
2647
|
+
}
|
|
2648
|
+
}
|
|
2649
|
+
|
|
2650
|
+
/**
|
|
2651
|
+
* @notice Helper function to set a packed boolean in a Bid struct.
|
|
2652
|
+
* @param bid Bid to update
|
|
2653
|
+
* @param index Index of packed boolean to update
|
|
2654
|
+
* @param value Value to set packed boolean to
|
|
2655
|
+
*/
|
|
2656
|
+
function _setBidPackedBool(
|
|
2657
|
+
Bid storage bid,
|
|
2658
|
+
uint8 index,
|
|
2659
|
+
bool value
|
|
2660
|
+
) private {
|
|
2661
|
+
// @dev no coverage on else branch because it is unreachable as used
|
|
2662
|
+
if (value) {
|
|
2663
|
+
bid.packedBools = uint8(
|
|
2664
|
+
uint256(bid.packedBools).setBoolTrue(index)
|
|
2665
|
+
);
|
|
2666
|
+
} else {
|
|
2667
|
+
bid.packedBools = uint8(
|
|
2668
|
+
uint256(bid.packedBools).setBoolFalse(index)
|
|
2669
|
+
);
|
|
2670
|
+
}
|
|
2671
|
+
}
|
|
2672
|
+
|
|
2673
|
+
/**
|
|
2674
|
+
* @notice Helper function to get a packed boolean from a Bid struct.
|
|
2675
|
+
* @param bid Bid to query
|
|
2676
|
+
* @param index Index of packed boolean to query
|
|
2677
|
+
* @return Value of packed boolean
|
|
2678
|
+
*/
|
|
2679
|
+
function _getBidPackedBool(
|
|
2680
|
+
Bid storage bid,
|
|
2681
|
+
uint8 index
|
|
2682
|
+
) private view returns (bool) {
|
|
2683
|
+
return uint256(bid.packedBools).getBool(index);
|
|
2684
|
+
}
|
|
2685
|
+
|
|
2686
|
+
/**
|
|
2687
|
+
* @notice Helper function to get minimum slot index with an active bid,
|
|
2688
|
+
* starting at a given slot index and searching upwards.
|
|
2689
|
+
* Returns 512, (invalid slot index) if no slots with bids were found.
|
|
2690
|
+
* Reverts if startSlotIndex > 511, since this library only supports 512
|
|
2691
|
+
* slots.
|
|
2692
|
+
* @param RAMProjectConfig_ RAM project config to query
|
|
2693
|
+
* @param startSlotIndex Slot index to start search at
|
|
2694
|
+
* @return minSlotWithBid Minimum slot index with an active bid, or 512 (invalid index) if
|
|
2695
|
+
* no slots with bids were found.
|
|
2696
|
+
*/
|
|
2697
|
+
function _getMinSlotWithBid(
|
|
2698
|
+
RAMProjectConfig storage RAMProjectConfig_,
|
|
2699
|
+
uint16 startSlotIndex
|
|
2700
|
+
) private view returns (uint16 minSlotWithBid) {
|
|
2701
|
+
bool foundSlotWithBid;
|
|
2702
|
+
// revert if startSlotIndex > 511, since this is an invalid input
|
|
2703
|
+
// @dev no coverage on if branch because unreachable as used
|
|
2704
|
+
if (startSlotIndex > 511) {
|
|
2705
|
+
revert("Only start slot index lt 512");
|
|
2706
|
+
}
|
|
2707
|
+
// temporary uint256 in working memory
|
|
2708
|
+
uint256 minSlotWithBid_;
|
|
2709
|
+
// start at startSlotIndex
|
|
2710
|
+
if (startSlotIndex > 255) {
|
|
2711
|
+
// @dev <512 check results in no overflow when casting to uint8
|
|
2712
|
+
(minSlotWithBid_, foundSlotWithBid) = RAMProjectConfig_
|
|
2713
|
+
.slotsBitmapB
|
|
2714
|
+
.minBitSet(
|
|
2715
|
+
// @dev casting to uint8 intentional overflow instead of
|
|
2716
|
+
// subtracting 256 from slotIndex
|
|
2717
|
+
uint8(startSlotIndex)
|
|
2718
|
+
);
|
|
2719
|
+
// add 256 to account for slotsBitmapB offset
|
|
2720
|
+
minSlotWithBid_ += 256;
|
|
2721
|
+
} else {
|
|
2722
|
+
// @dev <256 conditional ensures no overflow when casting to uint8
|
|
2723
|
+
(minSlotWithBid_, foundSlotWithBid) = RAMProjectConfig_
|
|
2724
|
+
.slotsBitmapA
|
|
2725
|
+
.minBitSet(uint8(startSlotIndex));
|
|
2726
|
+
|
|
2727
|
+
// if no bids in first bitmap, check second bitmap
|
|
2728
|
+
// @dev behavior of library's minBitSet is to return 256 if no bits
|
|
2729
|
+
// were set
|
|
2730
|
+
if (!foundSlotWithBid) {
|
|
2731
|
+
// @dev <512 check results in no overflow when casting to uint8
|
|
2732
|
+
(minSlotWithBid_, foundSlotWithBid) = RAMProjectConfig_
|
|
2733
|
+
.slotsBitmapB
|
|
2734
|
+
.minBitSet(
|
|
2735
|
+
// start at beginning of second bitmap
|
|
2736
|
+
uint8(0)
|
|
2737
|
+
);
|
|
2738
|
+
// add 256 to account for slotsBitmapB offset
|
|
2739
|
+
minSlotWithBid_ += 256;
|
|
2740
|
+
}
|
|
2741
|
+
}
|
|
2742
|
+
// populate return value
|
|
2743
|
+
if (!foundSlotWithBid) {
|
|
2744
|
+
return uint16(NUM_SLOTS);
|
|
2745
|
+
} else {
|
|
2746
|
+
minSlotWithBid = uint16(minSlotWithBid_);
|
|
2747
|
+
return minSlotWithBid;
|
|
2748
|
+
}
|
|
2749
|
+
}
|
|
2750
|
+
|
|
2751
|
+
/**
|
|
2752
|
+
* @notice Helper function to get maximum slot index with an active bid,
|
|
2753
|
+
* starting at a given slot index and searching downwards.
|
|
2754
|
+
* Returns 512, (invalid slot index) if no slots with bids were found.
|
|
2755
|
+
* Reverts if startSlotIndex > 511, since this library only supports 512
|
|
2756
|
+
* slots.
|
|
2757
|
+
* @param RAMProjectConfig_ RAM project config to query
|
|
2758
|
+
* @param startSlotIndex Slot index to start search at
|
|
2759
|
+
* @return maxSlotWithBid Maximum slot index with an active bid, and 512 (invalid index) if
|
|
2760
|
+
* no slots with bids were found.
|
|
2761
|
+
*/
|
|
2762
|
+
function _getMaxSlotWithBid(
|
|
2763
|
+
RAMProjectConfig storage RAMProjectConfig_,
|
|
2764
|
+
uint16 startSlotIndex
|
|
2765
|
+
) private view returns (uint16 maxSlotWithBid) {
|
|
2766
|
+
bool foundSlotWithBid;
|
|
2767
|
+
// revert if startSlotIndex > 511, since this is an invalid input
|
|
2768
|
+
// @dev no coverage on if branch because unreachable as used
|
|
2769
|
+
if (startSlotIndex > 511) {
|
|
2770
|
+
revert("Only start slot index lt 512");
|
|
2771
|
+
}
|
|
2772
|
+
// temporary uint256 in working memory
|
|
2773
|
+
uint256 maxSlotWithBid_;
|
|
2774
|
+
// start at startSlotIndex
|
|
2775
|
+
if (startSlotIndex < 256) {
|
|
2776
|
+
// @dev <256 conditional ensures no overflow when casting to uint8
|
|
2777
|
+
(maxSlotWithBid_, foundSlotWithBid) = RAMProjectConfig_
|
|
2778
|
+
.slotsBitmapA
|
|
2779
|
+
.maxBitSet(uint8(startSlotIndex));
|
|
2780
|
+
} else {
|
|
2781
|
+
// need to potentially check both bitmaps
|
|
2782
|
+
(maxSlotWithBid_, foundSlotWithBid) = RAMProjectConfig_
|
|
2783
|
+
.slotsBitmapB
|
|
2784
|
+
.maxBitSet(
|
|
2785
|
+
// @dev casting to uint8 intentional overflow instead of
|
|
2786
|
+
// subtracting 256 from slotIndex
|
|
2787
|
+
uint8(startSlotIndex)
|
|
2788
|
+
);
|
|
2789
|
+
// add 256 to account for slotsBitmapB offset
|
|
2790
|
+
maxSlotWithBid_ += 256;
|
|
2791
|
+
if (!foundSlotWithBid) {
|
|
2792
|
+
// no bids in first bitmap B, so check second bitmap A
|
|
2793
|
+
(maxSlotWithBid_, foundSlotWithBid) = RAMProjectConfig_
|
|
2794
|
+
.slotsBitmapA
|
|
2795
|
+
.maxBitSet(
|
|
2796
|
+
// start at the end of the first bitmap
|
|
2797
|
+
uint8(255)
|
|
2798
|
+
);
|
|
2799
|
+
}
|
|
2800
|
+
}
|
|
2801
|
+
// populate return value
|
|
2802
|
+
// @dev no coverage on if branch because it is unreachable as used
|
|
2803
|
+
if (!foundSlotWithBid) {
|
|
2804
|
+
return uint16(NUM_SLOTS);
|
|
2805
|
+
} else {
|
|
2806
|
+
maxSlotWithBid = uint16(maxSlotWithBid_);
|
|
2807
|
+
return maxSlotWithBid;
|
|
2808
|
+
}
|
|
2809
|
+
}
|
|
2810
|
+
|
|
2811
|
+
/**
|
|
2812
|
+
* @notice Returns the next valid bid slot index and value for a given project.
|
|
2813
|
+
* @dev this may return slot index and value higher than the maximum slot index and value
|
|
2814
|
+
* allowed by the minter, in which case a bid cannot actually be placed
|
|
2815
|
+
* to outbid a bid at `startSlotIndex`.
|
|
2816
|
+
* @param projectId Project ID to find next valid bid slot index for
|
|
2817
|
+
* @param coreContract Core contract address for the given project
|
|
2818
|
+
* @param startSlotIndex Slot index to start search from
|
|
2819
|
+
* @return nextValidBidSlotIndex Next valid bid slot index
|
|
2820
|
+
* @return nextValidBidValue Next valid bid value at nextValidBidSlotIndex slot index, in Wei
|
|
2821
|
+
*/
|
|
2822
|
+
function _findNextValidBidSlotIndexAndValue(
|
|
2823
|
+
uint256 projectId,
|
|
2824
|
+
address coreContract,
|
|
2825
|
+
uint16 startSlotIndex
|
|
2826
|
+
)
|
|
2827
|
+
private
|
|
2828
|
+
view
|
|
2829
|
+
returns (uint16 nextValidBidSlotIndex, uint256 nextValidBidValue)
|
|
2830
|
+
{
|
|
2831
|
+
RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({
|
|
2832
|
+
projectId: projectId,
|
|
2833
|
+
coreContract: coreContract
|
|
2834
|
+
});
|
|
2835
|
+
uint88 basePrice = RAMProjectConfig_.basePrice;
|
|
2836
|
+
uint256 startBidValue = slotIndexToBidValue({
|
|
2837
|
+
basePrice: basePrice,
|
|
2838
|
+
slotIndex: startSlotIndex
|
|
2839
|
+
});
|
|
2840
|
+
// start search at next slot, incremented in while loop
|
|
2841
|
+
uint16 currentSlotIndex = startSlotIndex;
|
|
2842
|
+
while (true) {
|
|
2843
|
+
// increment slot index and re-calc current slot bid value
|
|
2844
|
+
unchecked {
|
|
2845
|
+
currentSlotIndex++;
|
|
2846
|
+
}
|
|
2847
|
+
nextValidBidValue = slotIndexToBidValue({
|
|
2848
|
+
basePrice: basePrice,
|
|
2849
|
+
slotIndex: currentSlotIndex
|
|
2850
|
+
});
|
|
2851
|
+
// break if current slot's bid value is sufficiently greater than
|
|
2852
|
+
// the starting slot's bid value
|
|
2853
|
+
if (
|
|
2854
|
+
_isSufficientOutbid({
|
|
2855
|
+
oldBidValue: startBidValue,
|
|
2856
|
+
newBidValue: nextValidBidValue
|
|
2857
|
+
})
|
|
2858
|
+
) {
|
|
2859
|
+
break;
|
|
2860
|
+
}
|
|
2861
|
+
// otherwise continue to next iteration
|
|
2862
|
+
}
|
|
2863
|
+
// return the found valid slot index
|
|
2864
|
+
nextValidBidSlotIndex = currentSlotIndex;
|
|
2865
|
+
}
|
|
2866
|
+
|
|
2867
|
+
/**
|
|
2868
|
+
* @notice Returns a bool indicating if a new bid value is sufficiently
|
|
2869
|
+
* greater than an old bid value, to replace the old bid value.
|
|
2870
|
+
* @param oldBidValue Old bid value to compare
|
|
2871
|
+
* @param newBidValue New bid value to compare
|
|
2872
|
+
* @return isSufficientOutbid True if new bid is sufficiently greater than
|
|
2873
|
+
* old bid, false otherwise
|
|
2874
|
+
*/
|
|
2875
|
+
function _isSufficientOutbid(
|
|
2876
|
+
uint256 oldBidValue,
|
|
2877
|
+
uint256 newBidValue
|
|
2878
|
+
) private pure returns (bool) {
|
|
2879
|
+
if (oldBidValue > 0.5 ether) {
|
|
2880
|
+
// require new bid is at least 2.5% greater than removed minimum bid
|
|
2881
|
+
return newBidValue > (oldBidValue * 10250) / 10000;
|
|
2882
|
+
}
|
|
2883
|
+
// require new bid is at least 5% greater than removed minimum bid
|
|
2884
|
+
return newBidValue > (oldBidValue * 10500) / 10000;
|
|
2885
|
+
}
|
|
2886
|
+
|
|
2887
|
+
/**
|
|
2888
|
+
* @notice Returns the value of a bid in a given slot, in Wei.
|
|
2889
|
+
* @dev returns 0 if base price is zero
|
|
2890
|
+
* @param basePrice Base price (or reserve price) of the auction, in Wei
|
|
2891
|
+
* @param slotIndex Slot index to query
|
|
2892
|
+
* @return slotBidValue Value of a bid in the slot, in Wei
|
|
2893
|
+
*/
|
|
2894
|
+
function slotIndexToBidValue(
|
|
2895
|
+
uint88 basePrice,
|
|
2896
|
+
uint16 slotIndex
|
|
2897
|
+
) internal pure returns (uint256 slotBidValue) {
|
|
2898
|
+
// @dev for overflow safety, always revert if slotIndex >= NUM_SLOTS
|
|
2899
|
+
require(slotIndex < NUM_SLOTS, "Only slot index lt NUM_SLOTS");
|
|
2900
|
+
// use pseud-exponential pricing curve
|
|
2901
|
+
// multiply by two (via bit-shifting) for the number of entire
|
|
2902
|
+
// slots-per-price-double associated with the slot index
|
|
2903
|
+
// @dev overflow not possible due to typing, constants, and check above
|
|
2904
|
+
// (max(uint88) << (512 / 64)) < max(uint256)
|
|
2905
|
+
slotBidValue =
|
|
2906
|
+
uint256(basePrice) <<
|
|
2907
|
+
(slotIndex / SLOTS_PER_PRICE_DOUBLE);
|
|
2908
|
+
// perform a linear interpolation between partial half-life points, to
|
|
2909
|
+
// approximate the current place on a perfect exponential curve.
|
|
2910
|
+
// @dev overflow automatically checked in solidity 0.8, not expected
|
|
2911
|
+
slotBidValue +=
|
|
2912
|
+
(slotBidValue * (slotIndex % SLOTS_PER_PRICE_DOUBLE)) /
|
|
2913
|
+
SLOTS_PER_PRICE_DOUBLE;
|
|
2914
|
+
}
|
|
2915
|
+
|
|
2916
|
+
/**
|
|
2917
|
+
* @notice Return the storage struct for reading and writing. This library
|
|
2918
|
+
* uses a diamond storage pattern when managing storage.
|
|
2919
|
+
* @return storageStruct The RAMLibStorage struct.
|
|
2920
|
+
*/
|
|
2921
|
+
function s() private pure returns (RAMLibStorage storage storageStruct) {
|
|
2922
|
+
bytes32 position = RAM_LIB_STORAGE_POSITION;
|
|
2923
|
+
assembly ("memory-safe") {
|
|
2924
|
+
storageStruct.slot := position
|
|
2925
|
+
}
|
|
2926
|
+
}
|
|
2927
|
+
}
|