// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)pragmasolidity ^0.8.0;/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/abstractcontractContext{
function_msgSender() internalviewvirtualreturns (address) {
returnmsg.sender;
}
function_msgData() internalviewvirtualreturns (bytescalldata) {
returnmsg.data;
}
}
Contract Source Code
File 2 of 9: IAdminACLV0.sol
// SPDX-License-Identifier: LGPL-3.0-only// Created By: Art Blocks Inc.pragmasolidity ^0.8.0;interfaceIAdminACLV0{
/**
* @notice Token ID `_tokenId` minted to `_to`.
* @param previousSuperAdmin The previous superAdmin address.
* @param newSuperAdmin The new superAdmin address.
* @param genArt721CoreAddressesToUpdate Array of genArt721Core
* addresses to update to the new superAdmin, for indexing purposes only.
*/eventSuperAdminTransferred(addressindexed previousSuperAdmin,
addressindexed newSuperAdmin,
address[] genArt721CoreAddressesToUpdate
);
/// Type of the Admin ACL contract, e.g. "AdminACLV0"functionAdminACLType() externalviewreturns (stringmemory);
/// super admin addressfunctionsuperAdmin() externalviewreturns (address);
/**
* @notice Calls transferOwnership on other contract from this contract.
* This is useful for updating to a new AdminACL contract.
* @dev this function should be gated to only superAdmin-like addresses.
*/functiontransferOwnershipOn(address _contract,
address _newAdminACL
) external;
/**
* @notice Calls renounceOwnership on other contract from this contract.
* @dev this function should be gated to only superAdmin-like addresses.
*/functionrenounceOwnershipOn(address _contract) external;
/**
* @notice Checks if sender `_sender` is allowed to call function with selector
* `_selector` on contract `_contract`.
*/functionallowed(address _sender,
address _contract,
bytes4 _selector
) externalreturns (bool);
}
Contract Source Code
File 3 of 9: IERC165.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)pragmasolidity ^0.8.0;/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/interfaceIERC165{
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/functionsupportsInterface(bytes4 interfaceId) externalviewreturns (bool);
}
Contract Source Code
File 4 of 9: IERC721.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol)pragmasolidity ^0.8.0;import"../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/interfaceIERC721isIERC165{
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/eventTransfer(addressindexedfrom, addressindexed to, uint256indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/eventApproval(addressindexed owner, addressindexed approved, uint256indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/eventApprovalForAll(addressindexed owner, addressindexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/functionbalanceOf(address owner) externalviewreturns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/functionownerOf(uint256 tokenId) externalviewreturns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId,
bytescalldata data
) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId
) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/functiontransferFrom(addressfrom,
address to,
uint256 tokenId
) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/functionapprove(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/functionsetApprovalForAll(address operator, bool _approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/functiongetApproved(uint256 tokenId) externalviewreturns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/functionisApprovedForAll(address owner, address operator) externalviewreturns (bool);
}
Contract Source Code
File 5 of 9: IGenArt721CoreContractV3_Base.sol
// SPDX-License-Identifier: LGPL-3.0-only// Created By: Art Blocks Inc.pragmasolidity ^0.8.0;import"./IAdminACLV0.sol";
/// use the Royalty Registry's IManifold interface for token royaltiesimport"./IManifold.sol";
/**
* @title This interface is intended to house interface items that are common
* across all GenArt721CoreContractV3 flagship and derivative implementations.
* This interface extends the IManifold royalty interface in order to
* add support the Royalty Registry by default.
* @author Art Blocks Inc.
*/interfaceIGenArt721CoreContractV3_BaseisIManifold{
/**
* @notice Token ID `_tokenId` minted to `_to`.
*/eventMint(addressindexed _to, uint256indexed _tokenId);
/**
* @notice currentMinter updated to `_currentMinter`.
* @dev Implemented starting with V3 core
*/eventMinterUpdated(addressindexed _currentMinter);
/**
* @notice Platform updated on bytes32-encoded field `_field`.
*/eventPlatformUpdated(bytes32indexed _field);
/**
* @notice Project ID `_projectId` updated on bytes32-encoded field
* `_update`.
*/eventProjectUpdated(uint256indexed _projectId, bytes32indexed _update);
eventProposedArtistAddressesAndSplits(uint256indexed _projectId,
address _artistAddress,
address _additionalPayeePrimarySales,
uint256 _additionalPayeePrimarySalesPercentage,
address _additionalPayeeSecondarySales,
uint256 _additionalPayeeSecondarySalesPercentage
);
eventAcceptedArtistAddressesAndSplits(uint256indexed _projectId);
// version and type of the core contract// coreVersion is a string of the form "0.x.y"functioncoreVersion() externalviewreturns (stringmemory);
// coreType is a string of the form "GenArt721CoreV3"functioncoreType() externalviewreturns (stringmemory);
// owner (pre-V3 was named admin) of contract// this is expected to be an Admin ACL contract for V3functionowner() externalviewreturns (address);
// Admin ACL contract for V3, will be at the address owner()functionadminACLContract() externalreturns (IAdminACLV0);
// backwards-compatible (pre-V3) admin - equal to owner()functionadmin() externalviewreturns (address);
/**
* Function determining if _sender is allowed to call function with
* selector _selector on contract `_contract`. Intended to be used with
* peripheral contracts such as minters, as well as internally by the
* core contract itself.
*/functionadminACLAllowed(address _sender,
address _contract,
bytes4 _selector
) externalreturns (bool);
/// getter function of public variablefunctionstartingProjectId() externalviewreturns (uint256);
// getter function of public variablefunctionnextProjectId() externalviewreturns (uint256);
// getter function of public mappingfunctiontokenIdToProjectId(uint256 tokenId
) externalviewreturns (uint256 projectId);
// @dev this is not available in V0functionisMintWhitelisted(address minter) externalviewreturns (bool);
functionprojectIdToArtistAddress(uint256 _projectId
) externalviewreturns (addresspayable);
functionprojectIdToAdditionalPayeePrimarySales(uint256 _projectId
) externalviewreturns (addresspayable);
functionprojectIdToAdditionalPayeePrimarySalesPercentage(uint256 _projectId
) externalviewreturns (uint256);
functionprojectIdToSecondaryMarketRoyaltyPercentage(uint256 _projectId
) externalviewreturns (uint256);
functionprojectURIInfo(uint256 _projectId
) externalviewreturns (stringmemory projectBaseURI);
// @dev new function in V3functionprojectStateData(uint256 _projectId
)
externalviewreturns (uint256 invocations,
uint256 maxInvocations,
bool active,
bool paused,
uint256 completedTimestamp,
bool locked
);
functionprojectDetails(uint256 _projectId
)
externalviewreturns (stringmemory projectName,
stringmemory artist,
stringmemory description,
stringmemory website,
stringmemory license
);
functionprojectScriptDetails(uint256 _projectId
)
externalviewreturns (stringmemory scriptTypeAndVersion,
stringmemory aspectRatio,
uint256 scriptCount
);
functionprojectScriptByIndex(uint256 _projectId,
uint256 _index
) externalviewreturns (stringmemory);
functiontokenIdToHash(uint256 _tokenId) externalviewreturns (bytes32);
// function to set a token's hash (must be guarded)functionsetTokenHash_8PT(uint256 _tokenId, bytes32 _hash) external;
// @dev gas-optimized signature in V3 for `mint`functionmint_Ecf(address _to,
uint256 _projectId,
address _by
) externalreturns (uint256 tokenId);
}
Contract Source Code
File 6 of 9: IGenArt721CoreContractV3_Engine.sol
// SPDX-License-Identifier: LGPL-3.0-only// Created By: Art Blocks Inc.pragmasolidity ^0.8.0;import"./IAdminACLV0.sol";
import"./IGenArt721CoreContractV3_Base.sol";
interfaceIGenArt721CoreContractV3_EngineisIGenArt721CoreContractV3_Base{
// @dev new function in V3functiongetPrimaryRevenueSplits(uint256 _projectId,
uint256 _price
)
externalviewreturns (uint256 renderProviderRevenue_,
addresspayable renderProviderAddress_,
uint256 platformProviderRevenue_,
addresspayable platformProviderAddress_,
uint256 artistRevenue_,
addresspayable artistAddress_,
uint256 additionalPayeePrimaryRevenue_,
addresspayable additionalPayeePrimaryAddress_
);
// @dev The render provider primary sales payment addressfunctionrenderProviderPrimarySalesAddress()
externalviewreturns (addresspayable);
// @dev The platform provider primary sales payment addressfunctionplatformProviderPrimarySalesAddress()
externalviewreturns (addresspayable);
// @dev Percentage of primary sales allocated to the render providerfunctionrenderProviderPrimarySalesPercentage()
externalviewreturns (uint256);
// @dev Percentage of primary sales allocated to the platform providerfunctionplatformProviderPrimarySalesPercentage()
externalviewreturns (uint256);
// @dev The render provider secondary sales royalties payment addressfunctionrenderProviderSecondarySalesAddress()
externalviewreturns (addresspayable);
// @dev The platform provider secondary sales royalties payment addressfunctionplatformProviderSecondarySalesAddress()
externalviewreturns (addresspayable);
// @dev Basis points of secondary sales allocated to the render providerfunctionrenderProviderSecondarySalesBPS() externalviewreturns (uint256);
// @dev Basis points of secondary sales allocated to the platform providerfunctionplatformProviderSecondarySalesBPS()
externalviewreturns (uint256);
}
Contract Source Code
File 7 of 9: IManifold.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/// @dev Royalty Registry interface, used to support the Royalty Registry./// @dev Source: https://github.com/manifoldxyz/royalty-registry-solidity/blob/main/contracts/specs/IManifold.sol/// @author: manifold.xyz/**
* @dev Royalty interface for creator core classes
*/interfaceIManifold{
/**
* @dev Get royalites of a token. Returns list of receivers and basisPoints
*
* bytes4(keccak256('getRoyalties(uint256)')) == 0xbb3bafd6
*
* => 0xbb3bafd6 = 0xbb3bafd6
*/functiongetRoyalties(uint256 tokenId
) externalviewreturns (addresspayable[] memory, uint256[] memory);
}
Contract Source Code
File 8 of 9: Ownable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)pragmasolidity ^0.8.0;import"../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/abstractcontractOwnableisContext{
addressprivate _owner;
eventOwnershipTransferred(addressindexed previousOwner, addressindexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/modifieronlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/functionowner() publicviewvirtualreturns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/function_checkOwner() internalviewvirtual{
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/functionrenounceOwnership() publicvirtualonlyOwner{
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/functiontransferOwnership(address newOwner) publicvirtualonlyOwner{
require(newOwner !=address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/function_transferOwnership(address newOwner) internalvirtual{
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
Contract Source Code
File 9 of 9: ScribbleTogetherPaletteSelections.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.9;/* @title ScribbleTogetherPaletteSelections
* @author minimizer <me@minimizer.art>; https://www.minimizer.art/
*
* This is a helper contract for Scribble Together, a project to be released on Plottables.
* Scribble Together is an experiment where minimizer has created the scribbling algorithm
* and invited friends to create the palettes.
*
* During mint, palettes are randomly assigned. Once all mints are concluded, collectors can
* then select an alternative palette for their piece.
*
* This contract is responsible for:
* - collecting primary sales proceeds for the project (the "palette pool")
* - allowing collectors to change the palette of their piece, and keeping track of the selections
* - dividing up the proceeds of the palette pool based on collector's selections
*
* Inputs for this contract are:
* - ArtBlocks contract address and project id
* - Array of artist addresses for payment. The order of this list must match the order of palettes.
*
* Palette pool division calculation is:
* - proceedsPerPiece = funds stored in contract / number of pieces minted (from ArtBlocks contract)
* - prorataPercentage = 1 / # of palettes
* - proceedsPerArtist =
* proceedsPerPiece * prorataPercentage * (count of pieces collector did not change a palette)
* + proceedsPerPiece * (count of pieces collecor changed palette to that artist)
*
*
*
* Stages of the process are:
* 1) Initialization - the contract is deployed pointing to the specific ArtBlocks contract and
* project id, and includes the payment addresses of all artists (none of these settings can be changed)
* 2) Primaries collection & palette selection - while the primary sales occur, this contract can
* receive funds and also perform palette selection
* For any given piece, the owner of the token may select 'change palette'. The override is recorded,
* as well as counts updated per artist
* 3) Palette selection only - contract owner (minimizer) will pause primary mints on Plottables. At this point
* no further funds are expected.
* 4) Palette selection concluded - contract owner will flip the contract to stop further collection decisions.
* Two operations become available:
* a) GetPaletteDecisions: a summary of collector choices, to be re-integrated back into the art code
* b) DisperseFunds: a one-time operation to perform a full transfer of the palette pool to palette creators
*
*/import"@openzeppelin-4.7/contracts/access/Ownable.sol";
import"@openzeppelin-4.7/contracts/token/ERC721/IERC721.sol";
import'@artblocks/contracts/contracts/interfaces/v0.8.x/IGenArt721CoreContractV3_Engine.sol';
contractScribbleTogetherPaletteSelectionsisOwnable{
stringpublicconstant CONFIRMATION_FOR_STOPPING_PALETTE_SELECTION ='yes conclude palette selection';
stringpublicconstant CONFIRMATION_FOR_DISTRIBUTING_PAYOUTS ='yes distribute payouts';
IGenArt721CoreContractV3_Engine public plottablesContract;
uint256public projectId;
addresspayable[] public paletteCreators;
boolpublic paletteSelectionConcluded;
boolpublic payoutsDistributed;
uint256private numberOfTokensWithChangedPalettesTotal;
uint256[] private numberOfTokensWithChangedPalettesPerPalette;
mapping(uint=>uint) private tokenToOverriddenPalette; //zero means no override, otherwise the value is overridden palette - 1structPaletteSelection {
uint256 tokenId;
uint256 defaultPalette;
uint256 selectedPalette;
}
constructor(IGenArt721CoreContractV3_Engine _plottablesContract, uint256 _projectId, addresspayable[] memory _paletteCreators)
Ownable()
{
plottablesContract = _plottablesContract;
projectId = _projectId;
paletteCreators = _paletteCreators;
paletteSelectionConcluded =false;
payoutsDistributed =false;
numberOfTokensWithChangedPalettesPerPalette =newuint256[](paletteCreators.length);
require(plottablesContract.projectIdToArtistAddress(projectId) ==msg.sender, 'Deployer must be project artist');
require(numInvocations() ==0, 'Project cannot have any mints yet');
require(paletteCreators.length>0, 'Need at least one palette');
}
receive() externalpayablerequirePayoutsNotDistributed{}
functionplottablesTokenIdFor(uint256 _tokenId) privateviewreturns (uint256) {
return projectId *1e6+ _tokenId;
}
functionnumPalettes() publicviewreturns (uint256) {
return paletteCreators.length;
}
functionnumInvocations() publicviewreturns (uint256) {
(uint256 invocations, , , , , ) = plottablesContract.projectStateData(projectId);
return invocations;
}
functionhashForTokenId(uint256 _tokenId) publicviewreturns (bytes32) {
require(_tokenId < numInvocations(), 'Invalid token');
return plottablesContract.tokenIdToHash(plottablesTokenIdFor(_tokenId));
}
functiondefaultPaletteForTokenId(uint256 _tokenId) publicviewreturns (uint256) {
return calculateDefaultPaletteForHash(hashForTokenId(_tokenId), paletteCreators.length);
}
functionselectedPaletteForTokenId(uint256 _tokenId) publicviewreturns (uint256) {
return paletteSelectionForTokenId(_tokenId).selectedPalette;
}
functionpaletteSelectionForTokenId(uint256 _tokenId) privateviewreturns (PaletteSelection memory selection) {
selection.tokenId = _tokenId;
selection.defaultPalette = defaultPaletteForTokenId(_tokenId);
uint256 paletteSelection = tokenToOverriddenPalette[_tokenId];
if(paletteSelection ==0) {
selection.selectedPalette = selection.defaultPalette;
}
else {
selection.selectedPalette = paletteSelection-1;
}
}
functionpaletteSelectionsInRange(uint256 _firstTokenId, uint256 _numTokens) publicviewreturns (PaletteSelection[] memory selections) {
selections =new PaletteSelection[](_numTokens);
for(uint i =0; i < _numTokens; i++) {
selections[i] = paletteSelectionForTokenId(i + _firstTokenId);
}
}
functionallPaletteSelections() publicviewreturns (PaletteSelection[] memory selections) {
return paletteSelectionsInRange(0, numInvocations());
}
functionnumTokensOverridingByPalette() publicviewreturns (uint256[] memory result) {
return numberOfTokensWithChangedPalettesPerPalette;
}
functionselectPaletteForTokenId(uint256 _tokenId, uint256 _newPalette) public{
require(IERC721(address(plottablesContract)).ownerOf(plottablesTokenIdFor(_tokenId)) ==msg.sender, 'Not owner of token');
uint256 defaultPalette = defaultPaletteForTokenId(_tokenId);
uint256 currentPalette = selectedPaletteForTokenId(_tokenId);
if(_newPalette != currentPalette) {
if(currentPalette != defaultPalette) {
numberOfTokensWithChangedPalettesPerPalette[currentPalette]--;
numberOfTokensWithChangedPalettesTotal--;
}
if(_newPalette != defaultPalette) {
tokenToOverriddenPalette[_tokenId] = _newPalette+1;
numberOfTokensWithChangedPalettesPerPalette[_newPalette]++;
numberOfTokensWithChangedPalettesTotal++;
}
else {
tokenToOverriddenPalette[_tokenId] =0;
}
}
}
functionnumDefaultInvocations() publicviewreturns (uint256) {
return numInvocations() - numberOfTokensWithChangedPalettesTotal;
}
functionnumChangedInvocations() publicviewreturns (uint256) {
return numberOfTokensWithChangedPalettesTotal;
}
functioncalculatePayouts() publicviewreturns (uint256[] memory payouts) {
uint256 tokensCount = numInvocations();
require(tokensCount >0, 'No tokens');
uint256 palettesCount = paletteCreators.length;
uint256 totalDistribution =address(this).balance;
uint256 cumulativeDistribution =0;
uint256 proRataDistributionPerPalette = totalDistribution * numDefaultInvocations() / tokensCount / palettesCount;
payouts =newuint256[](palettesCount);
for(uint256 thisPalette =0; thisPalette < palettesCount -1; thisPalette++) {
uint256 thisDistributionForTokensSelectingThisPalette = totalDistribution * numberOfTokensWithChangedPalettesPerPalette[thisPalette] / tokensCount;
uint256 thisDistribution = proRataDistributionPerPalette + thisDistributionForTokensSelectingThisPalette;
payouts[thisPalette] = thisDistribution;
cumulativeDistribution += thisDistribution;
}
payouts[payouts.length-1] = totalDistribution - cumulativeDistribution;
}
functionconcludePaletteSelection(stringmemory _confirmation) publiconlyOwnerrequireValidConfirmation(CONFIRMATION_FOR_STOPPING_PALETTE_SELECTION, _confirmation) {
(,,,bool paused,,) = plottablesContract.projectStateData(projectId);
require(paused ==true, 'Project is not paused');
paletteSelectionConcluded =true;
}
functiondistributePayouts(stringmemory _confirmation) publiconlyOwnerrequireValidConfirmation(CONFIRMATION_FOR_DISTRIBUTING_PAYOUTS, _confirmation)
requirePayoutsNotDistributed{
require(paletteSelectionConcluded, 'Palette selection not concluded');
uint256[] memory payouts = calculatePayouts();
for(uint256 i=0; i<payouts.length; i++) {
(bool sent, ) =payable(paletteCreators[i]).call{value: payouts[i]}("");
require(sent, "Failed to send");
}
payoutsDistributed =true;
}
/* logic to match this in JavaScript:
*
* const hashToInt = hashBytes32 => parseInt(hashBytes32.slice(-8), 16)
* const hashToPalette = (hashBytes32, numPalettes) => hashToInt(hashBytes32) % numPalettes
*/functioncalculateDefaultPaletteForHash(bytes32 _hash, uint256 _numPalettes) publicpurereturns (uint256) {
uint256 intOfHash =uint256(uint32(uint256(_hash)));
return intOfHash % _numPalettes;
}
modifierrequireValidConfirmation(stringmemory expectedConfirmation, stringmemory actualConfirmation) {
require(
keccak256(abi.encodePacked(expectedConfirmation)) ==keccak256(abi.encodePacked(actualConfirmation)),
"Invalid confirmation string provided"
);
_; // continue execution
}
modifierrequirePayoutsNotDistributed() {
require(!payoutsDistributed, 'Payouts already distributed');
_; // continue execution
}
}