Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
BaseContest
Compiler Version
v0.8.22+commit.4fc1097e
Optimization Enabled:
Yes with 750 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0
/// @title A Revolution contest
/*********************************
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░█████████░░█████████░░░ *
* ░░░░░░██░░░████░░██░░░████░░░ *
* ░░██████░░░████████░░░████░░░ *
* ░░██░░██░░░████░░██░░░████░░░ *
* ░░██░░██░░░████░░██░░░████░░░ *
* ░░░░░░█████████░░█████████░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
*********************************/
pragma solidity ^0.8.22;
import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import { Ownable2StepUpgradeable } from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
import { IBaseContest } from "./IBaseContest.sol";
import { IWETH } from "../../interfaces/IWETH.sol";
import { ICultureIndex } from "../../interfaces/ICultureIndex.sol";
import { IRevolutionPointsEmitter } from "../../interfaces/IRevolutionPointsEmitter.sol";
import { RevolutionVersion } from "../../version/RevolutionVersion.sol";
import { ISplitMain } from "@cobuild/splits/src/interfaces/ISplitMain.sol";
import { UUPS } from "@cobuild/utility-contracts/src/proxy/UUPS.sol";
import { IUpgradeManager } from "@cobuild/utility-contracts/src/interfaces/IUpgradeManager.sol";
import { RevolutionRewards } from "@cobuild/protocol-rewards/src/abstract/RevolutionRewards.sol";
import { ISplitMain } from "@cobuild/splits/src/interfaces/ISplitMain.sol";
contract BaseContest is
IBaseContest,
RevolutionVersion,
UUPS,
PausableUpgradeable,
ReentrancyGuardUpgradeable,
OwnableUpgradeable,
RevolutionRewards
{
/// @notice constant to scale uints into percentages (1e6 == 100%)
uint256 public constant PERCENTAGE_SCALE = 1e6;
// The address of the WETH contract
address public WETH;
// The split of winning proceeds that is sent to winners
uint256 public entropyRate;
// The address of th account to receive builder rewards
address public builderReward;
// The start time of the contest
uint256 public startTime;
// The end time of the contest
uint256 public endTime;
// Whether the contest has been fully paid out
bool public paidOut;
// The current index of the payout splits. This is used to track which payout split is next to be paid out.
uint256 public payoutIndex;
// The balance of the contract at the time the first winner is paid out
uint256 public initialPayoutBalance;
// The SplitMain contract
ISplitMain public splitMain;
// The CultureIndex contract holding submissions
ICultureIndex public cultureIndex;
// The contest payout splits scaled by PERCENTAGE_SCALE in descending order
uint256[] public payoutSplits;
// When the contest has been fully paid out, stores the payout split accounts
// for each winner
mapping(uint256 => address) public payoutSplitAccounts;
/// ///
/// IMMUTABLES ///
/// ///
/// @notice The contract upgrade manager
IUpgradeManager public immutable manager;
/// ///
/// CONSTRUCTOR ///
/// ///
/// @param _manager The contract upgrade manager address
/// @param _protocolRewards The protocol rewards contract address
/// @param _protocolFeeRecipient The protocol fee recipient addres
constructor(
address _manager,
address _protocolRewards,
address _protocolFeeRecipient
) payable RevolutionRewards(_protocolRewards, _protocolFeeRecipient) initializer {
if (_manager == address(0)) revert ADDRESS_ZERO();
if (_protocolRewards == address(0)) revert ADDRESS_ZERO();
if (_protocolFeeRecipient == address(0)) revert ADDRESS_ZERO();
manager = IUpgradeManager(_manager);
}
/// ///
/// INITIALIZER ///
/// ///
/**
* @notice Initialize the contest and base contracts,
* populate configuration values, and pause the contract.
* @dev This function can only be called once.
* @param _initialOwner The address of the owner.
* @param _splitMain The address of the SplitMain splits creator contract.
* @param _cultureIndex The address of the CultureIndex contract holding submissions.
* @param _builderReward The address of the account to receive builder rewards.
* @param _weth The address of the WETH contract
* @param _baseContestParams The contest params for the contest.
*/
function initialize(
address _initialOwner,
address _splitMain,
address _cultureIndex,
address _builderReward,
address _weth,
IBaseContest.BaseContestParams calldata _baseContestParams
) external initializer {
if (msg.sender != address(manager)) revert NOT_MANAGER();
if (_weth == address(0)) revert ADDRESS_ZERO();
__Pausable_init();
__ReentrancyGuard_init();
__Ownable_init(_initialOwner);
uint256 numPayoutSplits = _baseContestParams.payoutSplits.length;
// check payout splits sum to PERCENTAGE_SCALE and ensure descending order
uint256 sum;
uint256 previousSplit = type(uint256).max;
for (uint256 i = 0; i < numPayoutSplits; i++) {
uint256 currentSplit = _baseContestParams.payoutSplits[i];
sum += currentSplit;
if (currentSplit > previousSplit) revert PAYOUT_SPLITS_NOT_DESCENDING();
previousSplit = currentSplit;
}
if (sum != PERCENTAGE_SCALE) revert INVALID_PAYOUT_SPLITS();
// set contracts
WETH = _weth;
builderReward = _builderReward;
splitMain = ISplitMain(_splitMain);
cultureIndex = ICultureIndex(_cultureIndex);
// set creator payout params
entropyRate = _baseContestParams.entropyRate;
startTime = _baseContestParams.startTime;
endTime = _baseContestParams.endTime;
payoutSplits = _baseContestParams.payoutSplits;
}
/**
* @notice Set the split of that is sent to the creator as ether
* @dev Only callable by the owner.
* @param _entropyRate New entropy rate, scaled by PERCENTAGE_SCALE.
*/
function setEntropyRate(uint256 _entropyRate) external onlyOwner {
if (_entropyRate > PERCENTAGE_SCALE) revert INVALID_ENTROPY_RATE();
entropyRate = _entropyRate;
emit EntropyRateUpdated(_entropyRate);
}
/**
* @notice Unpause the BaseContest
* @dev This function can only be called by the owner when the
* contract is paused.
*/
function unpause() external override onlyOwner {
_unpause();
}
/**
* @notice Emergency withdraw ETH from the contract to the points emitter owner.
* @dev This function can only be called by the owner.
*/
function emergencyWithdraw() external onlyOwner nonReentrant {
// Ensure the contract has enough ETH to transfer
if (address(this).balance == 0) revert NO_BALANCE_TO_WITHDRAW();
// Transfer the ETH to the points emitter owner
_safeTransferETHWithFallback(
Ownable2StepUpgradeable(address(ISplitMain(splitMain).pointsEmitter())).owner(),
address(this).balance
);
}
/**
* @notice Withdraw ETH balance to points emitter owner (DAO executor).
* @dev This function can be called by anyone if the contest is over.
* @dev Useful eg: in case the contest contract is used as the recipient of free mint protocol rewards
* for submissions, and members want to withdraw the rewards post-payout to the DAO executor.
*/
function withdrawToPointsEmitterOwner() external nonReentrant {
// Ensure the contract has enough ETH to transfer
if (address(this).balance == 0) revert NO_BALANCE_TO_WITHDRAW();
// Ensure the contest has been paid out, since anyone can call this function
if (!paidOut) revert CONTEST_NOT_ENDED();
// Transfer the ETH to the points emitter owner
_safeTransferETHWithFallback(
Ownable2StepUpgradeable(address(ISplitMain(splitMain).pointsEmitter())).owner(),
address(this).balance
);
}
/**
* @notice Pause the contest to prevent payouts.
* @dev This function can only be called by the owner when the
* contract is unpaused.
*/
function pause() external override onlyOwner {
_pause();
}
/**
* @notice Pays out the next up contest winner, the top voted submission in the CultureIndex
* @dev Only callable by the owner.
*/
function payoutNextSubmission() internal {
try cultureIndex.dropTopVotedPiece() returns (ICultureIndex.ArtPieceCondensed memory artPiece) {
// get index to pay out
uint256 currentPayoutIndex = payoutIndex;
// increment payout index for next iteration
payoutIndex++;
// if we have reached the end of the payoutSplits, set paidOut to true
// effectively the same as currentPayoutIndex == payoutSplits.length - 1
// (payoutIndex starts at 0)
if (payoutIndex == payoutSplits.length) {
// set true so the payouts stop on the next loop iteration in `payOutWinners`
paidOut = true;
}
uint256 numCreators = artPiece.creators.length;
address[] memory accounts = new address[](numCreators);
uint32[] memory percentAllocations = new uint32[](numCreators);
// iterate over numCreators and populate accounts and percentAllocations
for (uint256 i = 0; i < numCreators; i++) {
accounts[i] = artPiece.creators[i].creator;
// PERCENTAGE_SCALE is 1e6, CultureIndex scale is 1e4, so we multiply by 1e2
percentAllocations[i] = uint32(artPiece.creators[i].bps * 1e2);
}
// Create split contract
address splitToPay = splitMain.createSplit(
ISplitMain.PointsData({
pointsPercent: uint32(PERCENTAGE_SCALE - entropyRate),
accounts: accounts,
percentAllocations: percentAllocations
}),
accounts,
percentAllocations,
0,
// controller set to owner of SplitMain PointsEmitter - DAO executor
Ownable2StepUpgradeable(address(ISplitMain(splitMain).pointsEmitter())).owner()
);
// Store the split contract address for the payout
payoutSplitAccounts[currentPayoutIndex] = splitToPay;
// calculate payout based on currentPayoutIndex
uint256 payout = (initialPayoutBalance * payoutSplits[currentPayoutIndex]) / PERCENTAGE_SCALE;
// Send protocol rewards
uint256 payoutMinusFee = _handleRewardsAndGetValueToSend(
payout,
builderReward,
address(0),
cultureIndex.getPieceById(artPiece.pieceId).sponsor
);
emit WinnerPaid(
artPiece.pieceId,
accounts,
payoutMinusFee,
payout - payoutMinusFee,
payoutSplits[currentPayoutIndex],
currentPayoutIndex
);
// transfer ETH to split contract based on currentPayoutIndex
_safeTransferETHWithFallback(splitToPay, payoutMinusFee);
} catch {
revert("dropTopVotedPiece failed");
}
}
/**
* @notice Fetch an art piece by its ID.
* @param pieceId The ID of the art piece.
* @return The ArtPiece struct associated with the given ID.
*/
function getArtPieceById(uint256 pieceId) external view returns (ICultureIndex.ArtPiece memory) {
return cultureIndex.getPieceById(pieceId);
}
/**
* @notice Returns true or false depending on whether the top voted piece in the culture index meets quorum
* @return True if the top voted piece meets quorum, false otherwise
*/
function topVotedPieceMeetsQuorum() external view returns (bool) {
return cultureIndex.topVotedPieceMeetsQuorum();
}
/**
* @notice Returns the payout splits of the contest
* @return The payout splits of the contest
*/
function getPayoutSplits() external view returns (uint256[] memory) {
return payoutSplits;
}
/**
* @notice Returns the payout splits count
* @return The payout splits count
*/
function getPayoutSplitsCount() external view returns (uint256) {
return payoutSplits.length;
}
/**
* @notice Pay out the contest winners
* @param _payoutCount The number of winners to pay out. Needs to be adjusted based on gas requirements.
*/
function payOutWinners(uint256 _payoutCount) external nonReentrant whenNotPaused {
// ensure paying out at least one winner
if (_payoutCount == 0) revert NO_COUNT_SPECIFIED();
// Ensure the contest has not already paid out fully
if (paidOut) revert CONTEST_ALREADY_PAID_OUT();
// Ensure the contest has ended
//slither-disable-next-line timestamp
if (block.timestamp < endTime) revert CONTEST_NOT_ENDED();
// Set initial balance if not already set
if (initialPayoutBalance == 0) {
uint256 contractBalance = address(this).balance;
// if there's no balance to pay, don't let contest payout go through
if (contractBalance == 0) revert NO_BALANCE_TO_PAYOUT();
// store balance to pay out
initialPayoutBalance = contractBalance;
}
// pay out _payoutCount winners
for (uint256 i = 0; i < _payoutCount; i++) {
// if the contest is paid out - break
if (paidOut) break;
// while the contract has balance and the contest has not been fully paid out
payoutNextSubmission();
}
}
/// @notice Transfer ETH/WETH from the contract
/// @param _to The recipient address
/// @param _amount The amount transferring
function _safeTransferETHWithFallback(address _to, uint256 _amount) private {
// Ensure the contract has enough ETH to transfer
if (address(this).balance < _amount) revert("Insufficient balance");
// Used to store if the transfer succeeded
bool success;
assembly {
// Transfer ETH to the recipient
// Limit the call to 30,000 gas
success := call(30000, _to, _amount, 0, 0, 0, 0)
}
// If the transfer failed:
if (!success) {
// Wrap as WETH
IWETH(WETH).deposit{ value: _amount }();
// Transfer WETH instead
bool wethSuccess = IWETH(WETH).transfer(_to, _amount);
// Ensure successful transfer
if (!wethSuccess) revert("WETH transfer failed");
}
}
receive() external payable {}
fallback() external payable {}
/// ///
/// BASE CONTEST UPGRADE ///
/// ///
/// @notice Ensures the caller is authorized to upgrade the contract and the new implementation is valid
/// @dev This function is called in `upgradeTo` & `upgradeToAndCall`
/// @param _newImpl The new implementation address
function _authorizeUpgrade(address _newImpl) internal view override onlyOwner whenPaused {
// Ensure the new implementation is registered by the Builder DAO
if (!manager.isRegisteredUpgrade(_getImplementation(), _newImpl)) revert INVALID_UPGRADE(_newImpl);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol)
pragma solidity ^0.8.20;
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
/// @custom:storage-location erc7201:openzeppelin.storage.Pausable
struct PausableStorage {
bool _paused;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Pausable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant PausableStorageLocation = 0xcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300;
function _getPausableStorage() private pure returns (PausableStorage storage $) {
assembly {
$.slot := PausableStorageLocation
}
}
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
/**
* @dev The operation failed because the contract is paused.
*/
error EnforcedPause();
/**
* @dev The operation failed because the contract is not paused.
*/
error ExpectedPause();
/**
* @dev Initializes the contract in unpaused state.
*/
function __Pausable_init() internal onlyInitializing {
__Pausable_init_unchained();
}
function __Pausable_init_unchained() internal onlyInitializing {
PausableStorage storage $ = _getPausableStorage();
$._paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
PausableStorage storage $ = _getPausableStorage();
return $._paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
if (paused()) {
revert EnforcedPause();
}
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
if (!paused()) {
revert ExpectedPause();
}
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
PausableStorage storage $ = _getPausableStorage();
$._paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
PausableStorage storage $ = _getPausableStorage();
$._paused = false;
emit Unpaused(_msgSender());
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuardUpgradeable is Initializable {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
/// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard
struct ReentrancyGuardStorage {
uint256 _status;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;
function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {
assembly {
$.slot := ReentrancyGuardStorageLocation
}
}
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
$._status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// On the first call to nonReentrant, _status will be NOT_ENTERED
if ($._status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
$._status = ENTERED;
}
function _nonReentrantAfter() private {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
$._status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
return $._status == ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.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.
*
* The initial owner is set to the address provided by the deployer. 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.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
/// @custom:storage-location erc7201:openzeppelin.storage.Ownable
struct OwnableStorage {
address _owner;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;
function _getOwnableStorage() private pure returns (OwnableStorage storage $) {
assembly {
$.slot := OwnableStorageLocation
}
}
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
function __Ownable_init(address initialOwner) internal onlyInitializing {
__Ownable_init_unchained(initialOwner);
}
function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
OwnableStorage storage $ = _getOwnableStorage();
return $._owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
OwnableStorage storage $ = _getOwnableStorage();
address oldOwner = $._owner;
$._owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol)
pragma solidity ^0.8.20;
import {OwnableUpgradeable} from "./OwnableUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is specified at deployment time in the constructor for `Ownable`. This
* can later be changed with {transferOwnership} and {acceptOwnership}.
*
* This module is used through inheritance. It will make available all functions
* from parent (Ownable).
*/
abstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable {
/// @custom:storage-location erc7201:openzeppelin.storage.Ownable2Step
struct Ownable2StepStorage {
address _pendingOwner;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable2Step")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant Ownable2StepStorageLocation = 0x237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c00;
function _getOwnable2StepStorage() private pure returns (Ownable2StepStorage storage $) {
assembly {
$.slot := Ownable2StepStorageLocation
}
}
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
function __Ownable2Step_init() internal onlyInitializing {
}
function __Ownable2Step_init_unchained() internal onlyInitializing {
}
/**
* @dev Returns the address of the pending owner.
*/
function pendingOwner() public view virtual returns (address) {
Ownable2StepStorage storage $ = _getOwnable2StepStorage();
return $._pendingOwner;
}
/**
* @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual override onlyOwner {
Ownable2StepStorage storage $ = _getOwnable2StepStorage();
$._pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual override {
Ownable2StepStorage storage $ = _getOwnable2StepStorage();
delete $._pendingOwner;
super._transferOwnership(newOwner);
}
/**
* @dev The new owner accepts the ownership transfer.
*/
function acceptOwnership() public virtual {
address sender = _msgSender();
if (pendingOwner() != sender) {
revert OwnableUnauthorizedAccount(sender);
}
_transferOwnership(sender);
}
}// SPDX-License-Identifier: GPL-3.0
/// @title Interface for Revolution Auction Houses
/*********************************
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░█████████░░█████████░░░ *
* ░░░░░░██░░░████░░██░░░████░░░ *
* ░░██████░░░████████░░░████░░░ *
* ░░██░░██░░░████░░██░░░████░░░ *
* ░░██░░██░░░████░░██░░░████░░░ *
* ░░░░░░█████████░░█████████░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
*********************************/
pragma solidity ^0.8.22;
import { IUpgradeManager } from "@cobuild/utility-contracts/src/interfaces/IUpgradeManager.sol";
interface IBaseContestEvents {
event WinnerPaid(
uint256 indexed pieceId,
address[] winners,
uint256 amount,
uint256 protocolRewardsAmount,
uint256 payoutSplit,
uint256 payoutIndex
);
event EntropyRateUpdated(uint256 rate);
}
interface IBaseContest is IBaseContestEvents {
/// ///
/// ERRORS ///
/// ///
/// @dev Reverts if the function caller is not the manager.
error NOT_MANAGER();
/// @dev Reverts if address 0 is passed but not allowed
error ADDRESS_ZERO();
/// @dev Reverts if > PERCENTAGE_SCALE
error INVALID_ENTROPY_RATE();
/// @dev Reverts if the top voted piece does not meet quorum.
error QUORUM_NOT_MET();
/// @dev Reverts if the contest has already been paid out
error CONTEST_ALREADY_PAID_OUT();
/// @dev Reverts if the contest has not ended
error CONTEST_NOT_ENDED();
/// @dev Reverts if payout splits do not sum to PERCENTAGE_SCALE
error INVALID_PAYOUT_SPLITS();
/// @dev Reverts if payoutSplits are not descending
error PAYOUT_SPLITS_NOT_DESCENDING();
/// @dev Reverts if trying to payout contest with no balance
error NO_BALANCE_TO_PAYOUT();
/// @dev Reverts if trying to payout with no winners specified
error NO_COUNT_SPECIFIED();
/// @dev Reverts if no balance to withdraw
error NO_BALANCE_TO_WITHDRAW();
function setEntropyRate(uint256 _entropyRate) external;
function WETH() external view returns (address);
function manager() external returns (IUpgradeManager);
function unpause() external;
function pause() external;
function getPayoutSplits() external view returns (uint256[] memory);
function getPayoutSplitsCount() external view returns (uint256);
function startTime() external view returns (uint256);
function endTime() external view returns (uint256);
/// @notice The contest parameters
/// @param entropyRate The entropy rate of each contest - the portion of the creator's share that is directly sent to the creator in ETH
/// @param endTime The end time of the contest.
/// @param startTime The start time of the contest.
/// @param payoutSplits How to split the prize pool between the winners
struct BaseContestParams {
uint256 entropyRate;
uint256 startTime;
uint256 endTime;
uint256[] payoutSplits;
}
/**
* @notice Initialize the auction house and base contracts.
* @param initialOwner The address of the owner.
* @param splitMain The address of the SplitMain splits creator contract.
* @param cultureIndex The address of the CultureIndex contract holding submissions.
* @param builderReward The address of the account to receive builder rewards.
* @param weth The address of the WETH contract.
* @param contestParams The auction params for auctions.
*/
function initialize(
address initialOwner,
address splitMain,
address cultureIndex,
address builderReward,
address weth,
BaseContestParams calldata contestParams
) external;
}// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.22;
interface IWETH {
function deposit() external payable;
function withdraw(uint256 wad) external;
function transfer(address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.22;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { ERC721CheckpointableUpgradeable } from "../base/ERC721CheckpointableUpgradeable.sol";
import { IRevolutionBuilder } from "./IRevolutionBuilder.sol";
/**
* @title ICultureIndexEvents
* @dev This interface defines the events for the CultureIndex contract.
*/
interface ICultureIndexEvents {
event ERC721VotingTokenUpdated(ERC721CheckpointableUpgradeable ERC721VotingToken);
event ERC721VotingTokenLocked();
/**
* @dev Emitted when a new piece is created.
* @param pieceId Unique identifier for the newly created piece.
* @param sponsor Address that created the piece.
* @param metadata Metadata associated with the art piece.
* @param creators Creators of the art piece.
*/
event PieceCreated(
uint256 indexed pieceId,
address indexed sponsor,
ICultureIndex.ArtPieceMetadata metadata,
ICultureIndex.CreatorBps[] creators
);
/**
* @dev Emitted when a top-voted piece is dropped or released.
* @param pieceId Unique identifier for the dropped piece.
* @param remover Address that initiated the drop.
*/
event PieceDropped(uint256 indexed pieceId, address indexed remover);
/**
* @dev Emitted when a vote is cast for a piece.
* @param pieceId Unique identifier for the piece being voted for.
* @param voter Address of the voter.
* @param weight Weight of the vote.
* @param totalWeight Total weight of votes for the piece after the new vote.
*/
event VoteCast(uint256 indexed pieceId, address indexed voter, uint256 weight, uint256 totalWeight);
/// @notice Emitted when quorum votes basis points is set
event QuorumVotesBPSSet(uint256 oldQuorumVotesBPS, uint256 newQuorumVotesBPS);
/// @notice Emitted when min voting power to vote is set
event MinVotingPowerToVoteSet(uint256 oldMinVotingPowerToVote, uint256 newMinVotingPowerToVote);
/// @notice Emitted when min voting power to create is set
event MinVotingPowerToCreateSet(uint256 oldMinVotingPowerToCreate, uint256 newMinVotingPowerToCreate);
}
/**
* @title ICultureIndex
* @dev This interface defines the methods for the CultureIndex contract for art piece management and voting.
*/
interface ICultureIndex is ICultureIndexEvents {
/// ///
/// ERRORS ///
/// ///
/// @dev Reverts if the lengths of the provided arrays do not match.
error ARRAY_LENGTH_MISMATCH();
/// @dev Reverts if the specified piece ID is invalid or out of range.
error INVALID_PIECE_ID();
/// @dev Reverts if the art piece has already been dropped.
error ALREADY_DROPPED();
/// @dev Reverts if the voter has already voted for this piece.
error ALREADY_VOTED();
/// @dev Reverts if the voter's weight is below the minimum required vote weight.
error WEIGHT_TOO_LOW();
/// @dev Reverts if the voting signature is invalid
error INVALID_SIGNATURE();
/// @dev Reverts if the function caller is not the manager.
error NOT_MANAGER();
/// @dev Reverts if the quorum votes basis points exceed the maximum allowed value.
error INVALID_QUORUM_BPS();
/// @dev Reverts if the ERC721 voting token weight is invalid (i.e., 0).
error INVALID_ERC721_VOTING_WEIGHT();
/// @dev Reverts if the ERC20 voting token weight is invalid (i.e., 0).
error INVALID_ERC20_VOTING_WEIGHT();
/// @dev Reverts if the total vote weights do not meet the required quorum votes for a piece to be dropped.
error DOES_NOT_MEET_QUORUM();
/// @dev Reverts if the function caller is not the authorized dropper admin.
error NOT_DROPPER_ADMIN();
/// @dev Reverts if the voting signature has expired
error SIGNATURE_EXPIRED();
/// @dev Reverts if the culture index heap is empty.
error CULTURE_INDEX_EMPTY();
/// @dev Reverts if address 0 is passed but not allowed
error ADDRESS_ZERO();
/// @dev Reverts if art piece metadata is invalid
error INVALID_MEDIA_TYPE();
/// @dev Reverts if art piece image is invalid
error INVALID_IMAGE();
/// @dev Reverts if art piece animation url is invalid
error INVALID_ANIMATION_URL();
/// @dev Reverts if art piece text is invalid
error INVALID_TEXT();
/// @dev Reverts if art piece description is invalid
error INVALID_DESCRIPTION();
/// @dev Reverts if art piece name is invalid
error INVALID_NAME();
/// @dev Reverts if substring is invalid
error INVALID_SUBSTRING();
/// @dev Reverts if bps does not sum to 10000
error INVALID_BPS_SUM();
/// @dev Reverts if max number of creators is exceeded
error MAX_NUM_CREATORS_EXCEEDED();
/// @dev Reverts if the creator's BPS specified is invalid
error INVALID_CREATOR_BPS();
/// ///
/// CONSTANTS ///
/// ///
// Struct defining maximum lengths for art piece data
struct PieceMaximums {
uint256 name;
uint256 description;
uint256 image;
uint256 text;
uint256 animationUrl;
}
// Enum representing file type requirements for art pieces.
enum RequiredMediaPrefix {
MIXED, // IPFS or SVG
SVG,
IPFS
}
// Enum representing different media types for art pieces.
enum MediaType {
NONE, // never used by end user, only used in CultureIndex when using requriedMediaType
IMAGE,
ANIMATION,
AUDIO,
TEXT
}
// Struct defining metadata for an art piece.
struct ArtPieceMetadata {
string name;
string description;
MediaType mediaType;
string image;
string text;
string animationUrl;
}
// Struct representing a creator of an art piece and their basis points.
struct CreatorBps {
address creator;
uint256 bps;
}
/**
* @dev Struct defining an art piece.
*@param pieceId Unique identifier for the piece.
* @param metadata Metadata associated with the art piece.
* @param creators Creators of the art piece.
* @param sponsor Address that created the piece.
* @param isDropped Boolean indicating if the piece has been dropped.
* @param creationBlock Block number when the piece was created.
*/
struct ArtPiece {
uint256 pieceId;
ArtPieceMetadata metadata;
CreatorBps[] creators;
address sponsor;
bool isDropped;
uint256 creationBlock;
}
/**
* @dev Struct defining an art piece for use in a token
*@param pieceId Unique identifier for the piece.
* @param creators Creators of the art piece.
* @param sponsor Address that created the piece.
*/
struct ArtPieceCondensed {
uint256 pieceId;
CreatorBps[] creators;
address sponsor;
}
// Constant for max number of creators
function MAX_NUM_CREATORS() external view returns (uint256);
// Struct representing a voter and their weight for a specific art piece.
struct Vote {
address voterAddress;
uint256 weight;
}
/**
* @notice Returns the total number of art pieces.
* @return The total count of art pieces.
*/
function pieceCount() external view returns (uint256);
/**
* @notice Checks if a specific voter has already voted for a given art piece.
* @param pieceId The ID of the art piece.
* @param voter The address of the voter.
* @return A boolean indicating if the voter has voted for the art piece.
*/
function hasVoted(uint256 pieceId, address voter) external view returns (bool);
/**
* @notice Allows a user to create a new art piece.
* @param metadata The metadata associated with the art piece.
* @param creatorArray An array of creators and their associated basis points.
* @return The ID of the newly created art piece.
*/
function createPiece(ArtPieceMetadata memory metadata, CreatorBps[] memory creatorArray) external returns (uint256);
/**
* @notice Allows a user to vote for a specific art piece.
* @param pieceId The ID of the art piece.
*/
function vote(uint256 pieceId) external;
/**
* @notice Allows a user to vote for many art pieces.
* @param pieceIds The ID of the art pieces.
*/
function voteForMany(uint256[] calldata pieceIds) external;
/**
* @notice Allows a user to vote for a specific art piece using a signature.
* @param from The address of the voter.
* @param pieceIds The ID of the art piece.
* @param deadline The deadline for the vote.
* @param v The v component of the signature.
* @param r The r component of the signature.
* @param s The s component of the signature.
*/
function voteForManyWithSig(
address from,
uint256[] calldata pieceIds,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @notice Allows users to vote for a specific art piece using a signature.
* @param from The address of the voter.
* @param pieceIds The ID of the art piece.
* @param deadline The deadline for the vote.
* @param v The v component of the signature.
* @param r The r component of the signature.
* @param s The s component of the signature.
*/
function batchVoteForManyWithSig(
address[] memory from,
uint256[][] memory pieceIds,
uint256[] memory deadline,
uint8[] memory v,
bytes32[] memory r,
bytes32[] memory s
) external;
/**
* @notice Fetch an art piece by its ID.
* @param pieceId The ID of the art piece.
* @return The ArtPiece struct associated with the given ID.
*/
function getPieceById(uint256 pieceId) external view returns (ArtPiece memory);
/**
* @notice Fetch the list of voters for a given art piece.
* @param pieceId The ID of the art piece.
* @param voter The address of the voter.
* @return An Voter structs associated with the given art piece ID.
*/
function getVote(uint256 pieceId, address voter) external view returns (Vote memory);
/**
* @notice Retrieve the top-voted art piece based on the accumulated votes.
* @return The ArtPiece struct representing the piece with the most votes.
*/
function getTopVotedPiece() external view returns (ArtPiece memory);
/**
* @notice Fetch the ID of the top-voted art piece.
* @return The ID of the art piece with the most votes.
*/
function topVotedPieceId() external view returns (uint256);
/**
* @notice Returns true or false depending on whether the top voted piece meets quorum
* @return True if the top voted piece meets quorum, false otherwise
*/
function topVotedPieceMeetsQuorum() external view returns (bool);
/**
* @notice Officially release or "drop" the art piece with the most votes.
* @dev This function also updates internal state to reflect the piece's dropped status.
* @return The ArtPiece struct of the top voted piece that was just dropped.
*/
function dropTopVotedPiece() external returns (ArtPieceCondensed memory);
/**
* @notice Initializes a token's metadata descriptor
* @param votingPower The address of the revolution voting power contract
* @param initialOwner The owner of the contract, allowed to drop pieces. Commonly updated to the AuctionHouse
* @param maxHeap The address of the max heap contract
* @param dropperAdmin The address that can drop new art pieces
* @param cultureIndexParams The CultureIndex settings
*/
function initialize(
address votingPower,
address initialOwner,
address maxHeap,
address dropperAdmin,
IRevolutionBuilder.CultureIndexParams calldata cultureIndexParams
) external;
/**
* @notice Easily fetch piece maximums
* @return Max lengths for piece data
*/
function maxNameLength() external view returns (uint256);
function maxDescriptionLength() external view returns (uint256);
function maxImageLength() external view returns (uint256);
function maxTextLength() external view returns (uint256);
function maxAnimationUrlLength() external view returns (uint256);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.22;
import { IRevolutionBuilder } from "./IRevolutionBuilder.sol";
import { IGrantsRevenueStream } from "./IGrantsRevenueStream.sol";
import { IVRGDAC } from "./IVRGDAC.sol";
import { IRewardSplits } from "@cobuild/protocol-rewards/src/interfaces/IRewardSplits.sol";
interface IRevolutionPointsEmitter is IGrantsRevenueStream, IRewardSplits {
/// ///
/// ERRORS ///
/// ///
/// @dev Reverts if the function caller is not the manager.
error NOT_MANAGER();
/// @dev Reverts if address 0 is passed but not allowed
error ADDRESS_ZERO();
/// @dev Reverts if invalid BPS is passed
error INVALID_BPS();
/// @dev Reverts if BPS does not add up to 10_000
error INVALID_BPS_SUM();
/// @dev Reverts if payment amount is 0
error INVALID_PAYMENT();
/// @dev Reverts if amount is 0
error INVALID_AMOUNT();
/// @dev Reverts if there is an array length mismatch
error PARALLEL_ARRAYS_REQUIRED();
/// @dev Reverts if the buyToken sender is the owner or creatorsAddress
error FUNDS_RECIPIENT_CANNOT_BUY_TOKENS();
/// @dev Reverts if insufficient balance to transfer
error INSUFFICIENT_BALANCE();
/// @dev Reverts if the WETH transfer fails
error WETH_TRANSFER_FAILED();
/// @dev Reverts if invalid rewards timestamp is passed
error INVALID_REWARDS_TIMESTAMP();
struct BuyTokenPaymentShares {
uint256 buyersGovernancePayment;
uint256 founderDirectPayment;
uint256 founderGovernancePayment;
uint256 grantsDirectPayment;
}
// To find amount of ether to pay founder and owner after calculating the amount of points to emit
struct PaymentDistribution {
uint256 toPayOwner;
uint256 toPayFounder;
}
struct ProtocolRewardAddresses {
address builder;
address purchaseReferral;
address deployer;
}
struct AccountPurchaseHistory {
// The amount of tokens bought
uint256 tokensBought;
// The amount paid to owner()
uint256 amountPaidToOwner;
}
function buyToken(
address[] calldata addresses,
uint[] calldata bps,
ProtocolRewardAddresses calldata protocolRewardsRecipients
) external payable returns (uint256);
function WETH() external view returns (address);
function totalSupply() external view returns (uint256);
function balanceOf(address owner) external view returns (uint256);
function founderAddress() external view returns (address);
function startTime() external view returns (uint256);
function vrgda() external view returns (IVRGDAC);
function founderRateBps() external view returns (uint256);
function founderEntropyRateBps() external view returns (uint256);
function founderRewardsExpirationDate() external view returns (uint256);
function getTokenQuoteForPayment(uint256 paymentAmount) external returns (int256);
function getTokenQuoteForEther(uint256 etherAmount) external returns (int256);
function pause() external;
function unpause() external;
function getAccountPurchaseHistory(address account) external view returns (AccountPurchaseHistory memory);
event PurchaseFinalized(
address indexed buyer,
uint256 payment,
uint256 ownerAmount,
uint256 protocolRewardsAmount,
uint256 buyerTokensEmitted,
uint256 founderTokensEmitted,
uint256 founderDirectPayment,
uint256 grantsDirectPayment
);
/**
* @notice Initialize the points emitter
* @param initialOwner The initial owner of the points emitter
* @param weth The address of the WETH contract.
* @param revolutionPoints The ERC-20 token contract address
* @param vrgda The VRGDA contract address
* @param founderParams The founder rewards parameters
* @param grantsParams The grants rewards parameters
*/
function initialize(
address initialOwner,
address weth,
address revolutionPoints,
address vrgda,
IRevolutionBuilder.FounderParams calldata founderParams,
IRevolutionBuilder.GrantsParams calldata grantsParams
) external;
}// This file is automatically generated by code; do not manually update
// Last updated on 2024-04-02T01:46:23.237Z
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.22;
import { IVersionedContract } from "@cobuild/utility-contracts/src/interfaces/IVersionedContract.sol";
/// @title RevolutionVersion
/// @notice Base contract for versioning contracts
contract RevolutionVersion is IVersionedContract {
/// @notice The version of the contract
function contractVersion() external pure override returns (string memory) {
return "0.5.1";
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.22;
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { IRevolutionPointsEmitter } from "./IPointsEmitterLike.sol";
/**
* @title ISplitMain
* @author 0xSplits <[email protected]>
*/
interface ISplitMain {
/**
* STRUCTS
*/
struct PointsData {
uint32 pointsPercent;
address[] accounts;
uint32[] percentAllocations;
}
/**
* FUNCTIONS
*/
/**
* @notice Initializes the SplitMain contract
* @param initialOwner The address to set as the initial owner of the contract
* @param pointsEmitter The address of the points emitter to buy tokens through
*/
function initialize(address initialOwner, address pointsEmitter) external;
function walletImplementation() external returns (address);
function pointsEmitter() external returns (IRevolutionPointsEmitter);
function createSplit(
PointsData calldata pointsData,
address[] calldata accounts,
uint32[] calldata percentAllocations,
uint32 distributorFee,
address controller
) external returns (address);
function predictImmutableSplitAddress(
PointsData calldata pointsData,
address[] calldata accounts,
uint32[] calldata percentAllocations,
uint32 distributorFee
) external view returns (address);
function updateSplit(
address split,
PointsData calldata pointsData,
address[] calldata accounts,
uint32[] calldata percentAllocations,
uint32 distributorFee
) external;
function PERCENTAGE_SCALE() external returns (uint256);
function getHash(address split) external view returns (bytes32);
function getETHBalance(address account) external view returns (uint256);
function getERC20Balance(address account, ERC20 token) external view returns (uint256);
function getETHPointsBalance(address account) external view returns (uint256);
function getPointsBalance(address account) external view returns (int256);
function transferControl(address split, address newController) external;
function cancelControlTransfer(address split) external;
function acceptControl(address split) external;
function makeSplitImmutable(address split) external;
function distributeETH(
address split,
PointsData calldata pointsData,
address[] calldata accounts,
uint32[] calldata percentAllocations,
uint32 distributorFee,
address distributorAddress
) external;
function updateAndDistributeETH(
address split,
PointsData calldata pointsData,
address[] calldata accounts,
uint32[] calldata percentAllocations,
uint32 distributorFee,
address distributorAddress
) external;
function distributeERC20(
address split,
ERC20 token,
PointsData calldata pointsData,
address[] calldata accounts,
uint32[] calldata percentAllocations,
uint32 distributorFee,
address distributorAddress
) external;
function updateAndDistributeERC20(
address split,
ERC20 token,
PointsData calldata pointsData,
address[] calldata accounts,
uint32[] calldata percentAllocations,
uint32 distributorFee,
address distributorAddress
) external;
function withdraw(address account, uint256 withdrawETH, uint256 withdrawPoints, ERC20[] calldata tokens) external;
/**
* EVENTS
*/
/** @notice emitted after each successful split creation
* @param split Address of the created split
*/
event CreateSplit(
address indexed split,
PointsData pointsData,
address[] accounts,
uint32[] percentAllocations,
uint32 distributorFee,
address controller
);
/** @notice emitted after each successful split update
* @param split Address of the updated split
*/
event UpdateSplit(address indexed split);
/** @notice emitted after each initiated split control transfer
* @param split Address of the split control transfer was initiated for
* @param newPotentialController Address of the split's new potential controller
*/
event InitiateControlTransfer(address indexed split, address indexed newPotentialController);
/** @notice emitted after each canceled split control transfer
* @param split Address of the split control transfer was canceled for
*/
event CancelControlTransfer(address indexed split);
/** @notice emitted after each successful split control transfer
* @param split Address of the split control was transferred for
* @param previousController Address of the split's previous controller
* @param newController Address of the split's new controller
*/
event ControlTransfer(address indexed split, address indexed previousController, address indexed newController);
/** @notice emitted after each successful ETH balance split
* @param split Address of the split that distributed its balance
* @param amount Amount of ETH distributed
* @param distributorAddress Address to credit distributor fee to
*/
event DistributeETH(address indexed split, uint256 amount, address indexed distributorAddress);
/** @notice emitted after each successful ERC20 balance split
* @param split Address of the split that distributed its balance
* @param token Address of ERC20 distributed
* @param amount Amount of ERC20 distributed
* @param distributorAddress Address to credit distributor fee to
*/
event DistributeERC20(
address indexed split,
ERC20 indexed token,
uint256 amount,
address indexed distributorAddress
);
/** @notice emitted after each successful withdrawal
* @param account Address that funds were withdrawn to
* @param ethAmount Amount of ETH withdrawn
* @param tokens Addresses of ERC20s withdrawn
* @param tokenAmounts Amounts of corresponding ERC20s withdrawn
* @param pointsSold Amount of points withdrawn
*/
event Withdrawal(
address indexed account,
uint256 ethAmount,
ERC20[] tokens,
uint256[] tokenAmounts,
uint256 pointsSold
);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.22;
import { IUUPS } from "../interfaces/IUUPS.sol";
import { ERC1967Upgrade } from "./ERC1967Upgrade.sol";
/// @title UUPS
/// @author Rohan Kulkarni
/// @notice Modified from OpenZeppelin Contracts v4.7.3 (proxy/utils/UUPSUpgradeable.sol)
/// - Uses custom errors declared in IUUPS
/// - Inherits a modern, minimal ERC1967Upgrade
abstract contract UUPS is IUUPS, ERC1967Upgrade {
/// ///
/// IMMUTABLES ///
/// ///
/// @dev The address of the implementation
address private immutable __self = address(this);
/// ///
/// MODIFIERS ///
/// ///
/// @dev Ensures that execution is via proxy delegatecall with the correct implementation
modifier onlyProxy() {
if (address(this) == __self) revert ONLY_DELEGATECALL();
if (_getImplementation() != __self) revert ONLY_PROXY();
_;
}
/// @dev Ensures that execution is via direct call
modifier notDelegated() {
if (address(this) != __self) revert ONLY_CALL();
_;
}
/// ///
/// FUNCTIONS ///
/// ///
/// @dev Hook to authorize an implementation upgrade
/// @param _newImpl The new implementation address
function _authorizeUpgrade(address _newImpl) internal virtual;
/// @notice Upgrades to an implementation
/// @param _newImpl The new implementation address
function upgradeTo(address _newImpl) external onlyProxy {
_authorizeUpgrade(_newImpl);
_upgradeToAndCallUUPS(_newImpl, "", false);
}
/// @notice Upgrades to an implementation with an additional function call
/// @param _newImpl The new implementation address
/// @param _data The encoded function call
function upgradeToAndCall(address _newImpl, bytes memory _data) external payable onlyProxy {
_authorizeUpgrade(_newImpl);
_upgradeToAndCallUUPS(_newImpl, _data, true);
}
/// @notice The storage slot of the implementation address
function proxiableUUID() external view notDelegated returns (bytes32) {
return _IMPLEMENTATION_SLOT;
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.22;
import { IUUPS } from "../interfaces/IUUPS.sol";
/// @title IUpgradeManager
/// @notice The external manager of upgrades for Revolution DAOs
interface IUpgradeManager is IUUPS {
/// @notice If an implementation is registered by the DAO as an optional upgrade
/// @param baseImpl The base implementation address
/// @param upgradeImpl The upgrade implementation address
function isRegisteredUpgrade(address baseImpl, address upgradeImpl) external view returns (bool);
/// @notice Called by the DAO to offer opt-in implementation upgrades for all other DAOs
/// @param baseImpl The base implementation address
/// @param upgradeImpl The upgrade implementation address
function registerUpgrade(address baseImpl, address upgradeImpl) external;
/// @notice Called by the DAO to remove an upgrade
/// @param baseImpl The base implementation address
/// @param upgradeImpl The upgrade implementation address
function removeUpgrade(address baseImpl, address upgradeImpl) external;
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.22;
import { RewardSplits } from "./RewardSplits.sol";
abstract contract RevolutionRewards is RewardSplits {
constructor(
address _protocolRewards,
address _revolutionRewardRecipient
) payable RewardSplits(_protocolRewards, _revolutionRewardRecipient) {}
function _handleRewardsAndGetValueToSend(
uint256 msgValue,
address builderReferral,
address purchaseReferral,
address deployer
) internal returns (uint256) {
return msgValue - _depositPurchaseRewards(msgValue, builderReferral, purchaseReferral, deployer);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Context.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @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.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: GPL-3.0-or-later
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721Votes.sol)
pragma solidity ^0.8.22;
import { ERC721EnumerableUpgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol";
import { VotesUpgradeable } from "./VotesUpgradeable.sol";
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
/**
* @dev Extension of ERC-721 to support voting and delegation as implemented by {Votes}, where each individual NFT counts
* as 1 vote unit.
*
* Tokens do not count as votes until they are delegated, because votes must be tracked which incurs an additional cost
* on every transfer. Token holders can either delegate to a trusted representative who will decide how to make use of
* the votes in governance decisions, or they can delegate to themselves to be their own representative.
*/
/**
* @dev MODIFICATIONS
* Checkpointing logic from VotesUpgradeable.sol has been used with the following modifications:
* - `delegates` is renamed to `_delegates` and is set to private
* - `delegates` is a public function that uses the `_delegates` mapping look-up, but unlike
* VotesUpgradeable.sol, returns the delegator's own address if there is no delegate.
* This avoids the delegator needing to "delegate to self" with an additional transaction
*/
abstract contract ERC721CheckpointableUpgradeable is Initializable, ERC721EnumerableUpgradeable, VotesUpgradeable {
function __ERC721Votes_init() internal onlyInitializing {}
function __ERC721Votes_init_unchained() internal onlyInitializing {}
/**
* @dev See {ERC721-_update}. Adjusts votes when tokens are transferred.
*
* Emits a {IVotes-DelegateVotesChanged} event.
*/
function _update(address to, uint256 tokenId, address auth) internal virtual override returns (address) {
address previousOwner = super._update(to, tokenId, auth);
_transferVotingUnits(previousOwner, to, 1);
return previousOwner;
}
function getVotesStorage() private pure returns (VotesStorage storage $) {
assembly {
$.slot := VotesStorageLocation
}
}
// /**
// * @notice Overrides the standard `VotesUpgradeable.sol` delegates mapping to return
// * the accounts's own address if they haven't delegated.
// * This avoids having to delegate to oneself.
// */
function delegates(address account) public view override returns (address) {
VotesStorage storage $ = getVotesStorage();
return $._delegatee[account] == address(0) ? account : $._delegatee[account];
}
/**
* @dev Returns the balance of `account`.
*
* WARNING: Overriding this function will likely result in incorrect vote tracking.
*/
function _getVotingUnits(address account) internal view virtual override returns (uint256) {
return balanceOf(account);
}
/**
* @dev See {ERC721-_increaseBalance}. We need that to account tokens that were minted in batch.
*/
function _increaseBalance(address account, uint128 amount) internal virtual override {
super._increaseBalance(account, amount);
_transferVotingUnits(address(0), account, amount);
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.22;
import { RevolutionDAOStorageV1 } from "../governance/RevolutionDAOInterfaces.sol";
import { IUpgradeManager } from "@cobuild/utility-contracts/src/interfaces/IUpgradeManager.sol";
import { RevolutionBuilderTypesV1 } from "../builder/types/RevolutionBuilderTypesV1.sol";
import { ICultureIndex } from "./ICultureIndex.sol";
/// @title IRevolutionBuilder
/// @notice The external RevolutionBuilder events, errors, structs and functions
interface IRevolutionBuilder is IUpgradeManager {
struct TokenImplementations {
address revolutionToken;
address descriptor;
address auction;
}
struct DAOImplementations {
address executor;
address dao;
address revolutionVotingPower;
}
struct CultureIndexImplementations {
address cultureIndex;
address maxHeap;
}
struct PointsImplementations {
address revolutionPoints;
address revolutionPointsEmitter;
address vrgda;
address splitsCreator;
}
struct ExtensionData {
string name;
bytes executorInitializationData;
}
/// ///
/// EVENTS ///
/// ///
/// @notice Emitted when a DAO is deployed
/// @param revolutionToken The ERC-721 token address
/// @param descriptor The descriptor renderer address
/// @param auction The auction address
/// @param executor The executor address
/// @param dao The dao address
/// @param cultureIndex The cultureIndex address
/// @param revolutionPointsEmitter The RevolutionPointsEmitter address
/// @param revolutionPoints The dao address
/// @param maxHeap The maxHeap address
/// @param revolutionVotingPower The revolutionVotingPower address
/// @param vrgda The VRGDA address
/// @param splitsCreator The splits factory address
event RevolutionDeployed(
address revolutionToken,
address descriptor,
address auction,
address executor,
address dao,
address cultureIndex,
address revolutionPointsEmitter,
address revolutionPoints,
address maxHeap,
address revolutionVotingPower,
address vrgda,
address splitsCreator
);
/// @notice Emitted when an upgrade is registered by the Builder DAO
/// @param baseImpl The base implementation address
/// @param upgradeImpl The upgrade implementation address
event UpgradeRegistered(address baseImpl, address upgradeImpl);
/// @notice Emitted when an upgrade is unregistered by the Builder DAO
/// @param baseImpl The base implementation address
/// @param upgradeImpl The upgrade implementation address
event UpgradeRemoved(address baseImpl, address upgradeImpl);
/// @notice Emitted when an extension is registered by the Revolution DAO
/// @param name The name of the extension
/// @param builder The builder address to pay rewards to
/// @param addresses The implementations of the extension
event ExtensionRegistered(string name, address builder, RevolutionBuilderTypesV1.DAOAddresses addresses);
/// @notice Emitted when an extension is unregistered by the Revolution DAO
/// @param name The base implementation address
event ExtensionRemoved(string name);
/// @notice Emitted when a culture index is deployed
/// @param cultureIndex The culture index address
/// @param maxHeap The max heap address
/// @param votingPower The voting power address
event CultureIndexDeployed(address cultureIndex, address maxHeap, address votingPower);
/// ///
/// ERRORS ///
/// ///
/// @notice The error message when invalid address zero is passed
error INVALID_ZERO_ADDRESS();
/// @notice Reverts when invalid extension is passed
error INVALID_EXTENSION();
/// @notice Reverts when extension already exists
error EXTENSION_EXISTS();
/// ///
/// STRUCTS ///
/// ///
/// @notice DAO Version Information information struct
struct DAOVersionInfo {
string revolutionToken;
string descriptor;
string auction;
string executor;
string dao;
string cultureIndex;
string revolutionPoints;
string revolutionPointsEmitter;
string maxHeap;
string revolutionVotingPower;
string vrgda;
}
/// @notice The ERC-721 token parameters
/// @param name The token name
/// @param symbol The token symbol
/// @param contractURIHash The IPFS content hash of the contract-level metadata
/// @param tokenNamePrefix The token name prefix
struct RevolutionTokenParams {
string name;
string symbol;
string contractURIHash;
string tokenNamePrefix;
}
/// @notice The auction parameters
/// @param timeBuffer The time buffer of each auction
/// @param reservePrice The reserve price of each auction
/// @param duration The duration of each auction
/// @param minBidIncrementPercentage The minimum bid increment percentage of each auction
/// @param creatorRateBps The creator rate basis points of each auction - the share of the winning bid that is reserved for the creator
/// @param entropyRateBps The entropy rate basis points of each auction - the portion of the creator's share that is directly sent to the creator in ETH
/// @param minCreatorRateBps The minimum creator rate basis points of each auction
/// @param grantsParams The grants program parameters
struct AuctionParams {
uint256 timeBuffer;
uint256 reservePrice;
uint256 duration;
uint8 minBidIncrementPercentage;
uint256 creatorRateBps;
uint256 entropyRateBps;
uint256 minCreatorRateBps;
GrantsParams grantsParams;
}
/// @notice The governance parameters
/// @param timelockDelay The time delay to execute a queued transaction
/// @param votingDelay The time delay to vote on a created proposal
/// @param votingPeriod The time period to vote on a proposal
/// @param proposalThresholdBPS The basis points of the token supply required to create a proposal
/// @param vetoer The address authorized to veto proposals (address(0) if none desired)
/// @param name The name of the DAO
/// @param purpose The purpose of the DAO
/// @param flag The symbol of the DAO ⌐◨-◨
/// @param dynamicQuorumParams The dynamic quorum parameters
struct GovParams {
uint256 timelockDelay;
uint256 votingDelay;
uint256 votingPeriod;
uint256 proposalThresholdBPS;
address vetoer;
string name;
string purpose;
string flag;
RevolutionDAOStorageV1.DynamicQuorumParams dynamicQuorumParams;
}
/// @notice The RevolutionPoints ERC-20 params
/// @param tokenParams // The token parameters
/// @param emitterParams // The emitter parameters
struct RevolutionPointsParams {
PointsTokenParams tokenParams;
PointsEmitterParams emitterParams;
}
/// @notice The RevolutionPoints ERC-20 token parameters
/// @param name The token name
/// @param symbol The token symbol
struct PointsTokenParams {
string name;
string symbol;
}
/// @notice The RevolutionPoints ERC-20 emitter VRGDA parameters
/// @param vrgdaParams // The VRGDA parameters
/// @param founderParams // The params to dictate payments to the founder
/// @param grantsParams // The params to dictate payments to the grants program
struct PointsEmitterParams {
VRGDAParams vrgdaParams;
FounderParams founderParams;
GrantsParams grantsParams;
}
/// @notice The ERC-20 points emitter VRGDA parameters
/// @param targetPrice // The target price for a token if sold on pace, scaled by 1e18.
/// @param priceDecayPercent // The percent the price decays per unit of time with no sales, scaled by 1e18.
/// @param tokensPerTimeUnit // The number of tokens to target selling in 1 full unit of time, scaled by 1e18.
struct VRGDAParams {
int256 targetPrice;
int256 priceDecayPercent;
int256 tokensPerTimeUnit;
}
/// @notice The ERC-20 points emitter creator parameters
/// @param totalRateBps The founder rate in basis points - how much of each purchase to the points emitter is reserved for the founders
/// @param entropyRateBps The entropy of the founder rate in basis points - how much ether out of the total rate is sent to founders directly
/// @param founderAddress the address to send founder rewards to
/// @param rewardsExpirationDate The timestamp in seconds from the initialization block after which the founders reward stops
struct FounderParams {
uint256 totalRateBps;
uint256 entropyRateBps;
address founderAddress;
uint256 rewardsExpirationDate;
}
/// @notice Grants program params that detail payments to the grants program
/// @param totalRateBps The grants rate in basis points - how much of each purchase to the points emitter is reserved for the grants program
/// @param founderAddress the grants program address to send ether to
struct GrantsParams {
uint256 totalRateBps;
address grantsAddress;
}
/// @notice The CultureIndex parameters
/// @param name The name of the culture index
/// @param description A description for the culture index
/// @param checklist A checklist for the culture index, can include rules for uploads etc.
/// @param template A template for the culture index, an ipfs file that artists can download and use to create art pieces
/// @param tokenVoteWeight The voting weight of the individual Revolution ERC721 tokens. Normally a large multiple to match up with daily emission of ERC20 points to match up with daily emission of ERC20 points (which normally have 18 decimals)
/// @param pointsVoteWeight The voting weight of the individual Revolution ERC20 points tokens.
/// @param quorumVotesBPS The initial quorum votes threshold in basis points
/// @param minVotingPowerToVote The minimum vote weight that a voter must have to be able to vote.
/// @param minVotingPowerToCreate The minimum vote weight that a voter must have to be able to create an art piece.
/// @param pieceMaximums The maxium length for each field in an art piece
/// @param requiredMediaType The required media type for each art piece eg: image only
/// @param requiredMediaPrefix The required media prefix for each art piece eg: ipfs://
struct CultureIndexParams {
string name;
string description;
string checklist;
string template;
uint256 tokenVoteWeight;
uint256 pointsVoteWeight;
uint256 quorumVotesBPS;
uint256 minVotingPowerToVote;
uint256 minVotingPowerToCreate;
ICultureIndex.PieceMaximums pieceMaximums;
ICultureIndex.MediaType requiredMediaType;
ICultureIndex.RequiredMediaPrefix requiredMediaPrefix;
}
/// @notice The RevolutionVotingPower parameters
/// @param tokenVoteWeight The voting weight of the individual Revolution ERC721 tokens. Normally a large multiple to match up with daily emission of ERC20 points to match up with daily emission of ERC20 points (which normally have 18 decimals)
/// @param pointsVoteWeight The voting weight of the individual Revolution ERC20 points tokens. (usually 1 because of 18 decimals on the ERC20 contract)
struct RevolutionVotingPowerParams {
uint256 tokenVoteWeight;
uint256 pointsVoteWeight;
}
/// ///
/// FUNCTIONS ///
/// ///
/// @notice The token implementation address
function revolutionTokenImpl() external view returns (address);
/// @notice The descriptor renderer implementation address
function descriptorImpl() external view returns (address);
/// @notice The auction house implementation address
function auctionImpl() external view returns (address);
/// @notice The executor implementation address
function executorImpl() external view returns (address);
/// @notice The dao implementation address
function daoImpl() external view returns (address);
/// @notice The revolutionPointsEmitter implementation address
function revolutionPointsEmitterImpl() external view returns (address);
/// @notice The cultureIndex implementation address
function cultureIndexImpl() external view returns (address);
/// @notice The revolutionPoints implementation address
function revolutionPointsImpl() external view returns (address);
/// @notice The maxHeap implementation address
function maxHeapImpl() external view returns (address);
/// @notice The revolutionVotingPower implementation address
function revolutionVotingPowerImpl() external view returns (address);
/// @notice The VRGDA implementation address
function vrgdaImpl() external view returns (address);
/// @notice The splitsCreator implementation address
function splitsCreatorImpl() external view returns (address);
/// @notice Deploys a DAO with custom token, auction, and governance settings
/// @param initialOwner The initial owner address
/// @param weth The WETH address
/// @param revolutionTokenParams The Revolution ERC-721 token settings
/// @param auctionParams The auction settings
/// @param govParams The governance settings
/// @param cultureIndexParams The CultureIndex settings
/// @param revolutionPointsParams The RevolutionPoints settings
/// @param revolutionVotingPowerParams The RevolutionVotingPower settings
function deploy(
address initialOwner,
address weth,
RevolutionTokenParams calldata revolutionTokenParams,
AuctionParams calldata auctionParams,
GovParams calldata govParams,
CultureIndexParams calldata cultureIndexParams,
RevolutionPointsParams calldata revolutionPointsParams,
RevolutionVotingPowerParams calldata revolutionVotingPowerParams
) external returns (RevolutionBuilderTypesV1.DAOAddresses memory);
/// @notice Deploys an extension DAO with custom settings including token, auction, governance, and more
/// @param initialOwner The initial owner address
/// @param weth The WETH address
/// @param revolutionTokenParams The Revolution ERC-721 token settings
/// @param auctionParams The auction settings
/// @param govParams The governance settings
/// @param cultureIndexParams The CultureIndex settings
/// @param revolutionPointsParams The RevolutionPoints settings
/// @param revolutionVotingPowerParams The RevolutionVotingPower settings
/// @param extensionData The data for the extension
function deployExtension(
address initialOwner,
address weth,
RevolutionTokenParams calldata revolutionTokenParams,
AuctionParams calldata auctionParams,
GovParams calldata govParams,
CultureIndexParams calldata cultureIndexParams,
RevolutionPointsParams calldata revolutionPointsParams,
RevolutionVotingPowerParams calldata revolutionVotingPowerParams,
ExtensionData calldata extensionData
) external returns (RevolutionBuilderTypesV1.DAOAddresses memory);
/// @notice Adds an extension to the Revolution DAO
/// @param extensionName The user readable name of the extension domain, i.e. the name of the DApp or the protocol.
/// @param builder The address of the extension builder to pay rewards to
/// @param extensionImpls The extension implementation addresses
function registerExtension(
string calldata extensionName,
address builder,
RevolutionBuilderTypesV1.DAOAddresses calldata extensionImpls
) external;
/// @notice Called by the Revolution DAO to remove an extension
/// @param extensionName The name of the extension to remove
function removeExtension(string calldata extensionName) external;
/// @notice To check if a given extension is valid
/// @param extensionName The name of the extension
function isRegisteredExtension(string calldata extensionName) external view returns (bool);
/// @notice To get an extension's implementations
/// @param extensionName The name of the extension
/// @param implementationType The type of the implementation
function getExtensionImplementation(
string calldata extensionName,
RevolutionBuilderTypesV1.ImplementationType implementationType
) external view returns (address);
/// @notice To get an extension's builder
/// @param extensionName The name of the extension
function getExtensionBuilder(string calldata extensionName) external view returns (address);
/// @notice To get an extension's name by token address
/// @param token The token address
function getExtensionByToken(address token) external view returns (string memory);
/// @notice Registers an upgrade for a contract
/// @param baseImpl The base implementation address
/// @param upgradeImpl The upgrade implementation address
function registerUpgrade(address baseImpl, address upgradeImpl) external;
/// @notice Unregisters an upgrade for a contract
/// @param baseImpl The base implementation address
/// @param upgradeImpl The upgrade implementation address
function removeUpgrade(address baseImpl, address upgradeImpl) external;
/// @notice Check if a contract has been registered as an upgrade
/// @param baseImpl The base implementation address
/// @param upgradeImpl The upgrade implementation address
function isRegisteredUpgrade(address baseImpl, address upgradeImpl) external view returns (bool);
/// @notice Deploys a culture index
/// @param votingPower The voting power contract
/// @param initialOwner The initial owner address
/// @param dropperAdmin The address who can remove pieces from the culture index
/// @param cultureIndexParams The CultureIndex settings
function deployCultureIndex(
address votingPower,
address initialOwner,
address dropperAdmin,
CultureIndexParams calldata cultureIndexParams
) external returns (address, address);
/// @notice A DAO's remaining contract addresses from its token address
/// @param token The ERC-721 token address
function getAddresses(
address token
)
external
returns (
address revolutionToken,
address descriptor,
address auction,
address executor,
address dao,
address cultureIndex,
address revolutionPoints,
address revolutionPointsEmitter,
address maxHeap,
address revolutionVotingPower,
address vrgda,
address splitsCreator
);
function getDAOVersions(address token) external view returns (DAOVersionInfo memory);
function getLatestVersions() external view returns (DAOVersionInfo memory);
/// @notice Initializes the Revolution builder contract
/// @param initialOwner The address of the initial owner
function initialize(address initialOwner) external;
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.22;
import { IRevolutionBuilder } from "./IRevolutionBuilder.sol";
interface IGrantsRevenueStream {
/// ///
/// FUNCTIONS ///
/// ///
function setGrantsRateBps(uint256 grantsRateBps) external;
function grantsRateBps() external view returns (uint256);
function grantsAddress() external view returns (address);
function setGrantsAddress(address grants) external;
event GrantsAddressUpdated(address grants);
event GrantsRateBpsUpdated(uint256 rateBps);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.22;
interface IVRGDAC {
/**
* @notice Initializes the VRGDAC contract
* @param initialOwner The initial owner of the contract
* @param targetPrice The target price for a token if sold on pace, scaled by 1e18.
* @param priceDecayPercent The percent price decays per unit of time with no sales, scaled by 1e18.
* @param perTimeUnit The number of tokens to target selling in 1 full unit of time, scaled by 1e18.
*/
function initialize(
address initialOwner,
int256 targetPrice,
int256 priceDecayPercent,
int256 perTimeUnit
) external;
function yToX(int256 timeSinceStart, int256 sold, int256 amount) external view returns (int256);
function xToY(int256 timeSinceStart, int256 sold, int256 amount) external view returns (int256);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.22;
interface IRewardSplits {
struct RewardsSettings {
uint256 builderReferralReward;
uint256 purchaseReferralReward;
uint256 deployerReward;
uint256 revolutionReward;
}
function computeTotalReward(uint256 paymentAmountWei) external pure returns (uint256);
function computePurchaseRewards(uint256 paymentAmountWei) external pure returns (RewardsSettings memory, uint256);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.22;
interface IVersionedContract {
function contractVersion() external view returns (string memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*/
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
mapping(address account => uint256) private _balances;
mapping(address account => mapping(address spender => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `value`.
*/
function transfer(address to, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_transfer(owner, to, value);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, value);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `value`.
* - the caller must have allowance for ``from``'s tokens of at least
* `value`.
*/
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}
/**
* @dev Moves a `value` amount of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _transfer(address from, address to, uint256 value) internal {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}
/**
* @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
* (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
* this function.
*
* Emits a {Transfer} event.
*/
function _update(address from, address to, uint256 value) internal virtual {
if (from == address(0)) {
// Overflow check required: The rest of the code assumes that totalSupply never overflows
_totalSupply += value;
} else {
uint256 fromBalance = _balances[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
// Overflow not possible: value <= fromBalance <= totalSupply.
_balances[from] = fromBalance - value;
}
}
if (to == address(0)) {
unchecked {
// Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
_totalSupply -= value;
}
} else {
unchecked {
// Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
_balances[to] += value;
}
}
emit Transfer(from, to, value);
}
/**
* @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
* Relies on the `_update` mechanism
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _mint(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(address(0), account, value);
}
/**
* @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
* Relies on the `_update` mechanism.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead
*/
function _burn(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidSender(address(0));
}
_update(account, address(0), value);
}
/**
* @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
*/
function _approve(address owner, address spender, uint256 value) internal {
_approve(owner, spender, value, true);
}
/**
* @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
*
* By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
* `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
* `Approval` event during `transferFrom` operations.
*
* Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
* true using the following override:
* ```
* function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
* super._approve(owner, spender, value, true);
* }
* ```
*
* Requirements are the same as {_approve}.
*/
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC20InvalidSpender(address(0));
}
_allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `value`.
*
* Does not update the allowance value in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Does not emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.22;
interface IRevolutionPointsEmitter {
struct ProtocolRewardAddresses {
address builder;
address purchaseReferral;
address deployer;
}
function buyToken(
address[] calldata addresses,
uint[] calldata bps,
ProtocolRewardAddresses calldata protocolRewardsRecipients
) external payable returns (uint);
function getTokenQuoteForPayment(uint256 paymentAmount) external view returns (int256);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.22;
import { IERC1822Proxiable } from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol";
import { IERC1967Upgrade } from "./IERC1967Upgrade.sol";
/// @title IUUPS
/// @author Rohan Kulkarni
/// @notice The external UUPS errors and functions
interface IUUPS is IERC1967Upgrade, IERC1822Proxiable {
/// ///
/// ERRORS ///
/// ///
/// @dev Reverts if not called directly
error ONLY_CALL();
/// @dev Reverts if not called via delegatecall
error ONLY_DELEGATECALL();
/// @dev Reverts if not called via proxy
error ONLY_PROXY();
/// ///
/// FUNCTIONS ///
/// ///
/// @notice Upgrades to an implementation
/// @param newImpl The new implementation address
function upgradeTo(address newImpl) external;
/// @notice Upgrades to an implementation with an additional function call
/// @param newImpl The new implementation address
/// @param data The encoded function call
function upgradeToAndCall(address newImpl, bytes memory data) external payable;
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.22;
import { IERC1822Proxiable } from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol";
import { StorageSlot } from "@openzeppelin/contracts/utils/StorageSlot.sol";
import { IERC1967Upgrade } from "../interfaces/IERC1967Upgrade.sol";
import { Address } from "@openzeppelin/contracts/utils/Address.sol";
/// @title ERC1967Upgrade
/// @author Rohan Kulkarni
/// @notice Modified from OpenZeppelin Contracts v4.7.3 (proxy/ERC1967/ERC1967Upgrade.sol)
/// - Uses custom errors declared in IERC1967Upgrade
/// - Removes ERC1967 admin and beacon support
abstract contract ERC1967Upgrade is IERC1967Upgrade {
/// ///
/// CONSTANTS ///
/// ///
/// @dev bytes32(uint256(keccak256('eip1967.proxy.rollback')) - 1)
bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
/// @dev bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/// ///
/// FUNCTIONS ///
/// ///
/// @dev Upgrades to an implementation with security checks for UUPS proxies and an additional function call
/// @param _newImpl The new implementation address
/// @param _data The encoded function call
function _upgradeToAndCallUUPS(address _newImpl, bytes memory _data, bool _forceCall) internal {
if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
_setImplementation(_newImpl);
} else {
try IERC1822Proxiable(_newImpl).proxiableUUID() returns (bytes32 slot) {
if (slot != _IMPLEMENTATION_SLOT) revert UNSUPPORTED_UUID();
} catch {
revert ONLY_UUPS();
}
_upgradeToAndCall(_newImpl, _data, _forceCall);
}
}
/// @dev Upgrades to an implementation with an additional function call
/// @param _newImpl The new implementation address
/// @param _data The encoded function call
function _upgradeToAndCall(address _newImpl, bytes memory _data, bool _forceCall) internal {
_upgradeTo(_newImpl);
if (_data.length > 0 || _forceCall) {
Address.functionDelegateCall(_newImpl, _data);
}
}
/// @dev Performs an implementation upgrade
/// @param _newImpl The new implementation address
function _upgradeTo(address _newImpl) internal {
_setImplementation(_newImpl);
emit Upgraded(_newImpl);
}
/// @dev If an address is a contract
function isContract(address _account) internal view returns (bool rv) {
assembly {
rv := gt(extcodesize(_account), 0)
}
}
/// @dev Stores the address of an implementation
/// @param _impl The implementation address
function _setImplementation(address _impl) private {
if (!isContract(_impl)) revert INVALID_UPGRADE(_impl);
StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = _impl;
}
/// @dev The address of the current implementation
function _getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.22;
import { IProtocolRewards } from "../interfaces/IProtocolRewards.sol";
import { IRewardSplits } from "../interfaces/IRewardSplits.sol";
/// @notice Common logic for Revolution RevolutionPointsEmitter contracts for protocol reward splits & deposits
abstract contract RewardSplits is IRewardSplits {
// 2.5% total
uint256 internal constant DEPLOYER_REWARD_BPS = 25;
uint256 internal constant REVOLUTION_REWARD_BPS = 75;
uint256 internal constant BUILDER_REWARD_BPS = 100;
uint256 internal constant PURCHASE_REFERRAL_BPS = 50;
address internal immutable revolutionRewardRecipient;
IProtocolRewards internal immutable protocolRewards;
constructor(address _protocolRewards, address _revolutionRewardRecipient) payable {
if (_protocolRewards == address(0) || _revolutionRewardRecipient == address(0)) revert("Invalid Address Zero");
protocolRewards = IProtocolRewards(_protocolRewards);
revolutionRewardRecipient = _revolutionRewardRecipient;
}
/*
* @param _paymentAmountWei The amount of ETH being paid for the purchase
*/
function computeTotalReward(uint256 paymentAmountWei) public pure override returns (uint256) {
return
((paymentAmountWei * BUILDER_REWARD_BPS) / 10_000) +
((paymentAmountWei * PURCHASE_REFERRAL_BPS) / 10_000) +
((paymentAmountWei * DEPLOYER_REWARD_BPS) / 10_000) +
((paymentAmountWei * REVOLUTION_REWARD_BPS) / 10_000);
}
function computePurchaseRewards(
uint256 paymentAmountWei
) public pure override returns (RewardsSettings memory, uint256) {
return (
RewardsSettings({
builderReferralReward: (paymentAmountWei * BUILDER_REWARD_BPS) / 10_000,
purchaseReferralReward: (paymentAmountWei * PURCHASE_REFERRAL_BPS) / 10_000,
deployerReward: (paymentAmountWei * DEPLOYER_REWARD_BPS) / 10_000,
revolutionReward: (paymentAmountWei * REVOLUTION_REWARD_BPS) / 10_000
}),
computeTotalReward(paymentAmountWei)
);
}
function _depositPurchaseRewards(
uint256 paymentAmountWei,
address builderReferral,
address purchaseReferral,
address deployer
) internal returns (uint256) {
(RewardsSettings memory settings, uint256 totalReward) = computePurchaseRewards(paymentAmountWei);
if (builderReferral == address(0)) builderReferral = revolutionRewardRecipient;
if (deployer == address(0)) deployer = revolutionRewardRecipient;
if (purchaseReferral == address(0)) purchaseReferral = revolutionRewardRecipient;
protocolRewards.depositRewards{ value: totalReward }(
builderReferral,
settings.builderReferralReward,
purchaseReferral,
settings.purchaseReferralReward,
deployer,
settings.deployerReward,
revolutionRewardRecipient,
settings.revolutionReward
);
return totalReward;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721Enumerable.sol)
pragma solidity ^0.8.20;
import {ERC721Upgradeable} from "../ERC721Upgradeable.sol";
import {IERC721Enumerable} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {Initializable} from "../../../proxy/utils/Initializable.sol";
/**
* @dev This implements an optional extension of {ERC721} defined in the EIP that adds enumerability
* of all the token ids in the contract as well as all token ids owned by each account.
*
* CAUTION: `ERC721` extensions that implement custom `balanceOf` logic, such as `ERC721Consecutive`,
* interfere with enumerability and should not be used together with `ERC721Enumerable`.
*/
abstract contract ERC721EnumerableUpgradeable is Initializable, ERC721Upgradeable, IERC721Enumerable {
/// @custom:storage-location erc7201:openzeppelin.storage.ERC721Enumerable
struct ERC721EnumerableStorage {
mapping(address owner => mapping(uint256 index => uint256)) _ownedTokens;
mapping(uint256 tokenId => uint256) _ownedTokensIndex;
uint256[] _allTokens;
mapping(uint256 tokenId => uint256) _allTokensIndex;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ERC721Enumerable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ERC721EnumerableStorageLocation = 0x645e039705490088daad89bae25049a34f4a9072d398537b1ab2425f24cbed00;
function _getERC721EnumerableStorage() private pure returns (ERC721EnumerableStorage storage $) {
assembly {
$.slot := ERC721EnumerableStorageLocation
}
}
/**
* @dev An `owner`'s token query was out of bounds for `index`.
*
* NOTE: The owner being `address(0)` indicates a global out of bounds index.
*/
error ERC721OutOfBoundsIndex(address owner, uint256 index);
/**
* @dev Batch mint is not allowed.
*/
error ERC721EnumerableForbiddenBatchMint();
function __ERC721Enumerable_init() internal onlyInitializing {
}
function __ERC721Enumerable_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721Upgradeable) returns (bool) {
return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
*/
function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual returns (uint256) {
ERC721EnumerableStorage storage $ = _getERC721EnumerableStorage();
if (index >= balanceOf(owner)) {
revert ERC721OutOfBoundsIndex(owner, index);
}
return $._ownedTokens[owner][index];
}
/**
* @dev See {IERC721Enumerable-totalSupply}.
*/
function totalSupply() public view virtual returns (uint256) {
ERC721EnumerableStorage storage $ = _getERC721EnumerableStorage();
return $._allTokens.length;
}
/**
* @dev See {IERC721Enumerable-tokenByIndex}.
*/
function tokenByIndex(uint256 index) public view virtual returns (uint256) {
ERC721EnumerableStorage storage $ = _getERC721EnumerableStorage();
if (index >= totalSupply()) {
revert ERC721OutOfBoundsIndex(address(0), index);
}
return $._allTokens[index];
}
/**
* @dev See {ERC721-_update}.
*/
function _update(address to, uint256 tokenId, address auth) internal virtual override returns (address) {
address previousOwner = super._update(to, tokenId, auth);
if (previousOwner == address(0)) {
_addTokenToAllTokensEnumeration(tokenId);
} else if (previousOwner != to) {
_removeTokenFromOwnerEnumeration(previousOwner, tokenId);
}
if (to == address(0)) {
_removeTokenFromAllTokensEnumeration(tokenId);
} else if (previousOwner != to) {
_addTokenToOwnerEnumeration(to, tokenId);
}
return previousOwner;
}
/**
* @dev Private function to add a token to this extension's ownership-tracking data structures.
* @param to address representing the new owner of the given token ID
* @param tokenId uint256 ID of the token to be added to the tokens list of the given address
*/
function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
ERC721EnumerableStorage storage $ = _getERC721EnumerableStorage();
uint256 length = balanceOf(to) - 1;
$._ownedTokens[to][length] = tokenId;
$._ownedTokensIndex[tokenId] = length;
}
/**
* @dev Private function to add a token to this extension's token tracking data structures.
* @param tokenId uint256 ID of the token to be added to the tokens list
*/
function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
ERC721EnumerableStorage storage $ = _getERC721EnumerableStorage();
$._allTokensIndex[tokenId] = $._allTokens.length;
$._allTokens.push(tokenId);
}
/**
* @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that
* while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for
* gas optimizations e.g. when performing a transfer operation (avoiding double writes).
* This has O(1) time complexity, but alters the order of the _ownedTokens array.
* @param from address representing the previous owner of the given token ID
* @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
*/
function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
ERC721EnumerableStorage storage $ = _getERC721EnumerableStorage();
// To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and
// then delete the last slot (swap and pop).
uint256 lastTokenIndex = balanceOf(from);
uint256 tokenIndex = $._ownedTokensIndex[tokenId];
// When the token to delete is the last token, the swap operation is unnecessary
if (tokenIndex != lastTokenIndex) {
uint256 lastTokenId = $._ownedTokens[from][lastTokenIndex];
$._ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
$._ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
}
// This also deletes the contents at the last position of the array
delete $._ownedTokensIndex[tokenId];
delete $._ownedTokens[from][lastTokenIndex];
}
/**
* @dev Private function to remove a token from this extension's token tracking data structures.
* This has O(1) time complexity, but alters the order of the _allTokens array.
* @param tokenId uint256 ID of the token to be removed from the tokens list
*/
function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
ERC721EnumerableStorage storage $ = _getERC721EnumerableStorage();
// To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and
// then delete the last slot (swap and pop).
uint256 lastTokenIndex = $._allTokens.length - 1;
uint256 tokenIndex = $._allTokensIndex[tokenId];
// When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
// rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
// an 'if' statement (like in _removeTokenFromOwnerEnumeration)
uint256 lastTokenId = $._allTokens[lastTokenIndex];
$._allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
$._allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
// This also deletes the contents at the last position of the array
delete $._allTokensIndex[tokenId];
$._allTokens.pop();
}
/**
* See {ERC721-_increaseBalance}. We need that to account tokens that were minted in batch
*/
function _increaseBalance(address account, uint128 amount) internal virtual override {
if (amount > 0) {
revert ERC721EnumerableForbiddenBatchMint();
}
super._increaseBalance(account, amount);
}
}// SPDX-License-Identifier: GPL-3.0-or-later
// OpenZeppelin Contracts (last updated v5.0.0) (governance/utils/Votes.sol)
pragma solidity ^0.8.22;
import { IERC5805 } from "@openzeppelin/contracts/interfaces/IERC5805.sol";
import { ContextUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol";
import { NoncesUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/NoncesUpgradeable.sol";
import { EIP712Upgradeable } from "@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol";
import { Checkpoints } from "@openzeppelin/contracts/utils/structs/Checkpoints.sol";
import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import { Time } from "@openzeppelin/contracts/utils/types/Time.sol";
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
/**
* @dev This is a base abstract contract that tracks voting units, which are a measure of voting power that can be
* transferred, and provides a system of vote delegation, where an account can delegate its voting units to a sort of
* "representative" that will pool delegated voting units from different accounts and can then use it to vote in
* decisions. In fact, voting units _must_ be delegated in order to count as actual votes, and an account has to
* delegate those votes to itself if it wishes to participate in decisions and does not have a trusted representative.
*
* This contract is often combined with a token contract such that voting units correspond to token units. For an
* example, see {ERC721Votes}.
*
* The full history of delegate votes is tracked on-chain so that governance protocols can consider votes as distributed
* at a particular block number to protect against flash loans and double voting. The opt-in delegate system makes the
* cost of this history tracking optional.
*
* When using this module the derived contract must implement {_getVotingUnits} (for example, make it return
* {ERC721-balanceOf}), and can use {_transferVotingUnits} to track a change in the distribution of those units (in the
* previous example, it would be included in {ERC721-_update}).
*/
/**
* @dev MODIFICATIONS
* Checkpointing logic from VotesUpgradeable.sol has been used with the following modifications:
* - `delegates` is a public function that uses the `_delegatee` mapping look-up, but unlike
* VotesUpgradeable.sol, returns the delegator's own address if there is no delegate.
* This avoids the delegator needing to "delegate to self" with an additional transaction.
* - `_delegate` is a private function that does not allow delegating to the zero address.
* This prevents a delegatee from draining all voting units from delegator as a result of the change in default
* behavior of `delegates` function.
* Audit info: https://github.com/code-423n4/2023-12-revolutionprotocol-findings/issues/49
*/
abstract contract VotesUpgradeable is
Initializable,
ContextUpgradeable,
EIP712Upgradeable,
NoncesUpgradeable,
IERC5805
{
using Checkpoints for Checkpoints.Trace208;
bytes32 private constant DELEGATION_TYPEHASH =
keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
/// @custom:storage-location erc7201:openzeppelin.storage.Votes
struct VotesStorage {
mapping(address account => address) _delegatee;
mapping(address delegatee => Checkpoints.Trace208) _delegateCheckpoints;
Checkpoints.Trace208 _totalCheckpoints;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Votes")) - 1)) & ~bytes32(uint256(0xff))
bytes32 public constant VotesStorageLocation = 0xe8b26c30fad74198956032a3533d903385d56dd795af560196f9c78d4af40d00;
function _getVotesStorage() private pure returns (VotesStorage storage $) {
assembly {
$.slot := VotesStorageLocation
}
}
/**
* @dev The clock was incorrectly modified.
*/
error ERC6372InconsistentClock();
/**
* @dev Lookup to future votes is not available.
*/
error ERC5805FutureLookup(uint256 timepoint, uint48 clock);
function __Votes_init() internal onlyInitializing {}
function __Votes_init_unchained() internal onlyInitializing {}
/**
* @dev Clock used for flagging checkpoints. Can be overridden to implement timestamp based
* checkpoints (and voting), in which case {CLOCK_MODE} should be overridden as well to match.
*/
function clock() public view virtual returns (uint48) {
return Time.blockNumber();
}
/**
* @dev Machine-readable description of the clock as specified in EIP-6372.
*/
// solhint-disable-next-line func-name-mixedcase
function CLOCK_MODE() public view virtual returns (string memory) {
// Check that the clock was not modified
if (clock() != Time.blockNumber()) {
revert ERC6372InconsistentClock();
}
return "mode=blocknumber&from=default";
}
/**
* @dev Returns the current amount of votes that `account` has.
*/
function getVotes(address account) public view virtual returns (uint256) {
VotesStorage storage $ = _getVotesStorage();
return $._delegateCheckpoints[account].latest();
}
/**
* @dev Returns the amount of votes that `account` had at a specific moment in the past. If the `clock()` is
* configured to use block numbers, this will return the value at the end of the corresponding block.
*
* Requirements:
*
* - `timepoint` must be in the past. If operating using block numbers, the block must be already mined.
*/
function getPastVotes(address account, uint256 timepoint) public view virtual returns (uint256) {
VotesStorage storage $ = _getVotesStorage();
uint48 currentTimepoint = clock();
if (timepoint >= currentTimepoint) {
revert ERC5805FutureLookup(timepoint, currentTimepoint);
}
return $._delegateCheckpoints[account].upperLookupRecent(SafeCast.toUint48(timepoint));
}
/**
* @dev Returns the total supply of votes available at a specific moment in the past. If the `clock()` is
* configured to use block numbers, this will return the value at the end of the corresponding block.
*
* NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes.
* Votes that have not been delegated are still part of total supply, even though they would not participate in a
* vote.
*
* Requirements:
*
* - `timepoint` must be in the past. If operating using block numbers, the block must be already mined.
*/
function getPastTotalSupply(uint256 timepoint) public view virtual returns (uint256) {
VotesStorage storage $ = _getVotesStorage();
uint48 currentTimepoint = clock();
if (timepoint >= currentTimepoint) {
revert ERC5805FutureLookup(timepoint, currentTimepoint);
}
return $._totalCheckpoints.upperLookupRecent(SafeCast.toUint48(timepoint));
}
/**
* @dev Returns the current total supply of votes.
*/
function _getTotalSupply() internal view virtual returns (uint256) {
VotesStorage storage $ = _getVotesStorage();
return $._totalCheckpoints.latest();
}
// /**
// * @notice Overrides the standard `VotesUpgradeable.sol` delegates mapping to return
// * the accounts's own address if they haven't delegated.
// * This avoids having to delegate to oneself.
// */
function delegates(address account) public view virtual returns (address) {
VotesStorage storage $ = _getVotesStorage();
return $._delegatee[account] == address(0) ? account : $._delegatee[account];
}
/**
* @dev Delegates votes from the sender to `delegatee`.
*/
function delegate(address delegatee) public virtual {
address account = _msgSender();
_delegate(account, delegatee);
}
/**
* @dev Delegates votes from signer to `delegatee`.
*/
function delegateBySig(
address delegatee,
uint256 nonce,
uint256 expiry,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
if (block.timestamp > expiry) {
revert VotesExpiredSignature(expiry);
}
address signer = ECDSA.recover(
_hashTypedDataV4(keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry))),
v,
r,
s
);
_useCheckedNonce(signer, nonce);
_delegate(signer, delegatee);
}
/**
* @dev Delegate all of `account`'s voting units to `delegatee`.
*
* Emits events {IVotes-DelegateChanged} and {IVotes-DelegateVotesChanged}.
*/
function _delegate(address account, address delegatee) internal virtual {
VotesStorage storage $ = _getVotesStorage();
address oldDelegate = delegates(account);
$._delegatee[account] = delegatee;
emit DelegateChanged(account, oldDelegate, delegatee);
// Do not allow users to delegate to the zero address
// To prevent delegatee from draining all voting units from delegator
// As a result of the change in default behavior of "delegates" function
// Audit info: https://github.com/code-423n4/2023-12-revolutionprotocol-findings/issues/49
require(delegatee != address(0), "Votes: cannot delegate to zero address");
_moveDelegateVotes(oldDelegate, delegatee, _getVotingUnits(account));
}
/**
* @dev Transfers, mints, or burns voting units. To register a mint, `from` should be zero. To register a burn, `to`
* should be zero. Total supply of voting units will be adjusted with mints and burns.
*/
function _transferVotingUnits(address from, address to, uint256 amount) internal virtual {
VotesStorage storage $ = _getVotesStorage();
if (from == address(0)) {
_push($._totalCheckpoints, _add, SafeCast.toUint208(amount));
}
if (to == address(0)) {
_push($._totalCheckpoints, _subtract, SafeCast.toUint208(amount));
}
_moveDelegateVotes(delegates(from), delegates(to), amount);
}
/**
* @dev Moves delegated votes from one delegate to another.
*/
function _moveDelegateVotes(address from, address to, uint256 amount) private {
VotesStorage storage $ = _getVotesStorage();
if (from != to && amount > 0) {
if (from != address(0)) {
(uint256 oldValue, uint256 newValue) = _push(
$._delegateCheckpoints[from],
_subtract,
SafeCast.toUint208(amount)
);
emit DelegateVotesChanged(from, oldValue, newValue);
}
if (to != address(0)) {
(uint256 oldValue, uint256 newValue) = _push(
$._delegateCheckpoints[to],
_add,
SafeCast.toUint208(amount)
);
emit DelegateVotesChanged(to, oldValue, newValue);
}
}
}
/**
* @dev Get number of checkpoints for `account`.
*/
function _numCheckpoints(address account) internal view virtual returns (uint32) {
VotesStorage storage $ = _getVotesStorage();
return SafeCast.toUint32($._delegateCheckpoints[account].length());
}
/**
* @dev Get the `pos`-th checkpoint for `account`.
*/
function _checkpoints(
address account,
uint32 pos
) internal view virtual returns (Checkpoints.Checkpoint208 memory) {
VotesStorage storage $ = _getVotesStorage();
return $._delegateCheckpoints[account].at(pos);
}
function _push(
Checkpoints.Trace208 storage store,
function(uint208, uint208) view returns (uint208) op,
uint208 delta
) private returns (uint208, uint208) {
return store.push(clock(), op(store.latest(), delta));
}
function _add(uint208 a, uint208 b) private pure returns (uint208) {
return a + b;
}
function _subtract(uint208 a, uint208 b) private pure returns (uint208) {
return a - b;
}
/**
* @dev Must return the voting units held by an account.
*/
function _getVotingUnits(address) internal view virtual returns (uint256);
}// SPDX-License-Identifier: BSD-3-Clause
/// @title Revolution DAO Logic interfaces and events
/*********************************
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░█████████░░█████████░░░ *
* ░░░░░░██░░░████░░██░░░████░░░ *
* ░░██████░░░████████░░░████░░░ *
* ░░██░░██░░░████░░██░░░████░░░ *
* ░░██░░██░░░████░░██░░░████░░░ *
* ░░░░░░█████████░░█████████░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
*********************************/
// LICENSE
// RevolutionDAOInterfaces.sol is a modified version of Compound Lab's GovernorBravoInterfaces.sol:
// https://github.com/compound-finance/compound-protocol/blob/b9b14038612d846b83f8a009a82c38974ff2dcfe/contracts/Governance/GovernorBravoInterfaces.sol
//
// GovernorBravoInterfaces.sol source code Copyright 2020 Compound Labs, Inc. licensed under the BSD-3-Clause license.
// With modifications by Nounders DAO.
//
// Additional conditions of BSD-3-Clause can be found here: https://opensource.org/licenses/BSD-3-Clause
//
// MODIFICATIONS
// RevolutionDAOEvents, RevolutionDAOProxyStorage, RevolutionDAOStorageV1 add support for changes made by Revolution DAO to GovernorBravo.sol
// See RevolutionDAOLogicV1.sol for more details.
import { IDAOExecutor } from "../interfaces/IDAOExecutor.sol";
import { IRevolutionBuilder } from "../interfaces/IRevolutionBuilder.sol";
import { IUpgradeManager } from "@cobuild/utility-contracts/src/interfaces/IUpgradeManager.sol";
import { IRevolutionVotingPower } from "../interfaces/IRevolutionVotingPower.sol";
pragma solidity 0.8.22;
contract RevolutionDAOEvents {
/// @notice An event emitted when a new proposal is created
event ProposalCreated(
uint256 id,
address proposer,
address[] targets,
uint256[] values,
string[] signatures,
bytes[] calldatas,
uint256 startBlock,
uint256 endBlock,
string description
);
/// @notice An event emitted when a new proposal is created, which includes additional information
event ProposalCreatedWithRequirements(
uint256 id,
address proposer,
address[] targets,
uint256[] values,
string[] signatures,
bytes[] calldatas,
uint256 startBlock,
uint256 endBlock,
uint256 proposalThreshold,
uint256 quorumVotes,
string description
);
/// @notice An event emitted when a vote has been cast on a proposal
/// @param voter The address which casted a vote
/// @param proposalId The proposal id which was voted on
/// @param support Support value for the vote. 0=against, 1=for, 2=abstain
/// @param votes Number of votes which were cast by the voter
/// @param reason The reason given for the vote by the voter
event VoteCast(address indexed voter, uint256 proposalId, uint8 support, uint256 votes, string reason);
/// @notice An event emitted when a proposal has been canceled
event ProposalCanceled(uint256 id);
/// @notice An event emitted when a proposal has been queued in the DAOExecutor
event ProposalQueued(uint256 id, uint256 eta);
/// @notice An event emitted when a proposal has been executed in the DAOExecutor
event ProposalExecuted(uint256 id);
/// @notice An event emitted when a proposal has been vetoed by vetoAddress
event ProposalVetoed(uint256 id);
/// @notice An event emitted when the voting delay is set
event VotingDelaySet(uint256 oldVotingDelay, uint256 newVotingDelay);
/// @notice An event emitted when the voting period is set
event VotingPeriodSet(uint256 oldVotingPeriod, uint256 newVotingPeriod);
/// @notice Emitted when implementation is changed
event NewImplementation(address oldImplementation, address newImplementation);
/// @notice Emitted when proposal threshold basis points is set
event ProposalThresholdBPSSet(uint256 oldProposalThresholdBPS, uint256 newProposalThresholdBPS);
/// @notice Emitted when quorum votes basis points is set
event QuorumVotesBPSSet(uint256 oldQuorumVotesBPS, uint256 newQuorumVotesBPS);
/// @notice Emitted when pendingAdmin is changed
event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin);
/// @notice Emitted when pendingAdmin is accepted, which means admin is updated
event NewAdmin(address oldAdmin, address newAdmin);
/// @notice Emitted when vetoer is changed
event NewVetoer(address oldVetoer, address newVetoer);
/// @notice Emitted when minQuorumVotesBPS is set
event MinQuorumVotesBPSSet(uint16 oldMinQuorumVotesBPS, uint16 newMinQuorumVotesBPS);
/// @notice Emitted when maxQuorumVotesBPS is set
event MaxQuorumVotesBPSSet(uint16 oldMaxQuorumVotesBPS, uint16 newMaxQuorumVotesBPS);
/// @notice Emitted when quorumCoefficient is set
event QuorumCoefficientSet(uint32 oldQuorumCoefficient, uint32 newQuorumCoefficient);
/// @notice Emitted when a voter cast a vote requesting a gas refund.
event RefundableVote(address indexed voter, uint256 refundAmount, bool refundSent);
/// @notice Emitted when admin withdraws the DAO's balance.
event Withdraw(uint256 amount, bool sent);
/// @notice Emitted when pendingVetoer is changed
event NewPendingVetoer(address oldPendingVetoer, address newPendingVetoer);
}
contract RevolutionDAOProxyStorage {
/// @notice Administrator for this contract
address public admin;
/// @notice Pending administrator for this contract
address public pendingAdmin;
/// @notice Active brains of Governor
address public implementation;
}
/**
* @title Storage for Governor Bravo Delegate
* @notice For future upgrades, do not change RevolutionDAOStorageV1. Create a new
* contract which implements RevolutionDAOStorageV1 and following the naming convention
* RevolutionDAOStorageVX.
*/
contract RevolutionDAOStorageV1 is RevolutionDAOProxyStorage {
/// ///
/// ERRORS ///
/// ///
/// @dev Introduced these errors to reduce contract size, to avoid deployment failure
/// @dev Reverts if the caller is not the manager.
error NOT_MANAGER();
/// @dev Reverts if the provided executor address is invalid (zero address).
error INVALID_EXECUTOR_ADDRESS();
/// @dev Reverts if the provided RevolutionVotingPower address is invalid (zero address).
error INVALID_VOTINGPOWER_ADDRESS();
/// @dev Reverts if the voting period is outside the allowed range.
error INVALID_VOTING_PERIOD();
/// @dev Reverts if the voting delay is outside the allowed range.
error INVALID_VOTING_DELAY();
/// @dev Reverts if the proposal threshold basis points are outside the allowed range.
error INVALID_PROPOSAL_THRESHOLD_BPS();
/// @dev Reverts if the proposer's votes are below the proposal threshold.
error PROPOSER_VOTES_BELOW_THRESHOLD();
/// @dev Reverts if the lengths of proposal arrays (targets, values, signatures, calldatas) do not match.
error PROPOSAL_FUNCTION_PARITY_MISMATCH();
/// @dev Reverts if no actions are provided in the proposal.
error NO_ACTIONS_PROVIDED();
/// @dev Reverts if the number of actions in the proposal exceeds the maximum allowed.
error TOO_MANY_ACTIONS();
/// @dev Reverts if the proposer already has an active proposal.
error ACTIVE_PROPOSAL_EXISTS();
/// @dev Reverts if the proposer already has a pending proposal.
error PENDING_PROPOSAL_EXISTS();
/// @dev Reverts if the proposal is not in the 'Succeeded' state when attempting to queue.
error PROPOSAL_NOT_SUCCEEDED();
/// @dev Reverts if the proposal is not currently in an active state for voting.
error VOTING_CLOSED();
/// @dev Reverts if an invalid vote type is provided (vote type must be within a certain range).
error INVALID_VOTE_TYPE();
/// @dev Reverts if the voter has already cast a vote for the proposal.
error VOTER_ALREADY_VOTED();
/// @dev Reverts if the new minimum quorum votes basis points are outside the allowed bounds.
error INVALID_MIN_QUORUM_VOTES_BPS();
/// @dev Reverts if the new minimum quorum votes basis points exceed the maximum quorum votes basis points.
error MIN_QUORUM_EXCEEDS_MAX();
/// @dev Reverts if the new maximum quorum votes basis points exceed the upper bound.
error INVALID_MAX_QUORUM_VOTES_BPS();
/// @dev Reverts if the minimum quorum votes basis points are greater than the new maximum quorum votes basis points.
error MAX_QUORUM_EXCEEDS_MIN();
/// @dev Reverts if the caller is not the pending admin or is the zero address.
error PENDING_ADMIN_ONLY();
/// @dev Reverts if the caller is not the admin.
error ADMIN_ONLY();
/// @dev Reverts if the caller is not the vetoer.
error VETOER_ONLY();
/// @dev Reverts if the vetoer has been burned
error VETOER_BURNED();
/// @dev Reverts if the caller is not the pending vetoer.
error PENDING_VETOER_ONLY();
/// @dev Reverts if the minimum quorum votes basis points are greater than the maximum quorum votes basis points.
error MIN_QUORUM_BPS_GREATER_THAN_MAX_QUORUM_BPS();
/// @dev Reverts if an unsafe cast to uint16 is attempted.
error UNSAFE_UINT16_CAST();
/// @dev Reverts if an attempt is made to veto an already executed proposal.
error CANT_VETO_EXECUTED_PROPOSAL();
/// @dev Reverts if an attempt is made to cancel an already executed proposal.
error CANT_CANCEL_EXECUTED_PROPOSAL();
/// @dev Reverts if the caller is not the proposer and the proposer's votes are still above the proposal threshold.
error PROPOSER_ABOVE_THRESHOLD();
/// @dev Reverts if the proposal ID is invalid (greater than the current proposal count).
error INVALID_PROPOSAL_ID();
/// @dev Reverts if an identical proposal action is already queued at the same eta.
error PROPOSAL_ACTION_ALREADY_QUEUED();
/// @dev Reverts if the proposal is not in the 'Queued' state when attempting to execute.
error PROPOSAL_NOT_QUEUED();
/// @dev Reverts if the signatory is the zero address, indicating an invalid signature.
error INVALID_SIGNATURE();
/// ///
/// STATE ///
/// ///
/// @notice The contract upgrade manager
IUpgradeManager public immutable manager;
/// @notice The name of this revolution
string public name;
/// @notice The purpose of this revolution
string public purpose;
/// @notice The flag of this revolution
string public flag;
/// @notice Vetoer who has the ability to veto any proposal
address public vetoer;
/// @notice The delay before voting on a proposal may take place, once proposed, in blocks
uint256 public votingDelay;
/// @notice The duration of voting on a proposal, in blocks
uint256 public votingPeriod;
/// @notice The basis point number of votes required in order for a voter to become a proposer. *DIFFERS from GovernerBravo
uint256 public proposalThresholdBPS;
/// @notice The basis point number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed. *DIFFERS from GovernerBravo
uint256 public quorumVotesBPS;
/// @notice The total number of proposals
uint256 public proposalCount;
/// @notice The address of the Revolution DAO Executor DAOExecutor
IDAOExecutor public timelock;
/// @notice The RevolutionVotingPower contract
IRevolutionVotingPower public votingPower;
/// @notice The official record of all proposals ever proposed
mapping(uint256 => Proposal) internal _proposals;
/// @notice The latest proposal for each proposer
mapping(address => uint256) public latestProposalIds;
DynamicQuorumParamsCheckpoint[] public quorumParamsCheckpoints;
/// @notice Pending new vetoer
address public pendingVetoer;
/// ///
/// CONSTANTS ///
/// ///
struct Proposal {
/// @notice Unique id for looking up a proposal
uint256 id;
/// @notice Creator of the proposal
address proposer;
/// @notice The number of votes needed to create a proposal at the time of proposal creation. *DIFFERS from GovernerBravo
uint256 proposalThreshold;
/// @notice The number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed at the time of proposal creation. *DIFFERS from GovernerBravo
uint256 quorumVotes;
/// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds
uint256 eta;
/// @notice the ordered list of target addresses for calls to be made
address[] targets;
/// @notice The ordered list of values (i.e. msg.value) to be passed to the calls to be made
uint256[] values;
/// @notice The ordered list of function signatures to be called
string[] signatures;
/// @notice The ordered list of calldata to be passed to each call
bytes[] calldatas;
/// @notice The block at which voting begins: holders must delegate their votes prior to this block
uint256 startBlock;
/// @notice The block at which voting ends: votes must be cast prior to this block
uint256 endBlock;
/// @notice Current number of votes in favor of this proposal
uint256 forVotes;
/// @notice Current number of votes in opposition to this proposal
uint256 againstVotes;
/// @notice Current number of votes for abstaining for this proposal
uint256 abstainVotes;
/// @notice Flag marking whether the proposal has been canceled
bool canceled;
/// @notice Flag marking whether the proposal has been vetoed
bool vetoed;
/// @notice Flag marking whether the proposal has been executed
bool executed;
/// @notice Receipts of ballots for the entire set of voters
mapping(address => Receipt) receipts;
/// @notice The total weighted supply at the time of proposal creation
uint256 totalWeightedSupply;
/// @notice The total supply of points at the time of proposal creation
uint256 revolutionPointsSupply;
/// @notice The total supply of revolution at the time of proposal creation
uint256 revolutionTokenSupply;
/// @notice The block at which this proposal was created
uint256 creationBlock;
}
/// @notice Ballot receipt record for a voter
struct Receipt {
/// @notice Whether or not a vote has been cast
bool hasVoted;
/// @notice Whether or not the voter supports the proposal or abstains
uint8 support;
/// @notice The number of votes the voter had, which were cast
uint256 votes;
}
/// @notice Possible states that a proposal may be in
enum ProposalState {
Pending,
Active,
Canceled,
Defeated,
Succeeded,
Queued,
Expired,
Executed,
Vetoed
}
struct DynamicQuorumParams {
/// @notice The minimum basis point number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed.
uint16 minQuorumVotesBPS;
/// @notice The maximum basis point number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed.
uint16 maxQuorumVotesBPS;
/// @notice The dynamic quorum coefficient
/// @dev Assumed to be fixed point integer with 6 decimals, i.e 0.2 is represented as 0.2 * 1e6 = 200000
uint32 quorumCoefficient;
}
/// @notice A checkpoint for storing dynamic quorum params from a given block
struct DynamicQuorumParamsCheckpoint {
/// @notice The block at which the new values were set
uint32 fromBlock;
/// @notice The parameter values of this checkpoint
DynamicQuorumParams params;
}
struct ProposalCondensed {
/// @notice Unique id for looking up a proposal
uint256 id;
/// @notice Creator of the proposal
address proposer;
/// @notice The number of votes needed to create a proposal at the time of proposal creation. *DIFFERS from GovernerBravo
uint256 proposalThreshold;
/// @notice The minimum number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed at the time of proposal creation. *DIFFERS from GovernerBravo
uint256 quorumVotes;
/// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds
uint256 eta;
/// @notice The block at which voting begins: holders must delegate their votes prior to this block
uint256 startBlock;
/// @notice The block at which voting ends: votes must be cast prior to this block
uint256 endBlock;
/// @notice Current number of votes in favor of this proposal
uint256 forVotes;
/// @notice Current number of votes in opposition to this proposal
uint256 againstVotes;
/// @notice Current number of votes for abstaining for this proposal
uint256 abstainVotes;
/// @notice Flag marking whether the proposal has been canceled
bool canceled;
/// @notice Flag marking whether the proposal has been vetoed
bool vetoed;
/// @notice Flag marking whether the proposal has been executed
bool executed;
/// @notice The total weighted supply at the time of proposal creation
uint256 totalWeightedSupply;
/// @notice The block at which this proposal was created
uint256 creationBlock;
}
}
interface RevolutionTokenLike {
function getPastVotes(address account, uint256 blockNumber) external view returns (uint96);
function totalSupply() external view returns (uint256);
}
interface PointsLike {
function getPastVotes(address account, uint256 blockNumber) external view returns (uint96);
function totalSupply() external view returns (uint256);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.22;
/// @title RevolutionBuilderTypesV1
/// @author rocketman
/// @notice The external Base Metadata errors and functions
interface RevolutionBuilderTypesV1 {
/// @notice Stores deployed addresses for a given token's DAO
struct DAOAddresses {
/// @notice Address for deployed metadata contract
address descriptor;
/// @notice Address for deployed auction contract
address auction;
/// @notice Address for deployed auction contract
address revolutionPointsEmitter;
/// @notice Address for deployed auction contract
address revolutionPoints;
/// @notice Address for deployed cultureIndex contract
address cultureIndex;
/// @notice Address for deployed executor (treasury) contract
address executor;
/// @notice Address for deployed DAO contract
address dao;
/// @notice Address for deployed ERC-721 token contract
address revolutionToken;
/// @notice Address for deployed MaxHeap contract
address maxHeap;
/// @notice Address for deployed RevolutionVotingPower contract
address revolutionVotingPower;
/// @notice Address for deployed VRGDA contract
address vrgda;
/// @notice Address for the deployed splits factory contract
address splitsCreator;
}
struct InitialProxySetup {
address revolutionToken;
address executor;
address revolutionVotingPower;
address revolutionPointsEmitter;
address dao;
bytes32 salt;
}
enum ImplementationType {
DAO,
Executor,
VRGDAC,
Descriptor,
Auction,
CultureIndex,
MaxHeap,
RevolutionPoints,
RevolutionPointsEmitter,
RevolutionToken,
RevolutionVotingPower,
SplitsCreator
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @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.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard ERC20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
*/
interface IERC20Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/
error ERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
* Used in balance queries.
* @param owner Address of the current owner of a token.
*/
error ERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/
error ERC721NonexistentToken(uint256 tokenId);
/**
* @dev Indicates an error related to the ownership over a particular token. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param tokenId Identifier number of a token.
* @param owner Address of the current owner of a token.
*/
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC721InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param tokenId Identifier number of a token.
*/
error ERC721InsufficientApproval(address operator, uint256 tokenId);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC721InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
*/
interface IERC1155Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
* @param tokenId Identifier number of a token.
*/
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC1155InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param owner Address of the current owner of a token.
*/
error ERC1155MissingApprovalForAll(address operator, address owner);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC1155InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC1155InvalidOperator(address operator);
/**
* @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
* Used in batch transfers.
* @param idsLength Length of the array of token identifiers
* @param valuesLength Length of the array of token amounts
*/
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.20;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.22;
/// @title IERC1967Upgrade
/// @author Rohan Kulkarni
/// @notice The external ERC1967Upgrade events and errors
interface IERC1967Upgrade {
/// ///
/// EVENTS ///
/// ///
/// @notice Emitted when the implementation is upgraded
/// @param impl The address of the implementation
event Upgraded(address impl);
/// ///
/// ERRORS ///
/// ///
/// @dev Reverts if an implementation is an invalid upgrade
/// @param impl The address of the invalid implementation
error INVALID_UPGRADE(address impl);
/// @dev Reverts if an implementation upgrade is not stored at the storage slot of the original
error UNSUPPORTED_UUID();
/// @dev Reverts if an implementation does not support ERC1822 proxiableUUID()
error ONLY_UUPS();
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.22;
/// @title IProtocolRewards
/// @notice The interface for deposits & withdrawals for Protocol Rewards
interface IProtocolRewards {
/// @notice Rewards Deposit Event
/// @param builderReferral Builder referral
/// @param purchaseReferral Purchase referral user
/// @param deployer Deployer reward recipient
/// @param revolution Revolution recipient
/// @param from The caller of the deposit
/// @param builderReferralReward Builder referral reward
/// @param purchaseReferralReward Purchase referral amount
/// @param deployerReward Deployer reward amount
/// @param revolutionReward Revolution amount
event RewardsDeposit(
address indexed builderReferral,
address indexed purchaseReferral,
address deployer,
address revolution,
address from,
uint256 builderReferralReward,
uint256 purchaseReferralReward,
uint256 deployerReward,
uint256 revolutionReward
);
/// @notice Deposit Event
/// @param from From user
/// @param to To user (within contract)
/// @param reason Optional bytes4 reason for indexing
/// @param amount Amount of deposit
/// @param comment Optional user comment
event Deposit(address indexed from, address indexed to, bytes4 indexed reason, uint256 amount, string comment);
/// @notice Withdraw Event
/// @param from From user
/// @param to To user (within contract)
/// @param amount Amount of deposit
event Withdraw(address indexed from, address indexed to, uint256 amount);
/// @notice Cannot send to address zero
error ADDRESS_ZERO();
/// @notice Function argument array length mismatch
error ARRAY_LENGTH_MISMATCH();
/// @notice Invalid deposit
error INVALID_DEPOSIT();
/// @notice Invalid signature for deposit
error INVALID_SIGNATURE();
/// @notice Invalid withdraw
error INVALID_WITHDRAW();
/// @notice Signature for withdraw is too old and has expired
error SIGNATURE_DEADLINE_EXPIRED();
/// @notice Low-level ETH transfer has failed
error TRANSFER_FAILED();
/// @notice Generic function to deposit ETH for a recipient, with an optional comment
/// @param to Address to deposit to
/// @param to Reason system reason for deposit (used for indexing)
/// @param comment Optional comment as reason for deposit
function deposit(address to, bytes4 why, string calldata comment) external payable;
/// @notice Generic function to deposit ETH for multiple recipients, with an optional comment
/// @param recipients recipients to send the amount to, array aligns with amounts
/// @param amounts amounts to send to each recipient, array aligns with recipients
/// @param reasons optional bytes4 hash for indexing
/// @param comment Optional comment to include with purchase
function depositBatch(
address[] calldata recipients,
uint256[] calldata amounts,
bytes4[] calldata reasons,
string calldata comment
) external payable;
/// @notice Used by Revolution token contracts to deposit protocol rewards
/// @param builderReferral Builder referral
/// @param builderReferralReward Builder referral reward
/// @param purchaseReferral Purchase referral user
/// @param purchaseReferralReward Purchase referral amount
/// @param deployer Deployer
/// @param deployerReward Deployer reward amount
/// @param revolution Revolution recipient
/// @param revolutionReward Revolution amount
function depositRewards(
address builderReferral,
uint256 builderReferralReward,
address purchaseReferral,
uint256 purchaseReferralReward,
address deployer,
uint256 deployerReward,
address revolution,
uint256 revolutionReward
) external payable;
/// @notice Withdraw protocol rewards
/// @param to Withdraws from msg.sender to this address
/// @param amount amount to withdraw
function withdraw(address to, uint256 amount) external;
/// @notice Execute a withdraw of protocol rewards via signature
/// @param from Withdraw from this address
/// @param to Withdraw to this address
/// @param amount Amount to withdraw
/// @param deadline Deadline for the signature to be valid
/// @param v V component of signature
/// @param r R component of signature
/// @param s S component of signature
function withdrawWithSig(
address from,
address to,
uint256 amount,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/ERC721.sol)
pragma solidity ^0.8.20;
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import {IERC721Metadata} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
import {ContextUpgradeable} from "../../utils/ContextUpgradeable.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {ERC165Upgradeable} from "../../utils/introspection/ERC165Upgradeable.sol";
import {IERC721Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
* the Metadata extension, but not including the Enumerable extension, which is available separately as
* {ERC721Enumerable}.
*/
abstract contract ERC721Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradeable, IERC721, IERC721Metadata, IERC721Errors {
using Strings for uint256;
/// @custom:storage-location erc7201:openzeppelin.storage.ERC721
struct ERC721Storage {
// Token name
string _name;
// Token symbol
string _symbol;
mapping(uint256 tokenId => address) _owners;
mapping(address owner => uint256) _balances;
mapping(uint256 tokenId => address) _tokenApprovals;
mapping(address owner => mapping(address operator => bool)) _operatorApprovals;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ERC721")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ERC721StorageLocation = 0x80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab0079300;
function _getERC721Storage() private pure returns (ERC721Storage storage $) {
assembly {
$.slot := ERC721StorageLocation
}
}
/**
* @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
*/
function __ERC721_init(string memory name_, string memory symbol_) internal onlyInitializing {
__ERC721_init_unchained(name_, symbol_);
}
function __ERC721_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {
ERC721Storage storage $ = _getERC721Storage();
$._name = name_;
$._symbol = symbol_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165Upgradeable, IERC165) returns (bool) {
return
interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC721Metadata).interfaceId ||
super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC721-balanceOf}.
*/
function balanceOf(address owner) public view virtual returns (uint256) {
ERC721Storage storage $ = _getERC721Storage();
if (owner == address(0)) {
revert ERC721InvalidOwner(address(0));
}
return $._balances[owner];
}
/**
* @dev See {IERC721-ownerOf}.
*/
function ownerOf(uint256 tokenId) public view virtual returns (address) {
return _requireOwned(tokenId);
}
/**
* @dev See {IERC721Metadata-name}.
*/
function name() public view virtual returns (string memory) {
ERC721Storage storage $ = _getERC721Storage();
return $._name;
}
/**
* @dev See {IERC721Metadata-symbol}.
*/
function symbol() public view virtual returns (string memory) {
ERC721Storage storage $ = _getERC721Storage();
return $._symbol;
}
/**
* @dev See {IERC721Metadata-tokenURI}.
*/
function tokenURI(uint256 tokenId) public view virtual returns (string memory) {
_requireOwned(tokenId);
string memory baseURI = _baseURI();
return bytes(baseURI).length > 0 ? string.concat(baseURI, tokenId.toString()) : "";
}
/**
* @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
* token will be the concatenation of the `baseURI` and the `tokenId`. Empty
* by default, can be overridden in child contracts.
*/
function _baseURI() internal view virtual returns (string memory) {
return "";
}
/**
* @dev See {IERC721-approve}.
*/
function approve(address to, uint256 tokenId) public virtual {
_approve(to, tokenId, _msgSender());
}
/**
* @dev See {IERC721-getApproved}.
*/
function getApproved(uint256 tokenId) public view virtual returns (address) {
_requireOwned(tokenId);
return _getApproved(tokenId);
}
/**
* @dev See {IERC721-setApprovalForAll}.
*/
function setApprovalForAll(address operator, bool approved) public virtual {
_setApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev See {IERC721-isApprovedForAll}.
*/
function isApprovedForAll(address owner, address operator) public view virtual returns (bool) {
ERC721Storage storage $ = _getERC721Storage();
return $._operatorApprovals[owner][operator];
}
/**
* @dev See {IERC721-transferFrom}.
*/
function transferFrom(address from, address to, uint256 tokenId) public virtual {
if (to == address(0)) {
revert ERC721InvalidReceiver(address(0));
}
// Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists
// (from != 0). Therefore, it is not needed to verify that the return value is not 0 here.
address previousOwner = _update(to, tokenId, _msgSender());
if (previousOwner != from) {
revert ERC721IncorrectOwner(from, tokenId, previousOwner);
}
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) public {
safeTransferFrom(from, to, tokenId, "");
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual {
transferFrom(from, to, tokenId);
_checkOnERC721Received(from, to, tokenId, data);
}
/**
* @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist
*
* IMPORTANT: Any overrides to this function that add ownership of tokens not tracked by the
* core ERC721 logic MUST be matched with the use of {_increaseBalance} to keep balances
* consistent with ownership. The invariant to preserve is that for any address `a` the value returned by
* `balanceOf(a)` must be equal to the number of tokens such that `_ownerOf(tokenId)` is `a`.
*/
function _ownerOf(uint256 tokenId) internal view virtual returns (address) {
ERC721Storage storage $ = _getERC721Storage();
return $._owners[tokenId];
}
/**
* @dev Returns the approved address for `tokenId`. Returns 0 if `tokenId` is not minted.
*/
function _getApproved(uint256 tokenId) internal view virtual returns (address) {
ERC721Storage storage $ = _getERC721Storage();
return $._tokenApprovals[tokenId];
}
/**
* @dev Returns whether `spender` is allowed to manage `owner`'s tokens, or `tokenId` in
* particular (ignoring whether it is owned by `owner`).
*
* WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this
* assumption.
*/
function _isAuthorized(address owner, address spender, uint256 tokenId) internal view virtual returns (bool) {
return
spender != address(0) &&
(owner == spender || isApprovedForAll(owner, spender) || _getApproved(tokenId) == spender);
}
/**
* @dev Checks if `spender` can operate on `tokenId`, assuming the provided `owner` is the actual owner.
* Reverts if `spender` does not have approval from the provided `owner` for the given token or for all its assets
* the `spender` for the specific `tokenId`.
*
* WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this
* assumption.
*/
function _checkAuthorized(address owner, address spender, uint256 tokenId) internal view virtual {
if (!_isAuthorized(owner, spender, tokenId)) {
if (owner == address(0)) {
revert ERC721NonexistentToken(tokenId);
} else {
revert ERC721InsufficientApproval(spender, tokenId);
}
}
}
/**
* @dev Unsafe write access to the balances, used by extensions that "mint" tokens using an {ownerOf} override.
*
* NOTE: the value is limited to type(uint128).max. This protect against _balance overflow. It is unrealistic that
* a uint256 would ever overflow from increments when these increments are bounded to uint128 values.
*
* WARNING: Increasing an account's balance using this function tends to be paired with an override of the
* {_ownerOf} function to resolve the ownership of the corresponding tokens so that balances and ownership
* remain consistent with one another.
*/
function _increaseBalance(address account, uint128 value) internal virtual {
ERC721Storage storage $ = _getERC721Storage();
unchecked {
$._balances[account] += value;
}
}
/**
* @dev Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner
* (or `to`) is the zero address. Returns the owner of the `tokenId` before the update.
*
* The `auth` argument is optional. If the value passed is non 0, then this function will check that
* `auth` is either the owner of the token, or approved to operate on the token (by the owner).
*
* Emits a {Transfer} event.
*
* NOTE: If overriding this function in a way that tracks balances, see also {_increaseBalance}.
*/
function _update(address to, uint256 tokenId, address auth) internal virtual returns (address) {
ERC721Storage storage $ = _getERC721Storage();
address from = _ownerOf(tokenId);
// Perform (optional) operator check
if (auth != address(0)) {
_checkAuthorized(from, auth, tokenId);
}
// Execute the update
if (from != address(0)) {
// Clear approval. No need to re-authorize or emit the Approval event
_approve(address(0), tokenId, address(0), false);
unchecked {
$._balances[from] -= 1;
}
}
if (to != address(0)) {
unchecked {
$._balances[to] += 1;
}
}
$._owners[tokenId] = to;
emit Transfer(from, to, tokenId);
return from;
}
/**
* @dev Mints `tokenId` and transfers it to `to`.
*
* WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
*
* Requirements:
*
* - `tokenId` must not exist.
* - `to` cannot be the zero address.
*
* Emits a {Transfer} event.
*/
function _mint(address to, uint256 tokenId) internal {
if (to == address(0)) {
revert ERC721InvalidReceiver(address(0));
}
address previousOwner = _update(to, tokenId, address(0));
if (previousOwner != address(0)) {
revert ERC721InvalidSender(address(0));
}
}
/**
* @dev Mints `tokenId`, transfers it to `to` and checks for `to` acceptance.
*
* Requirements:
*
* - `tokenId` must not exist.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function _safeMint(address to, uint256 tokenId) internal {
_safeMint(to, tokenId, "");
}
/**
* @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
* forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
*/
function _safeMint(address to, uint256 tokenId, bytes memory data) internal virtual {
_mint(to, tokenId);
_checkOnERC721Received(address(0), to, tokenId, data);
}
/**
* @dev Destroys `tokenId`.
* The approval is cleared when the token is burned.
* This is an internal function that does not check if the sender is authorized to operate on the token.
*
* Requirements:
*
* - `tokenId` must exist.
*
* Emits a {Transfer} event.
*/
function _burn(uint256 tokenId) internal {
address previousOwner = _update(address(0), tokenId, address(0));
if (previousOwner == address(0)) {
revert ERC721NonexistentToken(tokenId);
}
}
/**
* @dev Transfers `tokenId` from `from` to `to`.
* As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
*
* Emits a {Transfer} event.
*/
function _transfer(address from, address to, uint256 tokenId) internal {
if (to == address(0)) {
revert ERC721InvalidReceiver(address(0));
}
address previousOwner = _update(to, tokenId, address(0));
if (previousOwner == address(0)) {
revert ERC721NonexistentToken(tokenId);
} else if (previousOwner != from) {
revert ERC721IncorrectOwner(from, tokenId, previousOwner);
}
}
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking that contract recipients
* are aware of the ERC721 standard to prevent tokens from being forever locked.
*
* `data` is additional data, it has no specified format and it is sent in call to `to`.
*
* This internal function is like {safeTransferFrom} in the sense that it invokes
* {IERC721Receiver-onERC721Received} on the receiver, and can be used to e.g.
* implement alternative mechanisms to perform token transfer, such as signature-based.
*
* Requirements:
*
* - `tokenId` token must exist and be owned by `from`.
* - `to` cannot be the zero address.
* - `from` cannot be the zero address.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function _safeTransfer(address from, address to, uint256 tokenId) internal {
_safeTransfer(from, to, tokenId, "");
}
/**
* @dev Same as {xref-ERC721-_safeTransfer-address-address-uint256-}[`_safeTransfer`], with an additional `data` parameter which is
* forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
*/
function _safeTransfer(address from, address to, uint256 tokenId, bytes memory data) internal virtual {
_transfer(from, to, tokenId);
_checkOnERC721Received(from, to, tokenId, data);
}
/**
* @dev Approve `to` to operate on `tokenId`
*
* The `auth` argument is optional. If the value passed is non 0, then this function will check that `auth` is
* either the owner of the token, or approved to operate on all tokens held by this owner.
*
* Emits an {Approval} event.
*
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
*/
function _approve(address to, uint256 tokenId, address auth) internal {
_approve(to, tokenId, auth, true);
}
/**
* @dev Variant of `_approve` with an optional flag to enable or disable the {Approval} event. The event is not
* emitted in the context of transfers.
*/
function _approve(address to, uint256 tokenId, address auth, bool emitEvent) internal virtual {
ERC721Storage storage $ = _getERC721Storage();
// Avoid reading the owner unless necessary
if (emitEvent || auth != address(0)) {
address owner = _requireOwned(tokenId);
// We do not use _isAuthorized because single-token approvals should not be able to call approve
if (auth != address(0) && owner != auth && !isApprovedForAll(owner, auth)) {
revert ERC721InvalidApprover(auth);
}
if (emitEvent) {
emit Approval(owner, to, tokenId);
}
}
$._tokenApprovals[tokenId] = to;
}
/**
* @dev Approve `operator` to operate on all of `owner` tokens
*
* Requirements:
* - operator can't be the address zero.
*
* Emits an {ApprovalForAll} event.
*/
function _setApprovalForAll(address owner, address operator, bool approved) internal virtual {
ERC721Storage storage $ = _getERC721Storage();
if (operator == address(0)) {
revert ERC721InvalidOperator(operator);
}
$._operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
/**
* @dev Reverts if the `tokenId` doesn't have a current owner (it hasn't been minted, or it has been burned).
* Returns the owner.
*
* Overrides to ownership logic should be done to {_ownerOf}.
*/
function _requireOwned(uint256 tokenId) internal view returns (address) {
address owner = _ownerOf(tokenId);
if (owner == address(0)) {
revert ERC721NonexistentToken(tokenId);
}
return owner;
}
/**
* @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target address. This will revert if the
* recipient doesn't accept the token transfer. The call is not executed if the target address is not a contract.
*
* @param from address representing the previous owner of the given token ID
* @param to target address that will receive the tokens
* @param tokenId uint256 ID of the token to be transferred
* @param data bytes optional data to send along with the call
*/
function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory data) private {
if (to.code.length > 0) {
try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {
if (retval != IERC721Receiver.onERC721Received.selector) {
revert ERC721InvalidReceiver(to);
}
} catch (bytes memory reason) {
if (reason.length == 0) {
revert ERC721InvalidReceiver(to);
} else {
/// @solidity memory-safe-assembly
assembly {
revert(add(32, reason), mload(reason))
}
}
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Enumerable.sol)
pragma solidity ^0.8.20;
import {IERC721} from "../IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
interface IERC721Enumerable is IERC721 {
/**
* @dev Returns the total amount of tokens stored by the contract.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns a token ID owned by `owner` at a given `index` of its token list.
* Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
*/
function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
/**
* @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
* Use along with {totalSupply} to enumerate all tokens.
*/
function tokenByIndex(uint256 index) external view returns (uint256);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @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}.
*/
interface IERC165 {
/**
* @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.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5805.sol)
pragma solidity ^0.8.20;
import {IVotes} from "../governance/utils/IVotes.sol";
import {IERC6372} from "./IERC6372.sol";
interface IERC5805 is IERC6372, IVotes {}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Nonces.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Provides tracking nonces for addresses. Nonces will only increment.
*/
abstract contract NoncesUpgradeable is Initializable {
/**
* @dev The nonce used for an `account` is not the expected current nonce.
*/
error InvalidAccountNonce(address account, uint256 currentNonce);
/// @custom:storage-location erc7201:openzeppelin.storage.Nonces
struct NoncesStorage {
mapping(address account => uint256) _nonces;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Nonces")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant NoncesStorageLocation = 0x5ab42ced628888259c08ac98db1eb0cf702fc1501344311d8b100cd1bfe4bb00;
function _getNoncesStorage() private pure returns (NoncesStorage storage $) {
assembly {
$.slot := NoncesStorageLocation
}
}
function __Nonces_init() internal onlyInitializing {
}
function __Nonces_init_unchained() internal onlyInitializing {
}
/**
* @dev Returns the next unused nonce for an address.
*/
function nonces(address owner) public view virtual returns (uint256) {
NoncesStorage storage $ = _getNoncesStorage();
return $._nonces[owner];
}
/**
* @dev Consumes a nonce.
*
* Returns the current value and increments nonce.
*/
function _useNonce(address owner) internal virtual returns (uint256) {
NoncesStorage storage $ = _getNoncesStorage();
// For each account, the nonce has an initial value of 0, can only be incremented by one, and cannot be
// decremented or reset. This guarantees that the nonce never overflows.
unchecked {
// It is important to do x++ and not ++x here.
return $._nonces[owner]++;
}
}
/**
* @dev Same as {_useNonce} but checking that `nonce` is the next valid for `owner`.
*/
function _useCheckedNonce(address owner, uint256 nonce) internal virtual {
uint256 current = _useNonce(owner);
if (nonce != current) {
revert InvalidAccountNonce(owner, current);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/EIP712.sol)
pragma solidity ^0.8.20;
import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
import {IERC5267} from "@openzeppelin/contracts/interfaces/IERC5267.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";
/**
* @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
*
* The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose
* encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract
* does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to
* produce the hash of their typed data using a combination of `abi.encode` and `keccak256`.
*
* This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
* scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
* ({_hashTypedDataV4}).
*
* The implementation of the domain separator was designed to be as efficient as possible while still properly updating
* the chain id to protect against replay attacks on an eventual fork of the chain.
*
* NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
* https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
*
* NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
* separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the
* separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
*/
abstract contract EIP712Upgradeable is Initializable, IERC5267 {
bytes32 private constant TYPE_HASH =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
/// @custom:storage-location erc7201:openzeppelin.storage.EIP712
struct EIP712Storage {
/// @custom:oz-renamed-from _HASHED_NAME
bytes32 _hashedName;
/// @custom:oz-renamed-from _HASHED_VERSION
bytes32 _hashedVersion;
string _name;
string _version;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.EIP712")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant EIP712StorageLocation = 0xa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100;
function _getEIP712Storage() private pure returns (EIP712Storage storage $) {
assembly {
$.slot := EIP712StorageLocation
}
}
/**
* @dev Initializes the domain separator and parameter caches.
*
* The meaning of `name` and `version` is specified in
* https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
*
* - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
* - `version`: the current major version of the signing domain.
*
* NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
* contract upgrade].
*/
function __EIP712_init(string memory name, string memory version) internal onlyInitializing {
__EIP712_init_unchained(name, version);
}
function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing {
EIP712Storage storage $ = _getEIP712Storage();
$._name = name;
$._version = version;
// Reset prior values in storage if upgrading
$._hashedName = 0;
$._hashedVersion = 0;
}
/**
* @dev Returns the domain separator for the current chain.
*/
function _domainSeparatorV4() internal view returns (bytes32) {
return _buildDomainSeparator();
}
function _buildDomainSeparator() private view returns (bytes32) {
return keccak256(abi.encode(TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash(), block.chainid, address(this)));
}
/**
* @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
* function returns the hash of the fully encoded EIP712 message for this domain.
*
* This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
*
* ```solidity
* bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
* keccak256("Mail(address to,string contents)"),
* mailTo,
* keccak256(bytes(mailContents))
* )));
* address signer = ECDSA.recover(digest, signature);
* ```
*/
function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash);
}
/**
* @dev See {IERC-5267}.
*/
function eip712Domain()
public
view
virtual
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
)
{
EIP712Storage storage $ = _getEIP712Storage();
// If the hashed name and version in storage are non-zero, the contract hasn't been properly initialized
// and the EIP712 domain is not reliable, as it will be missing name and version.
require($._hashedName == 0 && $._hashedVersion == 0, "EIP712: Uninitialized");
return (
hex"0f", // 01111
_EIP712Name(),
_EIP712Version(),
block.chainid,
address(this),
bytes32(0),
new uint256[](0)
);
}
/**
* @dev The name parameter for the EIP712 domain.
*
* NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs
* are a concern.
*/
function _EIP712Name() internal view virtual returns (string memory) {
EIP712Storage storage $ = _getEIP712Storage();
return $._name;
}
/**
* @dev The version parameter for the EIP712 domain.
*
* NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs
* are a concern.
*/
function _EIP712Version() internal view virtual returns (string memory) {
EIP712Storage storage $ = _getEIP712Storage();
return $._version;
}
/**
* @dev The hash of the name parameter for the EIP712 domain.
*
* NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Name` instead.
*/
function _EIP712NameHash() internal view returns (bytes32) {
EIP712Storage storage $ = _getEIP712Storage();
string memory name = _EIP712Name();
if (bytes(name).length > 0) {
return keccak256(bytes(name));
} else {
// If the name is empty, the contract may have been upgraded without initializing the new storage.
// We return the name hash in storage if non-zero, otherwise we assume the name is empty by design.
bytes32 hashedName = $._hashedName;
if (hashedName != 0) {
return hashedName;
} else {
return keccak256("");
}
}
}
/**
* @dev The hash of the version parameter for the EIP712 domain.
*
* NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Version` instead.
*/
function _EIP712VersionHash() internal view returns (bytes32) {
EIP712Storage storage $ = _getEIP712Storage();
string memory version = _EIP712Version();
if (bytes(version).length > 0) {
return keccak256(bytes(version));
} else {
// If the version is empty, the contract may have been upgraded without initializing the new storage.
// We return the version hash in storage if non-zero, otherwise we assume the version is empty by design.
bytes32 hashedVersion = $._hashedVersion;
if (hashedVersion != 0) {
return hashedVersion;
} else {
return keccak256("");
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/Checkpoints.sol)
// This file was procedurally generated from scripts/generate/templates/Checkpoints.js.
pragma solidity ^0.8.20;
import {Math} from "../math/Math.sol";
/**
* @dev This library defines the `Trace*` struct, for checkpointing values as they change at different points in
* time, and later looking up past values by block number. See {Votes} as an example.
*
* To create a history of checkpoints define a variable type `Checkpoints.Trace*` in your contract, and store a new
* checkpoint for the current transaction block using the {push} function.
*/
library Checkpoints {
/**
* @dev A value was attempted to be inserted on a past checkpoint.
*/
error CheckpointUnorderedInsertion();
struct Trace224 {
Checkpoint224[] _checkpoints;
}
struct Checkpoint224 {
uint32 _key;
uint224 _value;
}
/**
* @dev Pushes a (`key`, `value`) pair into a Trace224 so that it is stored as the checkpoint.
*
* Returns previous value and new value.
*
* IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint32).max` key set will disable the
* library.
*/
function push(Trace224 storage self, uint32 key, uint224 value) internal returns (uint224, uint224) {
return _insert(self._checkpoints, key, value);
}
/**
* @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if
* there is none.
*/
function lowerLookup(Trace224 storage self, uint32 key) internal view returns (uint224) {
uint256 len = self._checkpoints.length;
uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len);
return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value;
}
/**
* @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
* if there is none.
*/
function upperLookup(Trace224 storage self, uint32 key) internal view returns (uint224) {
uint256 len = self._checkpoints.length;
uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len);
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
}
/**
* @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
* if there is none.
*
* NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high
* keys).
*/
function upperLookupRecent(Trace224 storage self, uint32 key) internal view returns (uint224) {
uint256 len = self._checkpoints.length;
uint256 low = 0;
uint256 high = len;
if (len > 5) {
uint256 mid = len - Math.sqrt(len);
if (key < _unsafeAccess(self._checkpoints, mid)._key) {
high = mid;
} else {
low = mid + 1;
}
}
uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high);
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
}
/**
* @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints.
*/
function latest(Trace224 storage self) internal view returns (uint224) {
uint256 pos = self._checkpoints.length;
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
}
/**
* @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value
* in the most recent checkpoint.
*/
function latestCheckpoint(Trace224 storage self) internal view returns (bool exists, uint32 _key, uint224 _value) {
uint256 pos = self._checkpoints.length;
if (pos == 0) {
return (false, 0, 0);
} else {
Checkpoint224 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1);
return (true, ckpt._key, ckpt._value);
}
}
/**
* @dev Returns the number of checkpoint.
*/
function length(Trace224 storage self) internal view returns (uint256) {
return self._checkpoints.length;
}
/**
* @dev Returns checkpoint at given position.
*/
function at(Trace224 storage self, uint32 pos) internal view returns (Checkpoint224 memory) {
return self._checkpoints[pos];
}
/**
* @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint,
* or by updating the last one.
*/
function _insert(Checkpoint224[] storage self, uint32 key, uint224 value) private returns (uint224, uint224) {
uint256 pos = self.length;
if (pos > 0) {
// Copying to memory is important here.
Checkpoint224 memory last = _unsafeAccess(self, pos - 1);
// Checkpoint keys must be non-decreasing.
if (last._key > key) {
revert CheckpointUnorderedInsertion();
}
// Update or push new checkpoint
if (last._key == key) {
_unsafeAccess(self, pos - 1)._value = value;
} else {
self.push(Checkpoint224({_key: key, _value: value}));
}
return (last._value, value);
} else {
self.push(Checkpoint224({_key: key, _value: value}));
return (0, value);
}
}
/**
* @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or `high`
* if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive
* `high`.
*
* WARNING: `high` should not be greater than the array's length.
*/
function _upperBinaryLookup(
Checkpoint224[] storage self,
uint32 key,
uint256 low,
uint256 high
) private view returns (uint256) {
while (low < high) {
uint256 mid = Math.average(low, high);
if (_unsafeAccess(self, mid)._key > key) {
high = mid;
} else {
low = mid + 1;
}
}
return high;
}
/**
* @dev Return the index of the first (oldest) checkpoint with key is greater or equal than the search key, or
* `high` if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and
* exclusive `high`.
*
* WARNING: `high` should not be greater than the array's length.
*/
function _lowerBinaryLookup(
Checkpoint224[] storage self,
uint32 key,
uint256 low,
uint256 high
) private view returns (uint256) {
while (low < high) {
uint256 mid = Math.average(low, high);
if (_unsafeAccess(self, mid)._key < key) {
low = mid + 1;
} else {
high = mid;
}
}
return high;
}
/**
* @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
*/
function _unsafeAccess(
Checkpoint224[] storage self,
uint256 pos
) private pure returns (Checkpoint224 storage result) {
assembly {
mstore(0, self.slot)
result.slot := add(keccak256(0, 0x20), pos)
}
}
struct Trace208 {
Checkpoint208[] _checkpoints;
}
struct Checkpoint208 {
uint48 _key;
uint208 _value;
}
/**
* @dev Pushes a (`key`, `value`) pair into a Trace208 so that it is stored as the checkpoint.
*
* Returns previous value and new value.
*
* IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint48).max` key set will disable the
* library.
*/
function push(Trace208 storage self, uint48 key, uint208 value) internal returns (uint208, uint208) {
return _insert(self._checkpoints, key, value);
}
/**
* @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if
* there is none.
*/
function lowerLookup(Trace208 storage self, uint48 key) internal view returns (uint208) {
uint256 len = self._checkpoints.length;
uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len);
return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value;
}
/**
* @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
* if there is none.
*/
function upperLookup(Trace208 storage self, uint48 key) internal view returns (uint208) {
uint256 len = self._checkpoints.length;
uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len);
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
}
/**
* @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
* if there is none.
*
* NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high
* keys).
*/
function upperLookupRecent(Trace208 storage self, uint48 key) internal view returns (uint208) {
uint256 len = self._checkpoints.length;
uint256 low = 0;
uint256 high = len;
if (len > 5) {
uint256 mid = len - Math.sqrt(len);
if (key < _unsafeAccess(self._checkpoints, mid)._key) {
high = mid;
} else {
low = mid + 1;
}
}
uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high);
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
}
/**
* @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints.
*/
function latest(Trace208 storage self) internal view returns (uint208) {
uint256 pos = self._checkpoints.length;
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
}
/**
* @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value
* in the most recent checkpoint.
*/
function latestCheckpoint(Trace208 storage self) internal view returns (bool exists, uint48 _key, uint208 _value) {
uint256 pos = self._checkpoints.length;
if (pos == 0) {
return (false, 0, 0);
} else {
Checkpoint208 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1);
return (true, ckpt._key, ckpt._value);
}
}
/**
* @dev Returns the number of checkpoint.
*/
function length(Trace208 storage self) internal view returns (uint256) {
return self._checkpoints.length;
}
/**
* @dev Returns checkpoint at given position.
*/
function at(Trace208 storage self, uint32 pos) internal view returns (Checkpoint208 memory) {
return self._checkpoints[pos];
}
/**
* @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint,
* or by updating the last one.
*/
function _insert(Checkpoint208[] storage self, uint48 key, uint208 value) private returns (uint208, uint208) {
uint256 pos = self.length;
if (pos > 0) {
// Copying to memory is important here.
Checkpoint208 memory last = _unsafeAccess(self, pos - 1);
// Checkpoint keys must be non-decreasing.
if (last._key > key) {
revert CheckpointUnorderedInsertion();
}
// Update or push new checkpoint
if (last._key == key) {
_unsafeAccess(self, pos - 1)._value = value;
} else {
self.push(Checkpoint208({_key: key, _value: value}));
}
return (last._value, value);
} else {
self.push(Checkpoint208({_key: key, _value: value}));
return (0, value);
}
}
/**
* @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or `high`
* if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive
* `high`.
*
* WARNING: `high` should not be greater than the array's length.
*/
function _upperBinaryLookup(
Checkpoint208[] storage self,
uint48 key,
uint256 low,
uint256 high
) private view returns (uint256) {
while (low < high) {
uint256 mid = Math.average(low, high);
if (_unsafeAccess(self, mid)._key > key) {
high = mid;
} else {
low = mid + 1;
}
}
return high;
}
/**
* @dev Return the index of the first (oldest) checkpoint with key is greater or equal than the search key, or
* `high` if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and
* exclusive `high`.
*
* WARNING: `high` should not be greater than the array's length.
*/
function _lowerBinaryLookup(
Checkpoint208[] storage self,
uint48 key,
uint256 low,
uint256 high
) private view returns (uint256) {
while (low < high) {
uint256 mid = Math.average(low, high);
if (_unsafeAccess(self, mid)._key < key) {
low = mid + 1;
} else {
high = mid;
}
}
return high;
}
/**
* @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
*/
function _unsafeAccess(
Checkpoint208[] storage self,
uint256 pos
) private pure returns (Checkpoint208 storage result) {
assembly {
mstore(0, self.slot)
result.slot := add(keccak256(0, 0x20), pos)
}
}
struct Trace160 {
Checkpoint160[] _checkpoints;
}
struct Checkpoint160 {
uint96 _key;
uint160 _value;
}
/**
* @dev Pushes a (`key`, `value`) pair into a Trace160 so that it is stored as the checkpoint.
*
* Returns previous value and new value.
*
* IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint96).max` key set will disable the
* library.
*/
function push(Trace160 storage self, uint96 key, uint160 value) internal returns (uint160, uint160) {
return _insert(self._checkpoints, key, value);
}
/**
* @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if
* there is none.
*/
function lowerLookup(Trace160 storage self, uint96 key) internal view returns (uint160) {
uint256 len = self._checkpoints.length;
uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len);
return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value;
}
/**
* @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
* if there is none.
*/
function upperLookup(Trace160 storage self, uint96 key) internal view returns (uint160) {
uint256 len = self._checkpoints.length;
uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len);
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
}
/**
* @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
* if there is none.
*
* NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high
* keys).
*/
function upperLookupRecent(Trace160 storage self, uint96 key) internal view returns (uint160) {
uint256 len = self._checkpoints.length;
uint256 low = 0;
uint256 high = len;
if (len > 5) {
uint256 mid = len - Math.sqrt(len);
if (key < _unsafeAccess(self._checkpoints, mid)._key) {
high = mid;
} else {
low = mid + 1;
}
}
uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high);
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
}
/**
* @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints.
*/
function latest(Trace160 storage self) internal view returns (uint160) {
uint256 pos = self._checkpoints.length;
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
}
/**
* @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value
* in the most recent checkpoint.
*/
function latestCheckpoint(Trace160 storage self) internal view returns (bool exists, uint96 _key, uint160 _value) {
uint256 pos = self._checkpoints.length;
if (pos == 0) {
return (false, 0, 0);
} else {
Checkpoint160 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1);
return (true, ckpt._key, ckpt._value);
}
}
/**
* @dev Returns the number of checkpoint.
*/
function length(Trace160 storage self) internal view returns (uint256) {
return self._checkpoints.length;
}
/**
* @dev Returns checkpoint at given position.
*/
function at(Trace160 storage self, uint32 pos) internal view returns (Checkpoint160 memory) {
return self._checkpoints[pos];
}
/**
* @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint,
* or by updating the last one.
*/
function _insert(Checkpoint160[] storage self, uint96 key, uint160 value) private returns (uint160, uint160) {
uint256 pos = self.length;
if (pos > 0) {
// Copying to memory is important here.
Checkpoint160 memory last = _unsafeAccess(self, pos - 1);
// Checkpoint keys must be non-decreasing.
if (last._key > key) {
revert CheckpointUnorderedInsertion();
}
// Update or push new checkpoint
if (last._key == key) {
_unsafeAccess(self, pos - 1)._value = value;
} else {
self.push(Checkpoint160({_key: key, _value: value}));
}
return (last._value, value);
} else {
self.push(Checkpoint160({_key: key, _value: value}));
return (0, value);
}
}
/**
* @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or `high`
* if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive
* `high`.
*
* WARNING: `high` should not be greater than the array's length.
*/
function _upperBinaryLookup(
Checkpoint160[] storage self,
uint96 key,
uint256 low,
uint256 high
) private view returns (uint256) {
while (low < high) {
uint256 mid = Math.average(low, high);
if (_unsafeAccess(self, mid)._key > key) {
high = mid;
} else {
low = mid + 1;
}
}
return high;
}
/**
* @dev Return the index of the first (oldest) checkpoint with key is greater or equal than the search key, or
* `high` if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and
* exclusive `high`.
*
* WARNING: `high` should not be greater than the array's length.
*/
function _lowerBinaryLookup(
Checkpoint160[] storage self,
uint96 key,
uint256 low,
uint256 high
) private view returns (uint256) {
while (low < high) {
uint256 mid = Math.average(low, high);
if (_unsafeAccess(self, mid)._key < key) {
low = mid + 1;
} else {
high = mid;
}
}
return high;
}
/**
* @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
*/
function _unsafeAccess(
Checkpoint160[] storage self,
uint256 pos
) private pure returns (Checkpoint160 storage result) {
assembly {
mstore(0, self.slot)
result.slot := add(keccak256(0, 0x20), pos)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.20;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeCast {
/**
* @dev Value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
/**
* @dev An int value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedIntToUint(int256 value);
/**
* @dev Value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
/**
* @dev An uint value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedUintToInt(uint256 value);
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toUint248(uint256 value) internal pure returns (uint248) {
if (value > type(uint248).max) {
revert SafeCastOverflowedUintDowncast(248, value);
}
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toUint240(uint256 value) internal pure returns (uint240) {
if (value > type(uint240).max) {
revert SafeCastOverflowedUintDowncast(240, value);
}
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toUint232(uint256 value) internal pure returns (uint232) {
if (value > type(uint232).max) {
revert SafeCastOverflowedUintDowncast(232, value);
}
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toUint224(uint256 value) internal pure returns (uint224) {
if (value > type(uint224).max) {
revert SafeCastOverflowedUintDowncast(224, value);
}
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toUint216(uint256 value) internal pure returns (uint216) {
if (value > type(uint216).max) {
revert SafeCastOverflowedUintDowncast(216, value);
}
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toUint208(uint256 value) internal pure returns (uint208) {
if (value > type(uint208).max) {
revert SafeCastOverflowedUintDowncast(208, value);
}
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toUint200(uint256 value) internal pure returns (uint200) {
if (value > type(uint200).max) {
revert SafeCastOverflowedUintDowncast(200, value);
}
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toUint192(uint256 value) internal pure returns (uint192) {
if (value > type(uint192).max) {
revert SafeCastOverflowedUintDowncast(192, value);
}
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toUint184(uint256 value) internal pure returns (uint184) {
if (value > type(uint184).max) {
revert SafeCastOverflowedUintDowncast(184, value);
}
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toUint176(uint256 value) internal pure returns (uint176) {
if (value > type(uint176).max) {
revert SafeCastOverflowedUintDowncast(176, value);
}
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toUint168(uint256 value) internal pure returns (uint168) {
if (value > type(uint168).max) {
revert SafeCastOverflowedUintDowncast(168, value);
}
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toUint160(uint256 value) internal pure returns (uint160) {
if (value > type(uint160).max) {
revert SafeCastOverflowedUintDowncast(160, value);
}
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toUint152(uint256 value) internal pure returns (uint152) {
if (value > type(uint152).max) {
revert SafeCastOverflowedUintDowncast(152, value);
}
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toUint144(uint256 value) internal pure returns (uint144) {
if (value > type(uint144).max) {
revert SafeCastOverflowedUintDowncast(144, value);
}
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toUint136(uint256 value) internal pure returns (uint136) {
if (value > type(uint136).max) {
revert SafeCastOverflowedUintDowncast(136, value);
}
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toUint128(uint256 value) internal pure returns (uint128) {
if (value > type(uint128).max) {
revert SafeCastOverflowedUintDowncast(128, value);
}
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toUint120(uint256 value) internal pure returns (uint120) {
if (value > type(uint120).max) {
revert SafeCastOverflowedUintDowncast(120, value);
}
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toUint112(uint256 value) internal pure returns (uint112) {
if (value > type(uint112).max) {
revert SafeCastOverflowedUintDowncast(112, value);
}
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toUint104(uint256 value) internal pure returns (uint104) {
if (value > type(uint104).max) {
revert SafeCastOverflowedUintDowncast(104, value);
}
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toUint96(uint256 value) internal pure returns (uint96) {
if (value > type(uint96).max) {
revert SafeCastOverflowedUintDowncast(96, value);
}
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toUint88(uint256 value) internal pure returns (uint88) {
if (value > type(uint88).max) {
revert SafeCastOverflowedUintDowncast(88, value);
}
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toUint80(uint256 value) internal pure returns (uint80) {
if (value > type(uint80).max) {
revert SafeCastOverflowedUintDowncast(80, value);
}
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toUint72(uint256 value) internal pure returns (uint72) {
if (value > type(uint72).max) {
revert SafeCastOverflowedUintDowncast(72, value);
}
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toUint64(uint256 value) internal pure returns (uint64) {
if (value > type(uint64).max) {
revert SafeCastOverflowedUintDowncast(64, value);
}
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toUint56(uint256 value) internal pure returns (uint56) {
if (value > type(uint56).max) {
revert SafeCastOverflowedUintDowncast(56, value);
}
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toUint48(uint256 value) internal pure returns (uint48) {
if (value > type(uint48).max) {
revert SafeCastOverflowedUintDowncast(48, value);
}
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toUint40(uint256 value) internal pure returns (uint40) {
if (value > type(uint40).max) {
revert SafeCastOverflowedUintDowncast(40, value);
}
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toUint32(uint256 value) internal pure returns (uint32) {
if (value > type(uint32).max) {
revert SafeCastOverflowedUintDowncast(32, value);
}
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toUint24(uint256 value) internal pure returns (uint24) {
if (value > type(uint24).max) {
revert SafeCastOverflowedUintDowncast(24, value);
}
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toUint16(uint256 value) internal pure returns (uint16) {
if (value > type(uint16).max) {
revert SafeCastOverflowedUintDowncast(16, value);
}
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toUint8(uint256 value) internal pure returns (uint8) {
if (value > type(uint8).max) {
revert SafeCastOverflowedUintDowncast(8, value);
}
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
if (value < 0) {
revert SafeCastOverflowedIntToUint(value);
}
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(248, value);
}
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(240, value);
}
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(232, value);
}
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(224, value);
}
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(216, value);
}
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(208, value);
}
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(200, value);
}
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(192, value);
}
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(184, value);
}
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(176, value);
}
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(168, value);
}
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(160, value);
}
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(152, value);
}
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(144, value);
}
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(136, value);
}
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(128, value);
}
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(120, value);
}
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(112, value);
}
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(104, value);
}
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(96, value);
}
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(88, value);
}
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(80, value);
}
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(72, value);
}
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(64, value);
}
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(56, value);
}
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(48, value);
}
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(40, value);
}
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(32, value);
}
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(24, value);
}
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(16, value);
}
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(8, value);
}
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
if (value > uint256(type(int256).max)) {
revert SafeCastOverflowedUintToInt(value);
}
return int256(value);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.20;
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS
}
/**
* @dev The signature derives the `address(0)`.
*/
error ECDSAInvalidSignature();
/**
* @dev The signature has an invalid length.
*/
error ECDSAInvalidSignatureLength(uint256 length);
/**
* @dev The signature has an S value that is in the upper half order.
*/
error ECDSAInvalidSignatureS(bytes32 s);
/**
* @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
* return address(0) without also returning an error description. Errors are documented using an enum (error type)
* and a bytes32 providing additional information about the error.
*
* If no error is returned, then the address can be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*/
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {
unchecked {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
// We do not check for an overflow here since the shift operation results in 0 or 1.
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError, bytes32) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS, s);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature, bytes32(0));
}
return (signer, RecoverError.NoError, bytes32(0));
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
*/
function _throwError(RecoverError error, bytes32 errorArg) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert ECDSAInvalidSignature();
} else if (error == RecoverError.InvalidSignatureLength) {
revert ECDSAInvalidSignatureLength(uint256(errorArg));
} else if (error == RecoverError.InvalidSignatureS) {
revert ECDSAInvalidSignatureS(errorArg);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/types/Time.sol)
pragma solidity ^0.8.20;
import {Math} from "../math/Math.sol";
import {SafeCast} from "../math/SafeCast.sol";
/**
* @dev This library provides helpers for manipulating time-related objects.
*
* It uses the following types:
* - `uint48` for timepoints
* - `uint32` for durations
*
* While the library doesn't provide specific types for timepoints and duration, it does provide:
* - a `Delay` type to represent duration that can be programmed to change value automatically at a given point
* - additional helper functions
*/
library Time {
using Time for *;
/**
* @dev Get the block timestamp as a Timepoint.
*/
function timestamp() internal view returns (uint48) {
return SafeCast.toUint48(block.timestamp);
}
/**
* @dev Get the block number as a Timepoint.
*/
function blockNumber() internal view returns (uint48) {
return SafeCast.toUint48(block.number);
}
// ==================================================== Delay =====================================================
/**
* @dev A `Delay` is a uint32 duration that can be programmed to change value automatically at a given point in the
* future. The "effect" timepoint describes when the transitions happens from the "old" value to the "new" value.
* This allows updating the delay applied to some operation while keeping some guarantees.
*
* In particular, the {update} function guarantees that if the delay is reduced, the old delay still applies for
* some time. For example if the delay is currently 7 days to do an upgrade, the admin should not be able to set
* the delay to 0 and upgrade immediately. If the admin wants to reduce the delay, the old delay (7 days) should
* still apply for some time.
*
*
* The `Delay` type is 112 bits long, and packs the following:
*
* ```
* | [uint48]: effect date (timepoint)
* | | [uint32]: value before (duration)
* ↓ ↓ ↓ [uint32]: value after (duration)
* 0xAAAAAAAAAAAABBBBBBBBCCCCCCCC
* ```
*
* NOTE: The {get} and {withUpdate} functions operate using timestamps. Block number based delays are not currently
* supported.
*/
type Delay is uint112;
/**
* @dev Wrap a duration into a Delay to add the one-step "update in the future" feature
*/
function toDelay(uint32 duration) internal pure returns (Delay) {
return Delay.wrap(duration);
}
/**
* @dev Get the value at a given timepoint plus the pending value and effect timepoint if there is a scheduled
* change after this timepoint. If the effect timepoint is 0, then the pending value should not be considered.
*/
function _getFullAt(Delay self, uint48 timepoint) private pure returns (uint32, uint32, uint48) {
(uint32 valueBefore, uint32 valueAfter, uint48 effect) = self.unpack();
return effect <= timepoint ? (valueAfter, 0, 0) : (valueBefore, valueAfter, effect);
}
/**
* @dev Get the current value plus the pending value and effect timepoint if there is a scheduled change. If the
* effect timepoint is 0, then the pending value should not be considered.
*/
function getFull(Delay self) internal view returns (uint32, uint32, uint48) {
return _getFullAt(self, timestamp());
}
/**
* @dev Get the current value.
*/
function get(Delay self) internal view returns (uint32) {
(uint32 delay, , ) = self.getFull();
return delay;
}
/**
* @dev Update a Delay object so that it takes a new duration after a timepoint that is automatically computed to
* enforce the old delay at the moment of the update. Returns the updated Delay object and the timestamp when the
* new delay becomes effective.
*/
function withUpdate(
Delay self,
uint32 newValue,
uint32 minSetback
) internal view returns (Delay updatedDelay, uint48 effect) {
uint32 value = self.get();
uint32 setback = uint32(Math.max(minSetback, value > newValue ? value - newValue : 0));
effect = timestamp() + setback;
return (pack(value, newValue, effect), effect);
}
/**
* @dev Split a delay into its components: valueBefore, valueAfter and effect (transition timepoint).
*/
function unpack(Delay self) internal pure returns (uint32 valueBefore, uint32 valueAfter, uint48 effect) {
uint112 raw = Delay.unwrap(self);
valueAfter = uint32(raw);
valueBefore = uint32(raw >> 32);
effect = uint48(raw >> 64);
return (valueBefore, valueAfter, effect);
}
/**
* @dev pack the components into a Delay object.
*/
function pack(uint32 valueBefore, uint32 valueAfter, uint48 effect) internal pure returns (Delay) {
return Delay.wrap((uint112(effect) << 64) | (uint112(valueBefore) << 32) | uint112(valueAfter));
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.22;
interface IDAOExecutor {
function delay() external view returns (uint256);
function GRACE_PERIOD() external view returns (uint256);
function acceptAdmin() external;
function queuedTransactions(bytes32 hash) external view returns (bool);
function queueTransaction(
address target,
uint256 value,
string calldata signature,
bytes calldata data,
uint256 eta
) external returns (bytes32);
function cancelTransaction(
address target,
uint256 value,
string calldata signature,
bytes calldata data,
uint256 eta
) external;
function executeTransaction(
address target,
uint256 value,
string calldata signature,
bytes calldata data,
uint256 eta
) external returns (bytes memory);
/// @notice Initializes an instance of a DAO's treasury
/// @param admin The DAO's address
/// @param timelockDelay The time delay to execute a queued transaction
/// @param data The data to be decoded
function initialize(address admin, uint256 timelockDelay, bytes memory data) external;
}// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.22;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IRevolutionToken } from "./IRevolutionToken.sol";
import { IRevolutionBuilder } from "./IRevolutionBuilder.sol";
import { IRevolutionPoints } from "./IRevolutionPoints.sol";
/**
* @title IRevolutionVotingPowerEvents
* @dev This interface defines the events for the RevolutionVotingPower contract.
*/
interface IRevolutionVotingPowerEvents {
event ERC721VotingTokenUpdated(address erc721VotingToken);
event ERC721VotingPowerUpdated(uint256 oldERC721VotingPower, uint256 newERC721VotingPower);
event ERC20VotingTokenUpdated(address erc20VotingToken);
event ERC20VotingPowerUpdated(uint256 oldERC20VotingPower, uint256 newERC20VotingPower);
}
/**
* @title IRevolutionVotingPower
* @dev This interface defines the methods for the RevolutionVotingPower contract for art piece management and voting.
*/
interface IRevolutionVotingPower is IRevolutionVotingPowerEvents {
/**
* @notice Initializes the RevolutionVotingPower contract
* @param initialOwner The initial owner of the contract
* @param revolutionPoints The address of the ERC20 token used for voting
* @param pointsVoteWeight The vote weight of the ERC20 token
* @param revolutionToken The address of the ERC721 token used for voting
* @param tokenVoteWeight The vote weight of the ERC721 token
*/
function initialize(
address initialOwner,
address revolutionPoints,
uint256 pointsVoteWeight,
address revolutionToken,
uint256 tokenVoteWeight
) external;
/**
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
* POINTS
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
*/
function points() external returns (IRevolutionPoints);
function getPointsMinter() external view returns (address);
function getPointsVotes(address account) external view returns (uint256);
function getPastPointsVotes(address account, uint256 blockNumber) external view returns (uint256);
function getPointsSupply() external view returns (uint256);
function getPastPointsSupply(uint256 blockNumber) external view returns (uint256);
/**
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
* TOKEN
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
*/
function token() external returns (IRevolutionToken);
function getTokenMinter() external view returns (address);
function getTokenVotes(address account) external view returns (uint256);
function getPastTokenVotes(address account, uint256 blockNumber) external view returns (uint256);
function getTokenSupply() external view returns (uint256);
function getPastTokenSupply(uint256 blockNumber) external view returns (uint256);
/**
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
* VOTES
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
*/
function getVotes(address account) external view returns (uint256);
function getVotesWithWeights(
address account,
uint256 erc20PointsVoteWeight,
uint256 erc721TokenVoteWeight
) external view returns (uint256);
function getTotalVotesSupply() external view returns (uint256);
function getTotalVotesSupplyWithWeights(
uint256 erc20PointsVoteWeight,
uint256 erc721TokenVoteWeight
) external view returns (uint256);
/**
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
* PAST VOTES
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
*/
function getPastVotes(address account, uint256 blockNumber) external view returns (uint256);
function getPastVotesWithWeights(
address account,
uint256 blockNumber,
uint256 erc20PointsVoteWeight,
uint256 erc721TokenVoteWeight
) external view returns (uint256);
function getPastTotalVotesSupply(uint256 blockNumber) external view returns (uint256);
function getPastTotalVotesSupplyWithWeights(
uint256 blockNumber,
uint256 erc20PointsVoteWeight,
uint256 erc721TokenVoteWeight
) external view returns (uint256);
/**
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
* CALCULATE VOTES
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
*/
struct BalanceAndWeight {
uint256 balance;
uint256 voteWeight;
}
function calculateVotesWithWeights(
BalanceAndWeight calldata points,
BalanceAndWeight calldata token
) external pure returns (uint256);
function calculateVotes(uint256 pointsBalance, uint256 tokenBalance) external view returns (uint256);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (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.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata 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.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* 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.
*/
function transferFrom(address from, 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.
*/
function approve(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 address zero.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.20;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be
* reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Metadata.sol)
pragma solidity ^0.8.20;
import {IERC721} from "../IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional metadata extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
interface IERC721Metadata is IERC721 {
/**
* @dev Returns the token collection name.
*/
function name() external view returns (string memory);
/**
* @dev Returns the token collection symbol.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/
function tokenURI(uint256 tokenId) external view returns (string memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)
pragma solidity ^0.8.20;
import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant HEX_DIGITS = "0123456789abcdef";
uint8 private constant ADDRESS_LENGTH = 20;
/**
* @dev The `value` string doesn't fit in the specified `length`.
*/
error StringsInsufficientHexLength(uint256 value, uint256 length);
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toStringSigned(int256 value) internal pure returns (string memory) {
return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
uint256 localValue = value;
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = HEX_DIGITS[localValue & 0xf];
localValue >>= 4;
}
if (localValue != 0) {
revert StringsInsufficientHexLength(value, length);
}
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
* representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165Upgradeable is Initializable, IERC165 {
function __ERC165_init() internal onlyInitializing {
}
function __ERC165_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (governance/utils/IVotes.sol)
pragma solidity ^0.8.20;
/**
* @dev Common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts.
*/
interface IVotes {
/**
* @dev The signature used has expired.
*/
error VotesExpiredSignature(uint256 expiry);
/**
* @dev Emitted when an account changes their delegate.
*/
event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
/**
* @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of voting units.
*/
event DelegateVotesChanged(address indexed delegate, uint256 previousVotes, uint256 newVotes);
/**
* @dev Returns the current amount of votes that `account` has.
*/
function getVotes(address account) external view returns (uint256);
/**
* @dev Returns the amount of votes that `account` had at a specific moment in the past. If the `clock()` is
* configured to use block numbers, this will return the value at the end of the corresponding block.
*/
function getPastVotes(address account, uint256 timepoint) external view returns (uint256);
/**
* @dev Returns the total supply of votes available at a specific moment in the past. If the `clock()` is
* configured to use block numbers, this will return the value at the end of the corresponding block.
*
* NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes.
* Votes that have not been delegated are still part of total supply, even though they would not participate in a
* vote.
*/
function getPastTotalSupply(uint256 timepoint) external view returns (uint256);
/**
* @dev Returns the delegate that `account` has chosen.
*/
function delegates(address account) external view returns (address);
/**
* @dev Delegates votes from the sender to `delegatee`.
*/
function delegate(address delegatee) external;
/**
* @dev Delegates votes from signer to `delegatee`.
*/
function delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC6372.sol)
pragma solidity ^0.8.20;
interface IERC6372 {
/**
* @dev Clock used for flagging checkpoints. Can be overridden to implement timestamp based checkpoints (and voting).
*/
function clock() external view returns (uint48);
/**
* @dev Description of the clock
*/
// solhint-disable-next-line func-name-mixedcase
function CLOCK_MODE() external view returns (string memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol)
pragma solidity ^0.8.20;
import {Strings} from "../Strings.sol";
/**
* @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
*
* The library provides methods for generating a hash of a message that conforms to the
* https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
* specifications.
*/
library MessageHashUtils {
/**
* @dev Returns the keccak256 digest of an EIP-191 signed data with version
* `0x45` (`personal_sign` messages).
*
* The digest is calculated by prefixing a bytes32 `messageHash` with
* `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the
* hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
*
* NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with
* keccak256, although any bytes32 value can be safely used because the final digest will
* be re-hashed.
*
* See {ECDSA-recover}.
*/
function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash
mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix
digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)
}
}
/**
* @dev Returns the keccak256 digest of an EIP-191 signed data with version
* `0x45` (`personal_sign` messages).
*
* The digest is calculated by prefixing an arbitrary `message` with
* `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the
* hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
*
* See {ECDSA-recover}.
*/
function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
return
keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message));
}
/**
* @dev Returns the keccak256 digest of an EIP-191 signed data with version
* `0x00` (data with intended validator).
*
* The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended
* `validator` address. Then hashing the result.
*
* See {ECDSA-recover}.
*/
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(hex"19_00", validator, data));
}
/**
* @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`).
*
* The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
* `\x19\x01` and hashing the result. It corresponds to the hash signed by the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
*
* See {ECDSA-recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, hex"19_01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
digest := keccak256(ptr, 0x42)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol)
pragma solidity ^0.8.20;
interface IERC5267 {
/**
* @dev MAY be emitted to signal that the domain could have changed.
*/
event EIP712DomainChanged();
/**
* @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
* signature.
*/
function eip712Domain()
external
view
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
return a / b;
}
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: GPL-3.0
/// @title Interface for RevolutionToken
/*********************************
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░█████████░░█████████░░░ *
* ░░░░░░██░░░████░░██░░░████░░░ *
* ░░██████░░░████████░░░████░░░ *
* ░░██░░██░░░████░░██░░░████░░░ *
* ░░██░░██░░░████░░██░░░████░░░ *
* ░░░░░░█████████░░█████████░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
*********************************/
pragma solidity ^0.8.22;
import { IERC721Enumerable } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
import { IVotes } from "@openzeppelin/contracts/governance/utils/IVotes.sol";
import { IDescriptorMinimal } from "./IDescriptorMinimal.sol";
import { ICultureIndex } from "./ICultureIndex.sol";
import { IRevolutionBuilder } from "./IRevolutionBuilder.sol";
interface IRevolutionToken is IERC721Enumerable, IVotes {
/// ///
/// ERRORS ///
/// ///
/// @dev Reverts if the token ID is invalid (greater than the current token ID).
error INVALID_TOKEN_ID();
/// @dev Reverts if the number of creators for an art piece exceeds the maximum allowed.
error TOO_MANY_CREATORS();
/// @dev Reverts if the minter is locked.
error MINTER_LOCKED();
/// @dev Reverts if the CultureIndex is locked.
error CULTURE_INDEX_LOCKED();
/// @dev Reverts if the descriptor is locked.
error DESCRIPTOR_LOCKED();
/// @dev Reverts if the sender is not the minter.
error NOT_MINTER();
/// @dev Reverts if the caller is not the manager.
error ONLY_MANAGER_CAN_INITIALIZE();
/// @dev Reverts if an address is the zero address.
error ADDRESS_ZERO();
/// ///
/// EVENTS ///
/// ///
event RevolutionTokenCreated(uint256 indexed tokenId, ICultureIndex.ArtPieceCondensed artPiece);
event RevolutionTokenBurned(uint256 indexed tokenId);
event MinterUpdated(address minter);
event MinterLocked();
event DescriptorUpdated(IDescriptorMinimal descriptor);
event DescriptorLocked();
event CultureIndexUpdated(ICultureIndex cultureIndex);
event CultureIndexLocked();
/// ///
/// FUNCTIONS ///
/// ///
function mint() external returns (uint256);
function burn(uint256 tokenId) external;
function dataURI(uint256 tokenId) external returns (string memory);
function setMinter(address minter) external;
function lockMinter() external;
function minter() external view returns (address);
function setDescriptor(IDescriptorMinimal descriptor) external;
function lockDescriptor() external;
function lockCultureIndex() external;
function getArtPieceById(uint256 tokenId) external view returns (ICultureIndex.ArtPiece memory);
/**
* @notice Returns true or false depending on whether the top voted piece in the culture index meets quorum
* @return True if the top voted piece meets quorum, false otherwise
*/
function topVotedPieceMeetsQuorum() external view returns (bool);
/// @notice Initializes a DAO's ERC-721 token contract
/// @param minter The address of the minter
/// @param initialOwner The address of the initial owner
/// @param descriptor The address of the token URI descriptor
/// @param cultureIndex The address of the CultureIndex contract
/// @param revolutionTokenParams The name, symbol, and contract metadata of the token
function initialize(
address minter,
address initialOwner,
address descriptor,
address cultureIndex,
IRevolutionBuilder.RevolutionTokenParams memory revolutionTokenParams
) external;
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.22;
import { IRevolutionBuilder } from "./IRevolutionBuilder.sol";
import { IVotes } from "@openzeppelin/contracts/governance/utils/IVotes.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IRevolutionPoints is IERC20, IVotes {
/// ///
/// EVENTS ///
/// ///
event MinterUpdated(address minter);
event MinterLocked();
/// ///
/// ERRORS ///
/// ///
/// @dev Revert if transfer is attempted. This is a nontransferable token.
error TRANSFER_NOT_ALLOWED();
/// @dev Revert if not the manager
error ONLY_MANAGER();
/// @dev Revert if 0 address
error INVALID_ADDRESS_ZERO();
/// @dev Revert if minter is locked
error MINTER_LOCKED();
/// @dev Revert if not minter
error NOT_MINTER();
/// ///
/// FUNCTIONS ///
/// ///
function minter() external view returns (address);
function setMinter(address minter) external;
function lockMinter() external;
function mint(address account, uint256 amount) external;
function decimals() external view returns (uint8);
/// @notice Initializes a DAO's ERC-20 governance token contract
/// @param initialOwner The address of the initial owner
/// @param minter The address of the minter
/// @param tokenParams The params of the token
function initialize(
address initialOwner,
address minter,
IRevolutionBuilder.PointsTokenParams calldata tokenParams
) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}// SPDX-License-Identifier: GPL-3.0
/// @title Common interface for Descriptor versions, as used by RevolutionToken
/*********************************
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░█████████░░█████████░░░ *
* ░░░░░░██░░░████░░██░░░████░░░ *
* ░░██████░░░████████░░░████░░░ *
* ░░██░░██░░░████░░██░░░████░░░ *
* ░░██░░██░░░████░░██░░░████░░░ *
* ░░░░░░█████████░░█████████░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
*********************************/
pragma solidity ^0.8.22;
import { ICultureIndex } from "./ICultureIndex.sol";
interface IDescriptorMinimal {
///
/// USED BY TOKEN
///
function tokenURI(
uint256 tokenId,
ICultureIndex.ArtPieceMetadata memory metadata
) external view returns (string memory);
function dataURI(
uint256 tokenId,
ICultureIndex.ArtPieceMetadata memory metadata
) external view returns (string memory);
}{
"remappings": [
"ds-test/=node_modules/ds-test/src/",
"forge-std/=node_modules/forge-std/src/",
"@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/",
"@openzeppelin/contracts-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/",
"solmate/=node_modules/solmate/",
"@cobuild/protocol-rewards/src/=node_modules/@cobuild/protocol-rewards/src/",
"@cobuild/splits/src/=node_modules/@cobuild/splits/src/",
"@cobuild/utility-contracts/src/=node_modules/@cobuild/utility-contracts/src/",
"@gnosis.pm/=node_modules/@gnosis.pm/",
"contests/=script/contests/",
"extensions/=script/extensions/",
"solmate/=node_modules/solmate/"
],
"optimizer": {
"enabled": true,
"runs": 750
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": true,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_manager","type":"address"},{"internalType":"address","name":"_protocolRewards","type":"address"},{"internalType":"address","name":"_protocolFeeRecipient","type":"address"}],"stateMutability":"payable","type":"constructor"},{"inputs":[],"name":"ADDRESS_ZERO","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[],"name":"CONTEST_ALREADY_PAID_OUT","type":"error"},{"inputs":[],"name":"CONTEST_NOT_ENDED","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"INVALID_ENTROPY_RATE","type":"error"},{"inputs":[],"name":"INVALID_PAYOUT_SPLITS","type":"error"},{"inputs":[{"internalType":"address","name":"impl","type":"address"}],"name":"INVALID_UPGRADE","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NOT_MANAGER","type":"error"},{"inputs":[],"name":"NO_BALANCE_TO_PAYOUT","type":"error"},{"inputs":[],"name":"NO_BALANCE_TO_WITHDRAW","type":"error"},{"inputs":[],"name":"NO_COUNT_SPECIFIED","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"ONLY_CALL","type":"error"},{"inputs":[],"name":"ONLY_DELEGATECALL","type":"error"},{"inputs":[],"name":"ONLY_PROXY","type":"error"},{"inputs":[],"name":"ONLY_UUPS","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"PAYOUT_SPLITS_NOT_DESCENDING","type":"error"},{"inputs":[],"name":"QUORUM_NOT_MET","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"UNSUPPORTED_UUID","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"rate","type":"uint256"}],"name":"EntropyRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"impl","type":"address"}],"name":"Upgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"pieceId","type":"uint256"},{"indexed":false,"internalType":"address[]","name":"winners","type":"address[]"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"protocolRewardsAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"payoutSplit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"payoutIndex","type":"uint256"}],"name":"WinnerPaid","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"PERCENTAGE_SCALE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"builderReward","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"paymentAmountWei","type":"uint256"}],"name":"computePurchaseRewards","outputs":[{"components":[{"internalType":"uint256","name":"builderReferralReward","type":"uint256"},{"internalType":"uint256","name":"purchaseReferralReward","type":"uint256"},{"internalType":"uint256","name":"deployerReward","type":"uint256"},{"internalType":"uint256","name":"revolutionReward","type":"uint256"}],"internalType":"struct IRewardSplits.RewardsSettings","name":"","type":"tuple"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"paymentAmountWei","type":"uint256"}],"name":"computeTotalReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"contractVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"cultureIndex","outputs":[{"internalType":"contract ICultureIndex","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"endTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"entropyRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"pieceId","type":"uint256"}],"name":"getArtPieceById","outputs":[{"components":[{"internalType":"uint256","name":"pieceId","type":"uint256"},{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"description","type":"string"},{"internalType":"enum ICultureIndex.MediaType","name":"mediaType","type":"uint8"},{"internalType":"string","name":"image","type":"string"},{"internalType":"string","name":"text","type":"string"},{"internalType":"string","name":"animationUrl","type":"string"}],"internalType":"struct ICultureIndex.ArtPieceMetadata","name":"metadata","type":"tuple"},{"components":[{"internalType":"address","name":"creator","type":"address"},{"internalType":"uint256","name":"bps","type":"uint256"}],"internalType":"struct ICultureIndex.CreatorBps[]","name":"creators","type":"tuple[]"},{"internalType":"address","name":"sponsor","type":"address"},{"internalType":"bool","name":"isDropped","type":"bool"},{"internalType":"uint256","name":"creationBlock","type":"uint256"}],"internalType":"struct ICultureIndex.ArtPiece","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPayoutSplits","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPayoutSplitsCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialPayoutBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_initialOwner","type":"address"},{"internalType":"address","name":"_splitMain","type":"address"},{"internalType":"address","name":"_cultureIndex","type":"address"},{"internalType":"address","name":"_builderReward","type":"address"},{"internalType":"address","name":"_weth","type":"address"},{"components":[{"internalType":"uint256","name":"entropyRate","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256[]","name":"payoutSplits","type":"uint256[]"}],"internalType":"struct IBaseContest.BaseContestParams","name":"_baseContestParams","type":"tuple"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"manager","outputs":[{"internalType":"contract IUpgradeManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paidOut","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_payoutCount","type":"uint256"}],"name":"payOutWinners","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"payoutIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"payoutSplitAccounts","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"payoutSplits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_entropyRate","type":"uint256"}],"name":"setEntropyRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"splitMain","outputs":[{"internalType":"contract ISplitMain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"startTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"topVotedPieceMeetsQuorum","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newImpl","type":"address"}],"name":"upgradeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newImpl","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"withdrawToPointsEmitterOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
610100601f1962002db338819003601f810192909216830192916001600160401b0391838510838611176200029857816060928592604097885283398101031262000293576200004f82620002ae565b916200006b846200006360208401620002ae565b9201620002ae565b306080526001600160a01b03918216801592919083801562000288575b620002445760c0528060a0527ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0094855460ff81891c1615958116801590816200023b575b600114908162000230575b15908162000226575b5062000215576001600160401b03198116600117875583919086620001f7575b5016928315620001e657620001d5571615620001c45760e05262000183575b5051612aef9081620002c4823960805181818161067501528181610d0b0152611a22015260a05181818161291b01528181612a0a0152612a30015260c0518161293d015260e051818181610718015281816108db0152818161158f0152611a890152f35b68ff00000000000000001981541690557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d26020825160018152a1386200011f565b83516366e7950960e01b8152600490fd5b85516366e7950960e01b8152600490fd5b86516366e7950960e01b8152600490fd5b6001600160481b031916680100000000000000011787553862000100565b875163f92ee8a960e01b8152600490fd5b90501538620000e0565b303b159150620000d7565b879150620000cc565b865162461bcd60e51b815260206004820152601460248201527f496e76616c69642041646472657373205a65726f0000000000000000000000006044820152606490fd5b508282161562000088565b600080fd5b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b0382168203620002935756fe60806040526004361015610018575b361561001657005b005b60003560e01c80630e769b2b14610248578063135b15e91461024357806327394dce1461023e5780632b1b5cf8146102395780632dc8fb1c146102345780632df05a3e1461022f5780633197cbb61461022a5780633659cfe6146102255780633f26479e146102205780633f4ba83a1461021b578063400a976a146102165780634132239b14610211578063481c6a751461020c57806349a33562146102075780634f1ef2861461020257806352d1902d146101fd578063553a4e23146101f85780635c76ca2d146101f35780635c93c3d9146101ee5780635c975abb146101e9578063715018a6146101e4578063727bc4f8146101df57806373d7b942146101da57806378e97925146101d55780637c39a58f146101d05780638456cb59146101cb5780638da5cb5b146101c6578063a0a8e460146101c1578063ab7d4b22146101bc578063ad5c4648146101b7578063b8d1a3b5146101b2578063c5ea59ed146101ad578063db2e21bc146101a8578063f0f8f9f2146101a35763f2fde38b0361000e57611388565b61133d565b6112ad565b61127e565b6111c9565b6111a2565b611140565b6110fa565b6110b4565b61103b565b61101d565b610fff565b610f92565b610f6b565b610eef565b610ead565b610e69565b610e46565b610d6d565b610cf0565b610c74565b610a94565b6108bb565b61089b565b61086b565b6107f5565b6107d7565b61064d565b61062f565b610611565b610439565b61040a565b6102ab565b610284565b61025d565b600091031261025857565b600080fd5b346102585760003660031901126102585760206001600160a01b0360085416604051908152f35b346102585760003660031901126102585760206001600160a01b0360025416604051908152f35b3461025857600080600319360112610407576102c5611c40565b47156103f5576102de6102da60055460ff1690565b1590565b6103e357806103046102f86008546001600160a01b031690565b6001600160a01b031690565b60405190631ea72fdf60e01b82528160048160209586945af19081156103c1576001600160a01b0391839185916103c6575b50600460405180948193638da5cb5b60e01b8352165afa9081156103c157610368928492610394575b50504790611c82565b61039160017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b80f35b6103b39250803d106103ba575b6103ab8183610be7565b8101906113b5565b388061035f565b503d6103a1565b6113cd565b6103dd9150823d84116103ba576103ab8183610be7565b38610336565b6040516325765c0f60e11b8152600490fd5b6040516313e9de3f60e01b8152600490fd5b80fd5b34610258576000366003190112610258576020600154604051908152f35b6001600160a01b0381160361025857565b346102585760031960c0368201126102585760043561045781610428565b6024359061046482610428565b60443561047081610428565b60643561047c81610428565b6084359161048983610428565b60a4359467ffffffffffffffff96878711610258576080908736030112610258577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00549660ff8860401c1615971680159081610609575b60011490816105ff575b1590816105f6575b506105e4577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805467ffffffffffffffff1916600117905561053d95876105a3575b6004019461157e565b61054357005b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468ff000000000000000019169055604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1005b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468ff0000000000000000191668010000000000000000179055610534565b60405163f92ee8a960e01b8152600490fd5b905015386104f2565b303b1591506104ea565b8891506104e0565b34610258576000366003190112610258576020600654604051908152f35b34610258576000366003190112610258576020600454604051908152f35b346102585760203660031901126102585760043561066a81610428565b6001600160a01b03807f000000000000000000000000000000000000000000000000000000000000000016908130146107c557807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54169182036107b35782602091610714936106d8612065565b6106e0612754565b604051639bb8dcfd60e01b81526001600160a01b039182166004820152921660248301529092839190829081906044820190565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa9081156103c157600091610784575b5015610761576100169061075b611735565b90611eaf565b60405163310365cd60e21b81526001600160a01b03919091166004820152602490fd5b6107a6915060203d6020116107ac575b61079e8183610be7565b810190611ba6565b38610749565b503d610794565b60405163073a6c8560e51b8152600490fd5b6040516343d22ee960e01b8152600490fd5b34610258576000366003190112610258576020604051620f42408152f35b346102585760003660031901126102585761080e612065565b610816612754565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330060ff1981541690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a1005b34610258576000366003190112610258576020600a54604051908152f35b60209060031901126102585760043590565b346102585760206108b36108ae36610889565b611759565b604051908152f35b346102585760003660031901126102585760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b60005b8381106109125750506000910152565b8181015183820152602001610902565b9060209161093b815180928185528580860191016108ff565b601f01601f1916010190565b90815180825260208080930193019160005b828110610967575050505090565b835180516001600160a01b031686528201518583015260409094019392810192600101610959565b6020815281516020820152602082015160c060408301526109bd815160c060e08501526101a0840190610922565b6109da60208301519160df19928386830301610100870152610922565b6040830151906005821015610a7e5760c09360a09384610a2e610a19610a4195610a57976101208c01526060860151858c8303016101408d0152610922565b6080850151848b8303016101608c0152610922565b9201519087830301610180880152610922565b6040860151858203601f19016060870152610947565b60608501516001600160a01b03166080850152936080810151151584830152015191015290565b634e487b7160e01b600052602160045260246000fd5b346102585760a0610b35610aa736610889565b604090815190610ab682610b96565b600080958382809552828651610acb81610b96565b606090818152816020820152828982015281808201528160808201528185820152602084015280888401528201528260808201520152610b166102f86009546001600160a01b031690565b8351808096819463deb50c3560e01b8352600483019190602083019252565b03915afa9182156103c15783610b579493610b5b575b5050519182918261098f565b0390f35b610b789293503d8091833e610b708183610be7565b810190611977565b903880610b4b565b634e487b7160e01b600052604160045260246000fd5b60c0810190811067ffffffffffffffff821117610bb257604052565b610b80565b6040810190811067ffffffffffffffff821117610bb257604052565b67ffffffffffffffff8111610bb257604052565b90601f8019910116810190811067ffffffffffffffff821117610bb257604052565b60405190610c1682610b96565b565b604051906080820182811067ffffffffffffffff821117610bb257604052565b604051906060820182811067ffffffffffffffff821117610bb257604052565b67ffffffffffffffff8111610bb257601f01601f191660200190565b604036600319011261025857600435610c8c81610428565b6024359067ffffffffffffffff8211610258573660238301121561025857816004013590610cb982610c58565b91610cc76040519384610be7565b808352366024828601011161025857602081600092602461001697018387013784010152611a15565b34610258576000366003190112610258576001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610d5b5760206040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b604051632bade49760e11b8152600490fd5b3461025857610d7b36610889565b610d83611c40565b610d8b6120b0565b8015610e34576005805460ff16610e225760045442106103e35760075415610e01575b60005b828110610de2575b61001660017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b815460ff16610dfc57600190610df66122ff565b01610db1565b610db9565b478015610e1057600755610dae565b60405163078fa9c560e01b8152600490fd5b6040516386f66a2d60e01b8152600490fd5b60405163259b7da160e01b8152600490fd5b3461025857600036600319011261025857602060ff600554166040519015158152f35b346102585760a0610e81610e7c36610889565b611b0a565b606060405192805184526020810151602085015260408101516040850152015160608301526080820152f35b3461025857600036600319011261025857602060ff7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330054166040519015158152f35b346102585760008060031936011261040757610f09612065565b806001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993008054906001600160a01b031982169055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b346102585760003660031901126102585760206001600160a01b0360095416604051908152f35b3461025857600036600319011261025857600460206001600160a01b0360095416604051928380926339ebdca160e11b82525afa80156103c157602091600091610fe2575b506040519015158152f35b610ff99150823d84116107ac5761079e8183610be7565b38610fd7565b34610258576000366003190112610258576020600354604051908152f35b34610258576000366003190112610258576020600754604051908152f35b3461025857600036600319011261025857611054612065565b61105c6120b0565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300600160ff198254161790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a1005b346102585760003660031901126102585760206001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005416604051908152f35b3461025857600036600319011261025857610b5760405161111a81610bb7565b6005815264302e352e3160d81b6020820152604051918291602083526020830190610922565b346102585761114e36610889565b611156612065565b620f42408111611191576020817fad1b95c977e762e6dee3f0186da277d924ff2d10b85910c5c5a46c9d28572aff92600155604051908152a1005b604051625a60c360e41b8152600490fd5b346102585760003660031901126102585760206001600160a01b0360005416604051908152f35b3461025857600080600319360112610407576040518091600a549081835260208093018092600a83527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a890835b81811061126a575050508461122c910385610be7565b60405193838594850191818652518092526040850193925b82811061125357505050500390f35b835185528695509381019392810192600101611244565b825484529286019260019283019201611216565b346102585761128c36610889565b600052600b60205260206001600160a01b0360406000205416604051908152f35b3461025857600080600319360112610407576112c7612065565b6112cf611c40565b47156103f557806103046102f86008546001600160a01b031690565b634e487b7160e01b600052603260045260246000fd5b600a5481101561133857600a6000527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a80190600090565b6112eb565b346102585761134b36610889565b600a5481101561025857602090600a6000527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a80154604051908152f35b34610258576020366003190112610258576100166004356113a881610428565b6113b0612065565b611bba565b9081602091031261025857516113ca81610428565b90565b6040513d6000823e3d90fd5b5190610c1682610428565b903590601e1981360301821215610258570180359067ffffffffffffffff821161025857602001918160051b3603831361025857565b91908110156113385760051b0190565b634e487b7160e01b600052601160045260246000fd5b9190820180921161144d57565b61142a565b9060198202918083046019149015171561144d57565b90604b820291808304604b149015171561144d57565b9060328202918083046032149015171561144d57565b9060648202918083046064149015171561144d57565b8181029291811591840414171561144d57565b67ffffffffffffffff8211610bb257680100000000000000008211610bb257600a5482600a55808310611536575b50600a6000527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a860005b8381106115225750505050565b600190602084359401938184015501611515565b6000600a600052837fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a892830192015b8281106115735750506114eb565b818155600101611565565b94919293946001600160a01b0390817f00000000000000000000000000000000000000000000000000000000000000001633036117235781871615611711576115d6906115c9611e1b565b6115d1611e56565b611e8c565b60608301936115e585856113e4565b6000199150600090815b8181106116cc575050620f42409150036116ba5761166e8261168b946116516116b499611635610c169c6001600160a01b03166001600160a01b03196000541617600055565b6001600160a01b03166001600160a01b03196002541617600255565b166001600160a01b03166001600160a01b03196008541617600855565b166001600160a01b03166001600160a01b03196009541617600955565b6116958135600155565b6116a26020820135600355565b6116af6040820135600455565b6113e4565b906114bd565b6040516304c7776560e21b8152600490fd5b90916116ed6116e5836116df8c8c6113e4565b9061141a565b358092611440565b9381116116ff579291906001016115ef565b6040516314986eaf60e11b8152600490fd5b6040516366e7950960e01b8152600490fd5b604051634df0b5ad60e11b8152600490fd5b604051906020820182811067ffffffffffffffff821117610bb25760405260008252565b6064810281159180820460641483171561144d57612710809204926032820290828204603214171561144d57829004830180931161144d578161179b82611452565b04830180931161144d576117ae90611468565b04810180911161144d5790565b81601f820112156102585780516117d181610c58565b926117df6040519485610be7565b81845260208284010111610258576113ca91602080850191016108ff565b5190600582101561025857565b91909160c0818403126102585761181f610c09565b92815167ffffffffffffffff90818111610258578261183f9185016117bb565b8552602083015181811161025857826118599185016117bb565b602086015261186a604084016117fd565b6040860152606083015181811161025857826118879185016117bb565b6060860152608083015181811161025857826118a49185016117bb565b608086015260a0830151908111610258576118bf92016117bb565b60a0830152565b67ffffffffffffffff8111610bb25760051b60200190565b9080601f830112156102585781519160206118f8846118c6565b936040936119096040519687610be7565b818652828087019260061b85010193818511610258578301915b8483106119335750505050505090565b858383031261025857838691825161194a81610bb7565b855161195581610428565b81528286015183820152815201920191611923565b5190811515820361025857565b9060208282031261025857815167ffffffffffffffff92838211610258570160c081830312610258576119a8610c09565b9281518452602082015181811161025857836119c591840161180a565b602085015260408201519081116102585760a0926119e49183016118de565b60408401526119f5606082016113d9565b6060840152611a066080820161196a565b6080840152015160a082015290565b91906001600160a01b03807f000000000000000000000000000000000000000000000000000000000000000016908130146107c557807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54169182036107b35784602091611a85936106d8612065565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa9081156103c157600091611aeb575b5015611aca57610c169192611f9b565b60405163310365cd60e21b81526001600160a01b0384166004820152602490fd5b611b04915060203d6020116107ac5761079e8183610be7565b38611aba565b906040516080810181811067ffffffffffffffff821117610bb257600091606091604052828152826020820152826040820152015260648202918083046064148115171561144d5780611b6a611b626113ca9361147e565b612710900490565b611b76611b6283611452565b611b82611b6284611468565b91612710611b8e610c18565b97048752602087015260408601526060850152611759565b90816020910312610258576113ca9061196a565b6001600160a01b03809116908115611c27577f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300805490836001600160a01b03198316179055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b604051631e4fbdf760e01b815260006004820152602490fd5b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f006002815414611c705760029055565b604051633ee5aeb560e01b8152600490fd5b90804710611dd657600091611c9e838080808686617530f11590565b611ca757505050565b611cbe6102f86102f885546001600160a01b031690565b803b15611dd257838391600460405180968193630d0e30db60e41b83525af19182156103c157611d3c93602093611db9575b50611d086102f86102f887546001600160a01b031690565b908560405180968195829463a9059cbb60e01b845260048401602090939291936001600160a01b0360408201951681520152565b03925af19182156103c15791611d9a575b5015611d5557565b60405162461bcd60e51b815260206004820152601460248201527f57455448207472616e73666572206661696c65640000000000000000000000006044820152606490fd5b611db3915060203d6020116107ac5761079e8183610be7565b38611d4d565b80611dc6611dcc92610bd3565b8061024d565b38611cf0565b8380fd5b60405162461bcd60e51b815260206004820152601460248201527f496e73756666696369656e742062616c616e63650000000000000000000000006044820152606490fd5b611e23612713565b611e2b612713565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300805460ff19169055565b611e5e612713565b611e66612713565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b610c1690611e98612713565b6113b0612713565b90816020910312610258575190565b90611edb7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1690565b15611eea5750610c169061288a565b6040516352d1902d60e01b81526020816004816001600160a01b0387165afa60009181611f6a575b50611f295760405163605d905960e11b8152600490fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc03611f5857610c1691612792565b604051630424da4b60e11b8152600490fd5b611f8d91925060203d602011611f94575b611f858183610be7565b810190611ea0565b9038611f12565b503d611f7b565b90611fc77f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1690565b15611fd65750610c169061288a565b6040516352d1902d60e01b81526020816004816001600160a01b0387165afa60009181612044575b506120155760405163605d905960e11b8152600490fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc03611f5857610c1691612832565b61205e91925060203d602011611f9457611f858183610be7565b9038611ffe565b6001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005416330361209857565b60405163118cdaa760e01b8152336004820152602490fd5b60ff7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330054166120db57565b60405163d93c066560e01b8152600490fd5b9060208282031261025857815167ffffffffffffffff92838211610258570160608183031261025857604051926060840184811082821117610bb2576040528151845260208201519081116102585760409261214a9183016118de565b6020840152015161215a81610428565b604082015290565b600019811461144d5760010190565b9061217b826118c6565b6121886040519182610be7565b8281528092612199601f19916118c6565b0190602036910137565b80518210156113385760209160051b010190565b90620f424091820391821161144d57565b9190820391821161144d57565b90815180825260208080930193019160005b8281106121f5575050505090565b83516001600160a01b0316855293810193928101926001016121e7565b90815180825260208080930193019160005b828110612232575050505090565b835163ffffffff1685529381019392810192600101612224565b926122c3906122b56080946122a76001600160a01b039599989960a0895263ffffffff81511660a08a015260406122936020830151606060c08d01526101008c01906121d5565b910151898203609f190160e08b0152612212565b9087820360208901526121d5565b908582036040870152612212565b946000606085015216910152565b9195949390926122eb60809460a0855260a08501906121d5565b966020840152604083015260608201520152565b6123146102f86009546001600160a01b031690565b604080519163bad22aff60e01b835282600081819593829460049788925af18291816126ef575b5061238b57825162461bcd60e51b815260208186018181526018918101919091527f64726f70546f70566f7465645069656365206661696c65640000000000000000604082015281906060010390fd5b6006939293546123a261239d82612162565b600655565b600654600a54146126d8575b602091828101805151906123c182612171565b916123cb81612171565b91875b828110612666575050506123ed6102f86008546001600160a01b031690565b6124046123fb6001546121b7565b63ffffffff1690565b61241b61240f610c38565b63ffffffff9092168252565b8387820152828a820152895191631ea72fdf60e01b835287838b818c855af19283156103c1576001600160a01b039389918b91612649575b508b8d5180968193638da5cb5b60e01b8352165afa9182156103c157898b61249a88958f8d98859261262a575b5051630e94227960e11b815298899788968795860161224c565b03925af19485156103c1578695612605575b505083946124e784956124cc61256196600052600b602052604060002090565b906001600160a01b03166001600160a01b0319825416179055565b61251561250c6007546125066124fc89611301565b90549060031b1c90565b906114aa565b620f4240900490565b94816125296002546001600160a01b031690565b9861253f6102f86009546001600160a01b031690565b86518c5163deb50c3560e01b8152928301908152919788928391829160200190565b03915afa9889156103c1576125c06125cb996125b96060610c169d7f9c7f13a6670d986e16eac2fdab5e9b61887c71ff3bee8e46fbcc246a474e173f9a886125e299926125ea575b505001516001600160a01b031690565b90896128ef565b9889809651986121c8565b6125d76124fc84611301565b9151958695866122d1565b0390a2611c82565b6125fe92503d8091833e610b708183610be7565b38806125a9565b612561949550908161262292903d106103ba576103ab8183610be7565b9392386124ac565b612642919250893d8b116103ba576103ab8183610be7565b9038612480565b6126609150823d84116103ba576103ab8183610be7565b38612453565b806126a061268861267a60019486516121a3565b51516001600160a01b031690565b61269283896121a3565b906001600160a01b03169052565b6126d26126bd6123fb8b6126b58588516121a3565b510151611494565b6126c783886121a3565b9063ffffffff169052565b016123ce565b6126ea600160ff196005541617600555565b6123ae565b61270c9192503d8085833e6127048183610be7565b8101906120ed565b903861233b565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c161561274257565b604051631afcd79f60e31b8152600490fd5b60ff7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330054161561278057565b604051638dfc202b60e01b8152600490fd5b61279b8161288a565b7fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60206040516001600160a01b0384168152a18151801580159061282a575b6127e357505050565b60008091602061281f9501845af43d15612822573d9161280283610c58565b926128106040519485610be7565b83523d6000602085013e612a56565b50565b606091612a56565b5060006127da565b61283b8161288a565b7fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60206040516001600160a01b0384168152a181518015801590612882576127e357505050565b5060016127da565b803b156128cd576001600160a01b037f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc91166001600160a01b0319825416179055565b60405163310365cd60e21b81526001600160a01b039091166004820152602490fd5b91909181836128fd83611b0a565b9490926001600160a01b0380931615612a2e575b821615612a07575b7f0000000000000000000000000000000000000000000000000000000000000000917f000000000000000000000000000000000000000000000000000000000000000016908351906020850151976060604087015196015195843b15610258576040516301ba3d7f60e71b81526001600160a01b039283166004820152602481019490945294811660448401819052606484019990995216608482015260a481019290925260c482019590955260e481019190915292600090849061010490829086905af19283156103c1576113ca936129f4575b506121c8565b80611dc6612a0192610bd3565b386129ee565b507f0000000000000000000000000000000000000000000000000000000000000000612919565b7f00000000000000000000000000000000000000000000000000000000000000009650612911565b90612a7d5750805115612a6b57805190602001fd5b604051630a12f52160e11b8152600490fd5b81511580612ab0575b612a8e575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b15612a8656fea264697066735822122050cadc44f5ad999af5729f52eb790e1aae71d6299b2d4bf54a536f85ea857bcb64736f6c63430008160033000000000000000000000000d7c51e494b778bff7334afbe38d3961935144b0a0000000000000000000000009f7f714a3cd6b6eadbc9629838b0f6ddeabe1710000000000000000000000000459b40643251f10d93334d91cf256f97d31f69de
Deployed Bytecode
0x60806040526004361015610018575b361561001657005b005b60003560e01c80630e769b2b14610248578063135b15e91461024357806327394dce1461023e5780632b1b5cf8146102395780632dc8fb1c146102345780632df05a3e1461022f5780633197cbb61461022a5780633659cfe6146102255780633f26479e146102205780633f4ba83a1461021b578063400a976a146102165780634132239b14610211578063481c6a751461020c57806349a33562146102075780634f1ef2861461020257806352d1902d146101fd578063553a4e23146101f85780635c76ca2d146101f35780635c93c3d9146101ee5780635c975abb146101e9578063715018a6146101e4578063727bc4f8146101df57806373d7b942146101da57806378e97925146101d55780637c39a58f146101d05780638456cb59146101cb5780638da5cb5b146101c6578063a0a8e460146101c1578063ab7d4b22146101bc578063ad5c4648146101b7578063b8d1a3b5146101b2578063c5ea59ed146101ad578063db2e21bc146101a8578063f0f8f9f2146101a35763f2fde38b0361000e57611388565b61133d565b6112ad565b61127e565b6111c9565b6111a2565b611140565b6110fa565b6110b4565b61103b565b61101d565b610fff565b610f92565b610f6b565b610eef565b610ead565b610e69565b610e46565b610d6d565b610cf0565b610c74565b610a94565b6108bb565b61089b565b61086b565b6107f5565b6107d7565b61064d565b61062f565b610611565b610439565b61040a565b6102ab565b610284565b61025d565b600091031261025857565b600080fd5b346102585760003660031901126102585760206001600160a01b0360085416604051908152f35b346102585760003660031901126102585760206001600160a01b0360025416604051908152f35b3461025857600080600319360112610407576102c5611c40565b47156103f5576102de6102da60055460ff1690565b1590565b6103e357806103046102f86008546001600160a01b031690565b6001600160a01b031690565b60405190631ea72fdf60e01b82528160048160209586945af19081156103c1576001600160a01b0391839185916103c6575b50600460405180948193638da5cb5b60e01b8352165afa9081156103c157610368928492610394575b50504790611c82565b61039160017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b80f35b6103b39250803d106103ba575b6103ab8183610be7565b8101906113b5565b388061035f565b503d6103a1565b6113cd565b6103dd9150823d84116103ba576103ab8183610be7565b38610336565b6040516325765c0f60e11b8152600490fd5b6040516313e9de3f60e01b8152600490fd5b80fd5b34610258576000366003190112610258576020600154604051908152f35b6001600160a01b0381160361025857565b346102585760031960c0368201126102585760043561045781610428565b6024359061046482610428565b60443561047081610428565b60643561047c81610428565b6084359161048983610428565b60a4359467ffffffffffffffff96878711610258576080908736030112610258577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00549660ff8860401c1615971680159081610609575b60011490816105ff575b1590816105f6575b506105e4577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805467ffffffffffffffff1916600117905561053d95876105a3575b6004019461157e565b61054357005b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468ff000000000000000019169055604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1005b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468ff0000000000000000191668010000000000000000179055610534565b60405163f92ee8a960e01b8152600490fd5b905015386104f2565b303b1591506104ea565b8891506104e0565b34610258576000366003190112610258576020600654604051908152f35b34610258576000366003190112610258576020600454604051908152f35b346102585760203660031901126102585760043561066a81610428565b6001600160a01b03807f0000000000000000000000009e4e047004aedde4e5bd130432358f943e93ff2516908130146107c557807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54169182036107b35782602091610714936106d8612065565b6106e0612754565b604051639bb8dcfd60e01b81526001600160a01b039182166004820152921660248301529092839190829081906044820190565b03917f000000000000000000000000d7c51e494b778bff7334afbe38d3961935144b0a165afa9081156103c157600091610784575b5015610761576100169061075b611735565b90611eaf565b60405163310365cd60e21b81526001600160a01b03919091166004820152602490fd5b6107a6915060203d6020116107ac575b61079e8183610be7565b810190611ba6565b38610749565b503d610794565b60405163073a6c8560e51b8152600490fd5b6040516343d22ee960e01b8152600490fd5b34610258576000366003190112610258576020604051620f42408152f35b346102585760003660031901126102585761080e612065565b610816612754565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330060ff1981541690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a1005b34610258576000366003190112610258576020600a54604051908152f35b60209060031901126102585760043590565b346102585760206108b36108ae36610889565b611759565b604051908152f35b346102585760003660031901126102585760206040516001600160a01b037f000000000000000000000000d7c51e494b778bff7334afbe38d3961935144b0a168152f35b60005b8381106109125750506000910152565b8181015183820152602001610902565b9060209161093b815180928185528580860191016108ff565b601f01601f1916010190565b90815180825260208080930193019160005b828110610967575050505090565b835180516001600160a01b031686528201518583015260409094019392810192600101610959565b6020815281516020820152602082015160c060408301526109bd815160c060e08501526101a0840190610922565b6109da60208301519160df19928386830301610100870152610922565b6040830151906005821015610a7e5760c09360a09384610a2e610a19610a4195610a57976101208c01526060860151858c8303016101408d0152610922565b6080850151848b8303016101608c0152610922565b9201519087830301610180880152610922565b6040860151858203601f19016060870152610947565b60608501516001600160a01b03166080850152936080810151151584830152015191015290565b634e487b7160e01b600052602160045260246000fd5b346102585760a0610b35610aa736610889565b604090815190610ab682610b96565b600080958382809552828651610acb81610b96565b606090818152816020820152828982015281808201528160808201528185820152602084015280888401528201528260808201520152610b166102f86009546001600160a01b031690565b8351808096819463deb50c3560e01b8352600483019190602083019252565b03915afa9182156103c15783610b579493610b5b575b5050519182918261098f565b0390f35b610b789293503d8091833e610b708183610be7565b810190611977565b903880610b4b565b634e487b7160e01b600052604160045260246000fd5b60c0810190811067ffffffffffffffff821117610bb257604052565b610b80565b6040810190811067ffffffffffffffff821117610bb257604052565b67ffffffffffffffff8111610bb257604052565b90601f8019910116810190811067ffffffffffffffff821117610bb257604052565b60405190610c1682610b96565b565b604051906080820182811067ffffffffffffffff821117610bb257604052565b604051906060820182811067ffffffffffffffff821117610bb257604052565b67ffffffffffffffff8111610bb257601f01601f191660200190565b604036600319011261025857600435610c8c81610428565b6024359067ffffffffffffffff8211610258573660238301121561025857816004013590610cb982610c58565b91610cc76040519384610be7565b808352366024828601011161025857602081600092602461001697018387013784010152611a15565b34610258576000366003190112610258576001600160a01b037f0000000000000000000000009e4e047004aedde4e5bd130432358f943e93ff25163003610d5b5760206040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b604051632bade49760e11b8152600490fd5b3461025857610d7b36610889565b610d83611c40565b610d8b6120b0565b8015610e34576005805460ff16610e225760045442106103e35760075415610e01575b60005b828110610de2575b61001660017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b815460ff16610dfc57600190610df66122ff565b01610db1565b610db9565b478015610e1057600755610dae565b60405163078fa9c560e01b8152600490fd5b6040516386f66a2d60e01b8152600490fd5b60405163259b7da160e01b8152600490fd5b3461025857600036600319011261025857602060ff600554166040519015158152f35b346102585760a0610e81610e7c36610889565b611b0a565b606060405192805184526020810151602085015260408101516040850152015160608301526080820152f35b3461025857600036600319011261025857602060ff7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330054166040519015158152f35b346102585760008060031936011261040757610f09612065565b806001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993008054906001600160a01b031982169055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b346102585760003660031901126102585760206001600160a01b0360095416604051908152f35b3461025857600036600319011261025857600460206001600160a01b0360095416604051928380926339ebdca160e11b82525afa80156103c157602091600091610fe2575b506040519015158152f35b610ff99150823d84116107ac5761079e8183610be7565b38610fd7565b34610258576000366003190112610258576020600354604051908152f35b34610258576000366003190112610258576020600754604051908152f35b3461025857600036600319011261025857611054612065565b61105c6120b0565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300600160ff198254161790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a1005b346102585760003660031901126102585760206001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005416604051908152f35b3461025857600036600319011261025857610b5760405161111a81610bb7565b6005815264302e352e3160d81b6020820152604051918291602083526020830190610922565b346102585761114e36610889565b611156612065565b620f42408111611191576020817fad1b95c977e762e6dee3f0186da277d924ff2d10b85910c5c5a46c9d28572aff92600155604051908152a1005b604051625a60c360e41b8152600490fd5b346102585760003660031901126102585760206001600160a01b0360005416604051908152f35b3461025857600080600319360112610407576040518091600a549081835260208093018092600a83527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a890835b81811061126a575050508461122c910385610be7565b60405193838594850191818652518092526040850193925b82811061125357505050500390f35b835185528695509381019392810192600101611244565b825484529286019260019283019201611216565b346102585761128c36610889565b600052600b60205260206001600160a01b0360406000205416604051908152f35b3461025857600080600319360112610407576112c7612065565b6112cf611c40565b47156103f557806103046102f86008546001600160a01b031690565b634e487b7160e01b600052603260045260246000fd5b600a5481101561133857600a6000527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a80190600090565b6112eb565b346102585761134b36610889565b600a5481101561025857602090600a6000527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a80154604051908152f35b34610258576020366003190112610258576100166004356113a881610428565b6113b0612065565b611bba565b9081602091031261025857516113ca81610428565b90565b6040513d6000823e3d90fd5b5190610c1682610428565b903590601e1981360301821215610258570180359067ffffffffffffffff821161025857602001918160051b3603831361025857565b91908110156113385760051b0190565b634e487b7160e01b600052601160045260246000fd5b9190820180921161144d57565b61142a565b9060198202918083046019149015171561144d57565b90604b820291808304604b149015171561144d57565b9060328202918083046032149015171561144d57565b9060648202918083046064149015171561144d57565b8181029291811591840414171561144d57565b67ffffffffffffffff8211610bb257680100000000000000008211610bb257600a5482600a55808310611536575b50600a6000527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a860005b8381106115225750505050565b600190602084359401938184015501611515565b6000600a600052837fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a892830192015b8281106115735750506114eb565b818155600101611565565b94919293946001600160a01b0390817f000000000000000000000000d7c51e494b778bff7334afbe38d3961935144b0a1633036117235781871615611711576115d6906115c9611e1b565b6115d1611e56565b611e8c565b60608301936115e585856113e4565b6000199150600090815b8181106116cc575050620f42409150036116ba5761166e8261168b946116516116b499611635610c169c6001600160a01b03166001600160a01b03196000541617600055565b6001600160a01b03166001600160a01b03196002541617600255565b166001600160a01b03166001600160a01b03196008541617600855565b166001600160a01b03166001600160a01b03196009541617600955565b6116958135600155565b6116a26020820135600355565b6116af6040820135600455565b6113e4565b906114bd565b6040516304c7776560e21b8152600490fd5b90916116ed6116e5836116df8c8c6113e4565b9061141a565b358092611440565b9381116116ff579291906001016115ef565b6040516314986eaf60e11b8152600490fd5b6040516366e7950960e01b8152600490fd5b604051634df0b5ad60e11b8152600490fd5b604051906020820182811067ffffffffffffffff821117610bb25760405260008252565b6064810281159180820460641483171561144d57612710809204926032820290828204603214171561144d57829004830180931161144d578161179b82611452565b04830180931161144d576117ae90611468565b04810180911161144d5790565b81601f820112156102585780516117d181610c58565b926117df6040519485610be7565b81845260208284010111610258576113ca91602080850191016108ff565b5190600582101561025857565b91909160c0818403126102585761181f610c09565b92815167ffffffffffffffff90818111610258578261183f9185016117bb565b8552602083015181811161025857826118599185016117bb565b602086015261186a604084016117fd565b6040860152606083015181811161025857826118879185016117bb565b6060860152608083015181811161025857826118a49185016117bb565b608086015260a0830151908111610258576118bf92016117bb565b60a0830152565b67ffffffffffffffff8111610bb25760051b60200190565b9080601f830112156102585781519160206118f8846118c6565b936040936119096040519687610be7565b818652828087019260061b85010193818511610258578301915b8483106119335750505050505090565b858383031261025857838691825161194a81610bb7565b855161195581610428565b81528286015183820152815201920191611923565b5190811515820361025857565b9060208282031261025857815167ffffffffffffffff92838211610258570160c081830312610258576119a8610c09565b9281518452602082015181811161025857836119c591840161180a565b602085015260408201519081116102585760a0926119e49183016118de565b60408401526119f5606082016113d9565b6060840152611a066080820161196a565b6080840152015160a082015290565b91906001600160a01b03807f0000000000000000000000009e4e047004aedde4e5bd130432358f943e93ff2516908130146107c557807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54169182036107b35784602091611a85936106d8612065565b03917f000000000000000000000000d7c51e494b778bff7334afbe38d3961935144b0a165afa9081156103c157600091611aeb575b5015611aca57610c169192611f9b565b60405163310365cd60e21b81526001600160a01b0384166004820152602490fd5b611b04915060203d6020116107ac5761079e8183610be7565b38611aba565b906040516080810181811067ffffffffffffffff821117610bb257600091606091604052828152826020820152826040820152015260648202918083046064148115171561144d5780611b6a611b626113ca9361147e565b612710900490565b611b76611b6283611452565b611b82611b6284611468565b91612710611b8e610c18565b97048752602087015260408601526060850152611759565b90816020910312610258576113ca9061196a565b6001600160a01b03809116908115611c27577f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300805490836001600160a01b03198316179055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b604051631e4fbdf760e01b815260006004820152602490fd5b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f006002815414611c705760029055565b604051633ee5aeb560e01b8152600490fd5b90804710611dd657600091611c9e838080808686617530f11590565b611ca757505050565b611cbe6102f86102f885546001600160a01b031690565b803b15611dd257838391600460405180968193630d0e30db60e41b83525af19182156103c157611d3c93602093611db9575b50611d086102f86102f887546001600160a01b031690565b908560405180968195829463a9059cbb60e01b845260048401602090939291936001600160a01b0360408201951681520152565b03925af19182156103c15791611d9a575b5015611d5557565b60405162461bcd60e51b815260206004820152601460248201527f57455448207472616e73666572206661696c65640000000000000000000000006044820152606490fd5b611db3915060203d6020116107ac5761079e8183610be7565b38611d4d565b80611dc6611dcc92610bd3565b8061024d565b38611cf0565b8380fd5b60405162461bcd60e51b815260206004820152601460248201527f496e73756666696369656e742062616c616e63650000000000000000000000006044820152606490fd5b611e23612713565b611e2b612713565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300805460ff19169055565b611e5e612713565b611e66612713565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b610c1690611e98612713565b6113b0612713565b90816020910312610258575190565b90611edb7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1690565b15611eea5750610c169061288a565b6040516352d1902d60e01b81526020816004816001600160a01b0387165afa60009181611f6a575b50611f295760405163605d905960e11b8152600490fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc03611f5857610c1691612792565b604051630424da4b60e11b8152600490fd5b611f8d91925060203d602011611f94575b611f858183610be7565b810190611ea0565b9038611f12565b503d611f7b565b90611fc77f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1690565b15611fd65750610c169061288a565b6040516352d1902d60e01b81526020816004816001600160a01b0387165afa60009181612044575b506120155760405163605d905960e11b8152600490fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc03611f5857610c1691612832565b61205e91925060203d602011611f9457611f858183610be7565b9038611ffe565b6001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005416330361209857565b60405163118cdaa760e01b8152336004820152602490fd5b60ff7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330054166120db57565b60405163d93c066560e01b8152600490fd5b9060208282031261025857815167ffffffffffffffff92838211610258570160608183031261025857604051926060840184811082821117610bb2576040528151845260208201519081116102585760409261214a9183016118de565b6020840152015161215a81610428565b604082015290565b600019811461144d5760010190565b9061217b826118c6565b6121886040519182610be7565b8281528092612199601f19916118c6565b0190602036910137565b80518210156113385760209160051b010190565b90620f424091820391821161144d57565b9190820391821161144d57565b90815180825260208080930193019160005b8281106121f5575050505090565b83516001600160a01b0316855293810193928101926001016121e7565b90815180825260208080930193019160005b828110612232575050505090565b835163ffffffff1685529381019392810192600101612224565b926122c3906122b56080946122a76001600160a01b039599989960a0895263ffffffff81511660a08a015260406122936020830151606060c08d01526101008c01906121d5565b910151898203609f190160e08b0152612212565b9087820360208901526121d5565b908582036040870152612212565b946000606085015216910152565b9195949390926122eb60809460a0855260a08501906121d5565b966020840152604083015260608201520152565b6123146102f86009546001600160a01b031690565b604080519163bad22aff60e01b835282600081819593829460049788925af18291816126ef575b5061238b57825162461bcd60e51b815260208186018181526018918101919091527f64726f70546f70566f7465645069656365206661696c65640000000000000000604082015281906060010390fd5b6006939293546123a261239d82612162565b600655565b600654600a54146126d8575b602091828101805151906123c182612171565b916123cb81612171565b91875b828110612666575050506123ed6102f86008546001600160a01b031690565b6124046123fb6001546121b7565b63ffffffff1690565b61241b61240f610c38565b63ffffffff9092168252565b8387820152828a820152895191631ea72fdf60e01b835287838b818c855af19283156103c1576001600160a01b039389918b91612649575b508b8d5180968193638da5cb5b60e01b8352165afa9182156103c157898b61249a88958f8d98859261262a575b5051630e94227960e11b815298899788968795860161224c565b03925af19485156103c1578695612605575b505083946124e784956124cc61256196600052600b602052604060002090565b906001600160a01b03166001600160a01b0319825416179055565b61251561250c6007546125066124fc89611301565b90549060031b1c90565b906114aa565b620f4240900490565b94816125296002546001600160a01b031690565b9861253f6102f86009546001600160a01b031690565b86518c5163deb50c3560e01b8152928301908152919788928391829160200190565b03915afa9889156103c1576125c06125cb996125b96060610c169d7f9c7f13a6670d986e16eac2fdab5e9b61887c71ff3bee8e46fbcc246a474e173f9a886125e299926125ea575b505001516001600160a01b031690565b90896128ef565b9889809651986121c8565b6125d76124fc84611301565b9151958695866122d1565b0390a2611c82565b6125fe92503d8091833e610b708183610be7565b38806125a9565b612561949550908161262292903d106103ba576103ab8183610be7565b9392386124ac565b612642919250893d8b116103ba576103ab8183610be7565b9038612480565b6126609150823d84116103ba576103ab8183610be7565b38612453565b806126a061268861267a60019486516121a3565b51516001600160a01b031690565b61269283896121a3565b906001600160a01b03169052565b6126d26126bd6123fb8b6126b58588516121a3565b510151611494565b6126c783886121a3565b9063ffffffff169052565b016123ce565b6126ea600160ff196005541617600555565b6123ae565b61270c9192503d8085833e6127048183610be7565b8101906120ed565b903861233b565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c161561274257565b604051631afcd79f60e31b8152600490fd5b60ff7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330054161561278057565b604051638dfc202b60e01b8152600490fd5b61279b8161288a565b7fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60206040516001600160a01b0384168152a18151801580159061282a575b6127e357505050565b60008091602061281f9501845af43d15612822573d9161280283610c58565b926128106040519485610be7565b83523d6000602085013e612a56565b50565b606091612a56565b5060006127da565b61283b8161288a565b7fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60206040516001600160a01b0384168152a181518015801590612882576127e357505050565b5060016127da565b803b156128cd576001600160a01b037f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc91166001600160a01b0319825416179055565b60405163310365cd60e21b81526001600160a01b039091166004820152602490fd5b91909181836128fd83611b0a565b9490926001600160a01b0380931615612a2e575b821615612a07575b7f000000000000000000000000459b40643251f10d93334d91cf256f97d31f69de917f0000000000000000000000009f7f714a3cd6b6eadbc9629838b0f6ddeabe171016908351906020850151976060604087015196015195843b15610258576040516301ba3d7f60e71b81526001600160a01b039283166004820152602481019490945294811660448401819052606484019990995216608482015260a481019290925260c482019590955260e481019190915292600090849061010490829086905af19283156103c1576113ca936129f4575b506121c8565b80611dc6612a0192610bd3565b386129ee565b507f000000000000000000000000459b40643251f10d93334d91cf256f97d31f69de612919565b7f000000000000000000000000459b40643251f10d93334d91cf256f97d31f69de9650612911565b90612a7d5750805115612a6b57805190602001fd5b604051630a12f52160e11b8152600490fd5b81511580612ab0575b612a8e575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b15612a8656fea264697066735822122050cadc44f5ad999af5729f52eb790e1aae71d6299b2d4bf54a536f85ea857bcb64736f6c63430008160033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000d7c51e494b778bff7334afbe38d3961935144b0a0000000000000000000000009f7f714a3cd6b6eadbc9629838b0f6ddeabe1710000000000000000000000000459b40643251f10d93334d91cf256f97d31f69de
-----Decoded View---------------
Arg [0] : _manager (address): 0xD7C51e494B778Bff7334afBE38D3961935144B0A
Arg [1] : _protocolRewards (address): 0x9f7f714a3CD6B6eADbC9629838B0f6ddEAbE1710
Arg [2] : _protocolFeeRecipient (address): 0x459B40643251F10D93334D91cf256F97D31F69de
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000d7c51e494b778bff7334afbe38d3961935144b0a
Arg [1] : 0000000000000000000000009f7f714a3cd6b6eadbc9629838b0f6ddeabe1710
Arg [2] : 000000000000000000000000459b40643251f10d93334d91cf256f97d31f69de
Loading...
Loading
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.