Overview
ETH Balance
0 ETH
ETH Value
$0.00Token Holdings
More Info
Private Name Tags
ContractCreator
Sponsored
Latest 25 from a total of 106 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Sign Agreement | 125451746 | 39 hrs ago | IN | 0 ETH | 0.000001288034 | ||||
Sign Agreement A... | 125418811 | 2 days ago | IN | 0 ETH | 0.000000401677 | ||||
Sign Agreement A... | 125383106 | 3 days ago | IN | 0 ETH | 0.000000076556 | ||||
Sign Agreement A... | 125381091 | 3 days ago | IN | 0 ETH | 0.000000088132 | ||||
Sign Agreement A... | 125379751 | 3 days ago | IN | 0 ETH | 0.000000103481 | ||||
Sign Agreement A... | 125375801 | 3 days ago | IN | 0 ETH | 0.000000217226 | ||||
Sign Agreement A... | 125367223 | 3 days ago | IN | 0 ETH | 0.000000225233 | ||||
Sign Agreement A... | 125357384 | 3 days ago | IN | 0 ETH | 0.000000181436 | ||||
Sign Agreement A... | 124967536 | 12 days ago | IN | 0 ETH | 0.000000184327 | ||||
Sign Agreement | 124940109 | 13 days ago | IN | 0 ETH | 0.000000096031 | ||||
Sign Agreement A... | 124940077 | 13 days ago | IN | 0 ETH | 0.000000385262 | ||||
Sign Agreement A... | 124814509 | 16 days ago | IN | 0 ETH | 0.000000156733 | ||||
Sign Agreement A... | 124779280 | 17 days ago | IN | 0 ETH | 0.000000039709 | ||||
Sign Agreement A... | 124772656 | 17 days ago | IN | 0 ETH | 0.000000032554 | ||||
Sign Agreement A... | 124738321 | 18 days ago | IN | 0 ETH | 0.00000014559 | ||||
Sign Agreement A... | 124631278 | 20 days ago | IN | 0 ETH | 0.00000846242 | ||||
Sign Agreement A... | 124619712 | 20 days ago | IN | 0 ETH | 0.000000221065 | ||||
Sign Agreement A... | 124592541 | 21 days ago | IN | 0 ETH | 0.000000449608 | ||||
Sign Agreement | 124585809 | 21 days ago | IN | 0 ETH | 0.000000719426 | ||||
Set Agreement | 124585142 | 21 days ago | IN | 0 ETH | 0.000001359573 | ||||
Set Agreement | 124581659 | 21 days ago | IN | 0 ETH | 0.000000110461 | ||||
Sign Agreement A... | 124537068 | 22 days ago | IN | 0 ETH | 0.000000155725 | ||||
Sign Agreement A... | 124533223 | 22 days ago | IN | 0 ETH | 0.000000210882 | ||||
Sign Agreement A... | 124529551 | 23 days ago | IN | 0 ETH | 0.000000158212 | ||||
Sign Agreement A... | 124519657 | 23 days ago | IN | 0 ETH | 0.000000034041 |
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
121667839 | 89 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Minimal Proxy Contract for 0xf6bc6dd30403e6ff5b3bebead32b8fce1b753aa1
Contract Name:
AgreementEligibility
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 1000000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; // import { console2 } from "forge-std/Test.sol"; // remove before deploy import { HatsEligibilityModule, HatsModule, IHatsEligibility } from "hats-module/HatsEligibilityModule.sol"; import { MultiClaimsHatter } from "multi-claims-hatter/MultiClaimsHatter.sol"; /*////////////////////////////////////////////////////////////// CUSTOM ERRORS //////////////////////////////////////////////////////////////*/ /// @dev Thrown when the caller does not wear the `OWNER_HAT` error AgreementEligibility_NotOwner(); /// @dev Thrown when the caller does not wear the `ARBITRATOR_HAT` error AgreementEligibility_NotArbitrator(); /** * @title AgreementEligibility * @author Haberdasher Labs * @notice A Hats Protocol module enabling individuals to permissionlessly claim a hat by signing an agreement */ contract AgreementEligibility is HatsEligibilityModule { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ /// @dev Emitted when a user "signs" the `agreement` and claims the hat event AgreementEligibility_HatClaimedWithAgreement(address claimer, uint256 hatId, string agreement); /// @dev Emitted when a user "signs" the `agreement` without claiming the hat event AgreementEligibility_AgreementSigned(address signer, string agreement); /// @dev Emitted when a new `agreement` is set event AgreementEligibility_AgreementSet(string agreement, uint256 grace); /*////////////////////////////////////////////////////////////// CONSTANTS //////////////////////////////////////////////////////////////*/ /** * This contract is a clone with immutable args, which means that it is deployed with a set of * immutable storage variables (ie constants). Accessing these constants is cheaper than accessing * regular storage variables (such as those set on initialization of a typical EIP-1167 clone), * but requires a slightly different approach since they are read from calldata instead of storage. * * Below is a table of constants and their locations. * * For more, see here: https://github.com/Saw-mon-and-Natalie/clones-with-immutable-args * * ------------------------------------------------------------------------+ * CLONE IMMUTABLE "STORAGE" | * ------------------------------------------------------------------------| * Offset | Constant | Type | Length | Source | * ------------------------------------------------------------------------| * 0 | IMPLEMENTATION | address | 20 | HatsModule | * 20 | HATS | address | 20 | HatsModule | * 40 | hatId | uint256 | 32 | HatsModule | * 72 | OWNER_HAT | uint256 | 32 | this | * 104 | ARBITRATOR_HAT | uint256 | 32 | this | * ------------------------------------------------------------------------+ */ /// @notice The id of the hat whose wearer serves as the owner of this contract function OWNER_HAT() public pure returns (uint256) { return _getArgUint256(72); } /// @notice The id of the hat whose wearer serves as the arbitrator for this contract function ARBITRATOR_HAT() public pure returns (uint256) { return _getArgUint256(104); } /*////////////////////////////////////////////////////////////// MUTABLE STATE //////////////////////////////////////////////////////////////*/ /// @dev The current agreement, typically as a CID of the agreement plaintext string public currentAgreement; /// @notice The id of the current agreement /// @dev The first agreement is id 1 (see {setUp}) so that id 0 can be used in {claimerAgreements} to indicate that an /// address has not signed any agreements uint256 public currentAgreementId; /// @notice The timestamp at which the current grace period ends. Existing wearers of `hatId` have until this time to /// sign the current agreement. uint256 public graceEndsAt; /// @notice The most recent agreement that each wearer has signed /// @dev agreementId=0 indicates that the wearer has not signed any agreements mapping(address claimer => uint256 agreementId) public claimerAgreements; /// @dev The inverse of the standing of each wearer; inversed so that wearers are in good standing by default mapping(address wearer => bool badStandings) internal _badStandings; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ /// @notice Deploy the implementation contract and set its version /// @dev This is only used to deploy the implementation contract, and should not be used to deploy clones constructor(string memory _version) HatsModule(_version) { } /*////////////////////////////////////////////////////////////// INITIALIZER //////////////////////////////////////////////////////////////*/ /// @inheritdoc HatsModule function _setUp(bytes calldata _initData) internal override { // decode init data (string memory agreement) = abi.decode(_initData, (string)); // set the initial agreement currentAgreement = agreement; ++currentAgreementId; } /*////////////////////////////////////////////////////////////// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////*/ /** * @notice Sign the current agreement and claim the hat * @param _claimsHatter a Multi Claims Hatter instance with which to perform claiming * @dev Mints the hat to the caller if: * - the hat is "claimable-for" with the provided claims hatter instance, and * - caller does not already wear the hat, and * - caller is not in bad standing for the hat. */ function signAgreementAndClaimHat(address _claimsHatter) public { uint256 agreementId = currentAgreementId; // save SLOADs // we need to set the claimer's agreement before minting so that they are eligible for the hat on minting claimerAgreements[msg.sender] = agreementId; /** * @dev this call will revert if... * - the hat is not "claimable-for", or * - caller is currently wearing the hat, or * - caller is in bad standing for the hat */ MultiClaimsHatter(_claimsHatter).claimHatFor(hatId(), msg.sender); emit AgreementEligibility_HatClaimedWithAgreement(msg.sender, hatId(), currentAgreement); } /** * @notice Sign the current agreement without claiming the hat. */ function signAgreement() public { uint256 agreementId = currentAgreementId; // save SLOADs claimerAgreements[msg.sender] = agreementId; emit AgreementEligibility_AgreementSigned(msg.sender, currentAgreement); } /*////////////////////////////////////////////////////////////// HATS ELIGIBILITY FUNCTION //////////////////////////////////////////////////////////////*/ /// @inheritdoc IHatsEligibility function getWearerStatus(address _wearer, uint256 /* _hatId */ ) public view override returns (bool eligible, bool standing) { standing = !_badStandings[_wearer]; // bad standing means ineligible if (!standing) return (false, false); uint256 claimerAgreementId = claimerAgreements[_wearer]; // save SLOADs uint256 agreementId = currentAgreementId; // save SLOAD unchecked { // _wearer is eligible if they have signed the current agreement, or... if (claimerAgreementId == agreementId) { eligible = true; // if we are in a grace period and they have signed the previous agreement /// @dev agreementId is always > 0 after initialization, so this subtraction is safe } else if (block.timestamp < graceEndsAt && claimerAgreementId == agreementId - 1) { eligible = true; } } } /*////////////////////////////////////////////////////////////// ADMIN FUNCTIONS //////////////////////////////////////////////////////////////*/ /** * @notice Set a new agreement, with a grace period * @dev Only callable by a wearer of the `OWNER_HAT` * @param _agreement The new agreement, as a hash of the agreement plaintext (likely a CID) * @param _grace The new grace period */ function setAgreement(string calldata _agreement, uint256 _grace) public onlyOwner { uint256 _graceEndsAt = block.timestamp + _grace; graceEndsAt = _graceEndsAt; currentAgreement = _agreement; ++currentAgreementId; emit AgreementEligibility_AgreementSet(_agreement, _graceEndsAt); } /** * @notice Revoke the `_wearer`'s hat and place them in bad standing * @dev Only callable by a wearer of the `ARBITRATOR_HAT` * @param _wearer The address of the wearer from whom to revoke the hat */ function revoke(address _wearer) public onlyArbitrator { // set bad standing in this contract _badStandings[_wearer] = true; // revoke _wearer's hat and set their standing to false in Hats.sol HATS().setHatWearerStatus(hatId(), _wearer, false, false); /** * @dev Hats.sol will emit the following events: * 1. ERC1155.TransferSingle (burn) * 2. Hats.WearerStandingChanged */ } /** * @notice Forgive the `_wearer`'s bad standing, allowing them to claim the hat again * @dev Only callable by a wearer of the `ARBITRATOR_HAT` * @param _wearer The address of the wearer to forgive */ function forgive(address _wearer) public onlyArbitrator { _badStandings[_wearer] = false; HATS().setHatWearerStatus(hatId(), _wearer, true, true); /// @dev Hats.sol will emit a Hats.WearerStandingChanged event } /*////////////////////////////////////////////////////////////// VIEW FUNCTIONS //////////////////////////////////////////////////////////////*/ /** * @notice Returns whether `_wearer` is in good standing * @param _wearer The address to check */ function wearerStanding(address _wearer) public view returns (bool) { return !_badStandings[_wearer]; } /*////////////////////////////////////////////////////////////// MODIFERS //////////////////////////////////////////////////////////////*/ /// @notice Reverts if the caller is not wearing the OWNER_HAT. modifier onlyOwner() { if (!HATS().isWearerOfHat(msg.sender, OWNER_HAT())) revert AgreementEligibility_NotOwner(); _; } /// @notice Reverts if the caller is not wearing the ARBITRATOR_HAT. modifier onlyArbitrator() { if (!HATS().isWearerOfHat(msg.sender, ARBITRATOR_HAT())) revert AgreementEligibility_NotArbitrator(); _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; // import { console2 } from "forge-std/Test.sol"; // remove before deploy import { HatsModule } from "./HatsModule.sol"; import { IHatsEligibility } from "hats-protocol/Interfaces/IHatsEligibility.sol"; abstract contract HatsEligibilityModule is HatsModule, IHatsEligibility { /** * @dev Contracts that inherit from HatsEligibilityModule must call the HatsModule constructor: * `HatsModule(_version)`. */ /*////////////////////////////////////////////////////////////// HATS ELIGIBILITY FUNCTION //////////////////////////////////////////////////////////////*/ /// @inheritdoc IHatsEligibility function getWearerStatus(address _wearer, uint256 _hatId) public view virtual override returns (bool eligible, bool standing) { } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; // import { console2 } from "forge-std/Test.sol"; // remove before deploy import { HatsModule } from "hats-module/HatsModule.sol"; import { HatsModuleFactory } from "hats-module/HatsModuleFactory.sol"; /*////////////////////////////////////////////////////////////// CUSTOM ERRORS //////////////////////////////////////////////////////////////*/ /// @notice Thrown if the given array parameters are not of equal length error MultiClaimsHatter_ArrayLengthMismatch(); /// @notice Thrown if the calling account is not an admin of the hat error MultiClaimsHatter_NotAdminOfHat(address account, uint256 hatId); /// @notice Thrown if the account is not explicitly eligible for the hat error MultiClaimsHatter_NotExplicitlyEligible(address account, uint256 hatId); /// @notice Thrown if the hat is not claimable error MultiClaimsHatter_HatNotClaimable(uint256 hatId); /// @notice Thrown if the hat is not claimable on behalf of accounts error MultiClaimsHatter_HatNotClaimableFor(uint256 hatId); contract MultiClaimsHatter is HatsModule { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ /// @notice Emitted when the claimability of multiple hats was edited event HatsClaimabilitySet(uint256[] hatIds, ClaimType[] claimTypes); /// @notice Emitted when the calimability of a hat was edited event HatClaimabilitySet(uint256 hatId, ClaimType claimType); /*////////////////////////////////////////////////////////////// DATA MODELS //////////////////////////////////////////////////////////////*/ /** * @notice Hats claimability types. * @param NotClaimable The hat is not claimable * @param Claimable The hat is only claimable by the account that will be the hat's wearer * @param ClaimableFor The hat is claimable on behalf of accounts (and also by the wearer) */ enum ClaimType { NotClaimable, Claimable, ClaimableFor } /*////////////////////////////////////////////////////////////// CONSTANTS //////////////////////////////////////////////////////////////*/ /** * This contract is a clone with immutable args, which means that it is deployed with a set of * immutable storage variables (ie constants). Accessing these constants is cheaper than accessing * regular storage variables (such as those set on initialization of a typical EIP-1167 clone), * but requires a slightly different approach since they are read from calldata instead of storage. * * Below is a table of constants and their location. * * For more, see here: https://github.com/Saw-mon-and-Natalie/clones-with-immutable-args * * ----------------------------------------------------------------------+ * CLONE IMMUTABLE "STORAGE" | * ----------------------------------------------------------------------| * Offset | Constant | Type | Length | Source | * ----------------------------------------------------------------------| * 0 | IMPLEMENTATION | address | 20 | HatsModule | * 20 | HATS | address | 20 | HatsModule | * 40 | hatId | uint256 | 32 | HatsModule | * ----------------------------------------------------------------------+ */ /*////////////////////////////////////////////////////////////// MUTABLE STATE //////////////////////////////////////////////////////////////*/ /// @notice Maps between hats and their claimability type mapping(uint256 hatId => ClaimType claimType) public hatToClaimType; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ /// @notice Deploy the implementation contract and set its version /// @dev This is only used to deploy the implementation contract, and should not be used to deploy clones constructor(string memory _version) HatsModule(_version) { } /*////////////////////////////////////////////////////////////// INITIALIZOR //////////////////////////////////////////////////////////////*/ /// @inheritdoc HatsModule function _setUp(bytes calldata _initData) internal override { if (_initData.length == 0) return; // decode init data (uint256[] memory _hatIds, ClaimType[] memory _claimTypes) = abi.decode(_initData, (uint256[], ClaimType[])); _setHatsClaimabilityMemory(_hatIds, _claimTypes); } /*////////////////////////////////////////////////////////////// ADMIN FUNCTIONS //////////////////////////////////////////////////////////////*/ /** * @notice Change the claimability status of a hat. The caller should be an admin of the hat. * @param _hatId The ID of the hat to set claimability for * @param _claimType New claimability type for the hat */ function setHatClaimability(uint256 _hatId, ClaimType _claimType) public { if (!HATS().isAdminOfHat(msg.sender, _hatId)) revert MultiClaimsHatter_NotAdminOfHat(msg.sender, _hatId); hatToClaimType[_hatId] = _claimType; emit HatClaimabilitySet(_hatId, _claimType); } /** * @notice Change the claimability status of multiple hats. The caller should be an admin of the hats. * @param _hatIds The ID of the hat to set claimability for * @param _claimTypes New claimability types for each hat */ function setHatsClaimability(uint256[] calldata _hatIds, ClaimType[] calldata _claimTypes) public { uint256 length = _hatIds.length; if (_claimTypes.length != length) { revert MultiClaimsHatter_ArrayLengthMismatch(); } uint256 hatId; for (uint256 i; i < length;) { hatId = _hatIds[i]; if (!HATS().isAdminOfHat(msg.sender, hatId)) revert MultiClaimsHatter_NotAdminOfHat(msg.sender, hatId); hatToClaimType[hatId] = _claimTypes[i]; unchecked { ++i; } } emit HatsClaimabilitySet(_hatIds, _claimTypes); } /** * @notice Wrapper around a HatsModuleFactory. Deploys a new HatsModule instance and sets a hat's claimability type. * @param _factory The HatsModuleFactory instance that will deploy the module * @param _implementation The address of the implementation contract of which to deploy a clone * @param _moduleHatId The hat for which to deploy a HatsModule. * @param _otherImmutableArgs Other immutable args to pass to the clone as immutable storage. * @param _initData The encoded data to pass to the `setUp` function of the new HatsModule instance. Leave empty if no * @param _hatId The ID of the hat to set claimability for * @param _claimType New claimability type for the hat * @return _instance The address of the deployed HatsModule instance */ function setHatClaimabilityAndCreateModule( HatsModuleFactory _factory, address _implementation, uint256 _moduleHatId, bytes calldata _otherImmutableArgs, bytes calldata _initData, uint256 _hatId, ClaimType _claimType ) public returns (address _instance) { if (!HATS().isAdminOfHat(msg.sender, _hatId)) revert MultiClaimsHatter_NotAdminOfHat(msg.sender, _hatId); hatToClaimType[_hatId] = _claimType; _instance = _factory.createHatsModule(_implementation, _moduleHatId, _otherImmutableArgs, _initData); emit HatClaimabilitySet(_hatId, _claimType); } /** * @notice Wrapper around a HatsModuleFactory. Deploys new HatsModule instances and sets the claimability type of * multiple hats. * @param _factory The HatsModuleFactory instance that will deploy the modules * @param _implementations The addresses of the implementation contracts of which to deploy a clone * @param _moduleHatIds The hats for which to deploy a HatsModule. * @param _otherImmutableArgsArray Other immutable args to pass to the clones as immutable storage. * @param _initDataArray The encoded data to pass to the `setUp` functions of the new HatsModule instances. Leave * @param _hatIds The IDs of the hats to set claimability for * @param _claimTypes New claimability types for each hat * @return success True if all modules were successfully created and the claimability types were set */ function setHatsClaimabilityAndCreateModules( HatsModuleFactory _factory, address[] calldata _implementations, uint256[] calldata _moduleHatIds, bytes[] calldata _otherImmutableArgsArray, bytes[] calldata _initDataArray, uint256[] memory _hatIds, ClaimType[] memory _claimTypes ) public returns (bool success) { uint256 length = _hatIds.length; if (_claimTypes.length != length) { revert MultiClaimsHatter_ArrayLengthMismatch(); } uint256 hatId; for (uint256 i; i < length;) { hatId = _hatIds[i]; if (!HATS().isAdminOfHat(msg.sender, hatId)) revert MultiClaimsHatter_NotAdminOfHat(msg.sender, hatId); hatToClaimType[hatId] = _claimTypes[i]; unchecked { ++i; } } success = _factory.batchCreateHatsModule(_implementations, _moduleHatIds, _otherImmutableArgsArray, _initDataArray); emit HatsClaimabilitySet(_hatIds, _claimTypes); } /*////////////////////////////////////////////////////////////// CLAIMING FUNCTIONS //////////////////////////////////////////////////////////////*/ /** * @notice Claim a hat. * @dev This contract must be wearing an admin hat of the hat to claim or else it will revert * @param _hatId The ID of the hat to claim */ function claimHat(uint256 _hatId) public { if (hatToClaimType[_hatId] == ClaimType.NotClaimable) { revert MultiClaimsHatter_HatNotClaimable(_hatId); } _mint(_hatId, msg.sender); } /** * @notice Claim multiple hats. * @dev This contract must be wearing an admin hat of the hats to claim or else it will revert * @param _hatIds The IDs of the hats to claim */ function claimHats(uint256[] calldata _hatIds) public { uint256 hatId; for (uint256 i; i < _hatIds.length;) { hatId = _hatIds[i]; if (hatToClaimType[hatId] == ClaimType.NotClaimable) { revert MultiClaimsHatter_HatNotClaimable(hatId); } _mint(hatId, msg.sender); unchecked { ++i; } } } /** * @notice Claim a hat on behalf of an account * @dev This contract must be wearing an admin hat of the hat to claim or else it will revert * @param _hatId The ID of the hat to claim for * @param _account The account for which to claim */ function claimHatFor(uint256 _hatId, address _account) public { if (hatToClaimType[_hatId] != ClaimType.ClaimableFor) { revert MultiClaimsHatter_HatNotClaimableFor(_hatId); } _mint(_hatId, _account); } /** * @notice Claim multiple hats on behalf of accounts * @dev This contract must be wearing an admin hat of the hats to claim or else it will revert * @param _hatIds The IDs of the hats to claim for * @param _accounts The accounts for which to claim */ function claimHatsFor(uint256[] calldata _hatIds, address[] calldata _accounts) public { if (_hatIds.length != _accounts.length) { revert MultiClaimsHatter_ArrayLengthMismatch(); } uint256 hatId; for (uint256 i; i < _hatIds.length;) { hatId = _hatIds[i]; if (hatToClaimType[hatId] != ClaimType.ClaimableFor) { revert MultiClaimsHatter_HatNotClaimableFor(hatId); } _mint(hatId, _accounts[i]); unchecked { ++i; } } } /*////////////////////////////////////////////////////////////// VIEW FUNCTIONS //////////////////////////////////////////////////////////////*/ /** * @notice Checks if a hat is claimable on behalf of an account * @param _account The account to claim for * @param _hatId The hat to claim */ function canClaimForAccount(address _account, uint256 _hatId) public view returns (bool) { return (isClaimableFor(_hatId) && _isExplicitlyEligible(_hatId, _account)); } /** * @notice Checks if an account can claim a hat. * @param _account The claiming account * @param _hatId The hat to claim */ function accountCanClaim(address _account, uint256 _hatId) public view returns (bool) { return (isClaimableBy(_hatId) && _isExplicitlyEligible(_hatId, _account)); } /** * @notice Checks if a hat is claimable * @param _hatId The ID of the hat */ function isClaimableBy(uint256 _hatId) public view returns (bool) { return (hatExists(_hatId) && wearsAdmin(_hatId) && hatToClaimType[_hatId] > ClaimType.NotClaimable); } /** * @notice Checks if a hat is claimable on behalf of accounts * @param _hatId The ID of the hat */ function isClaimableFor(uint256 _hatId) public view returns (bool) { return (hatExists(_hatId) && wearsAdmin(_hatId) && hatToClaimType[_hatId] == ClaimType.ClaimableFor); } /** * @notice Check if this contract is an admin of a hat. * @param _hatId The ID of the hat */ function wearsAdmin(uint256 _hatId) public view returns (bool) { return HATS().isAdminOfHat(address(this), _hatId); } /// @notice Checks if a hat exists function hatExists(uint256 _hatId) public view returns (bool) { return HATS().getHatMaxSupply(_hatId) > 0; } /*////////////////////////////////////////////////////////////// INTERNAL FUNCTIONS //////////////////////////////////////////////////////////////*/ function _mint(uint256 _hatId, address _account) internal { // revert if _wearer is not explicitly eligible if (!_isExplicitlyEligible(_hatId, _account)) revert MultiClaimsHatter_NotExplicitlyEligible(_account, _hatId); // mint the hat to _wearer if eligible. This contract can mint as long as its the hat's admin. HATS().mintHat(_hatId, _account); } function _isExplicitlyEligible(uint256 _hatId, address _account) internal view returns (bool eligible) { // get the hat's eligibility module address address eligibility = HATS().getHatEligibilityModule(_hatId); // get _wearer's eligibility status from the eligibility module bool standing; (bool success, bytes memory returndata) = eligibility.staticcall(abi.encodeWithSignature("getWearerStatus(address,uint256)", _account, _hatId)); /* * if function call succeeds with data of length == 64, then we know the contract exists * and has the getWearerStatus function (which returns two words). * But — since function selectors don't include return types — we still can't assume that the return data is two booleans, * so we treat it as a uint so it will always safely decode without throwing. */ if (success && returndata.length == 64) { // check the returndata manually (uint256 firstWord, uint256 secondWord) = abi.decode(returndata, (uint256, uint256)); // returndata is valid if (firstWord < 2 && secondWord < 2) { standing = (secondWord == 1) ? true : false; // never eligible if in bad standing eligible = (standing && firstWord == 1) ? true : false; } // returndata is invalid else { // false since _wearer is not explicitly eligible eligible = false; } } else { // false since _wearer is not explicitly eligible eligible = false; } } function _setHatsClaimabilityMemory(uint256[] memory _hatIds, ClaimType[] memory _claimTypes) internal { uint256 length = _hatIds.length; if (_claimTypes.length != length) { revert MultiClaimsHatter_ArrayLengthMismatch(); } uint256 hatId; for (uint256 i; i < length;) { hatId = _hatIds[i]; hatToClaimType[hatId] = _claimTypes[i]; unchecked { ++i; } } emit HatsClaimabilitySet(_hatIds, _claimTypes); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; // import { console2 } from "forge-std/Test.sol"; // remove before deploy import { IHats } from "hats-protocol/Interfaces/IHats.sol"; import { IHatsModule } from "./interfaces/IHatsModule.sol"; import { Clone } from "solady/utils/Clone.sol"; import { Initializable } from "@openzeppelin-contracts/contracts/proxy/utils/Initializable.sol"; contract HatsModule is IHatsModule, Clone, Initializable { /*////////////////////////////////////////////////////////////// PUBLIC CONSTANTS //////////////////////////////////////////////////////////////*/ /** * This contract is a clone with immutable args, which means that it is deployed with a set of * immutable storage variables (ie constants). Accessing these constants is cheaper than accessing * regular storage variables (such as those set on initialization of a typical EIP-1167 clone), * but requires a slightly different approach since they are read from calldata instead of storage. * * Below is a table of constants and their location. * * For more, see here: https://github.com/Saw-mon-and-Natalie/clones-with-immutable-args * * --------------------------------------------------------------------+ * CLONE IMMUTABLE "STORAGE" | * --------------------------------------------------------------------| * Offset | Constant | Type | Length | | * --------------------------------------------------------------------| * 0 | IMPLEMENTATION | address | 20 | | * 20 | HATS | address | 20 | | * 40 | hatId | uint256 | 32 | | * 72+ | [other args] | [type] | [len] | | * --------------------------------------------------------------------+ */ /// @inheritdoc IHatsModule function IMPLEMENTATION() public pure returns (address) { return _getArgAddress(0); } /// @inheritdoc IHatsModule function HATS() public pure returns (IHats) { return IHats(_getArgAddress(20)); } /// @inheritdoc IHatsModule function hatId() public pure returns (uint256) { return _getArgUint256(40); } /// @inheritdoc IHatsModule string public version_; /// @inheritdoc IHatsModule function version() public view returns (string memory) { return HatsModule(IMPLEMENTATION()).version_(); } /*////////////////////////////////////////////////////////////// INITIALIZER //////////////////////////////////////////////////////////////*/ /// @inheritdoc IHatsModule function setUp(bytes calldata _initData) public initializer { _setUp(_initData); } /// @dev Override this function to set initial operational values for module instances function _setUp(bytes calldata _initData) internal virtual { } /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ /// @notice Deploy the implementation contract and set its version /// @dev This is only used to deploy the implementation contract, and should not be used to deploy clones constructor(string memory _version) { version_ = _version; // prevent the implementation contract from being initialized _disableInitializers(); } }
// SPDX-License-Identifier: AGPL-3.0 // Copyright (C) 2023 Haberdasher Labs // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <https://www.gnu.org/licenses/>. pragma solidity >=0.8.13; interface IHatsEligibility { /// @notice Returns the status of a wearer for a given hat /// @dev If standing is false, eligibility MUST also be false /// @param _wearer The address of the current or prospective Hat wearer /// @param _hatId The id of the hat in question /// @return eligible Whether the _wearer is eligible to wear the hat /// @return standing Whether the _wearer is in goog standing function getWearerStatus(address _wearer, uint256 _hatId) external view returns (bool eligible, bool standing); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; // import { console2 } from "forge-std/Test.sol"; // remove before deploy import { HatsModule } from "./HatsModule.sol"; import { LibClone } from "solady/utils/LibClone.sol"; import { IHats } from "hats-protocol/Interfaces/IHats.sol"; contract HatsModuleFactory { /*////////////////////////////////////////////////////////////// CUSTOM ERRORS //////////////////////////////////////////////////////////////*/ /** * @notice Emitted if attempting to deploy a clone of `implementation` for a given `hatId` and `otherImmutableArgs` * that already has a HatsModule deployment */ error HatsModuleFactory_ModuleAlreadyDeployed(address implementation, uint256 hatId, bytes otherImmutableArgs); /// @notice Emitted when array arguments to a batch function have mismatching lengths error BatchArrayLengthMismatch(); /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ /// @notice Emitted when a HatsModule for `hatId` and `otherImmutableArgs` is deployed to address `instance` event HatsModuleFactory_ModuleDeployed( address implementation, address instance, uint256 hatId, bytes otherImmutableArgs, bytes initData ); /*////////////////////////////////////////////////////////////// CONSTANTS //////////////////////////////////////////////////////////////*/ /// @notice The address of the Hats Protocol IHats public immutable HATS; /// @notice The version of this HatsModuleFactory string public version; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ /** * @param _hats The address of Hats Protocol * @param _version The label for this version of HatsModule */ constructor(IHats _hats, string memory _version) { HATS = _hats; version = _version; } /*////////////////////////////////////////////////////////////// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////*/ /** * @notice Deploys a new HatsModule instance for a given `_hatId` to a deterministic address, if not * already deployed, and sets up the new instance with initial operational values. * @dev Will revert *after* the instance is deployed if their initial values are invalid. * @param _implementation The address of the implementation contract of which to deploy a clone * @param _hatId The hat for which to deploy a HatsModule. * @param _otherImmutableArgs Other immutable args to pass to the clone as immutable storage. * @param _initData The encoded data to pass to the `setUp` function of the new HatsModule instance. Leave empty if no * {setUp} is required. * @return _instance The address of the deployed HatsModule instance */ function createHatsModule( address _implementation, uint256 _hatId, bytes calldata _otherImmutableArgs, bytes calldata _initData ) public returns (address _instance) { // calculate unique params that will be used to check for existing deployments and deploy the clone if none exists bytes memory args = _encodeArgs(_implementation, _hatId, _otherImmutableArgs); bytes32 _salt = _calculateSalt(args); // check if a HatsModule has already been deployed for these parameters if (_getHatsModuleAddress(_implementation, args, _salt).code.length > 0) { revert HatsModuleFactory_ModuleAlreadyDeployed(_implementation, _hatId, _otherImmutableArgs); } // deploy the clone to a deterministic address _instance = LibClone.cloneDeterministic(_implementation, args, _salt); // set up and initialize the module instance; empty _initData is allowed HatsModule(_instance).setUp(_initData); // log the deployment emit HatsModuleFactory_ModuleDeployed(_implementation, address(_instance), _hatId, _otherImmutableArgs, _initData); } /** * @notice Deploys new HatsModule instances in batch. * Every module is created for a given `_hatId` to a deterministic address, if not already deployed. * Sets up each new instance with initial operational values. * @dev Will revert *after* an instance is deployed if its initial values are invalid. * @param _implementations The addresses of the implementation contracts of which to deploy a clone * @param _hatIds The hats for which to deploy a HatsModule. * @param _otherImmutableArgsArray Other immutable args to pass to the clones as immutable storage. * @param _initDataArray The encoded data to pass to the `setUp` functions of the new HatsModule instances. Leave * empty if no {setUp} is required. * @return success True if all modules were successfully created */ function batchCreateHatsModule( address[] calldata _implementations, uint256[] calldata _hatIds, bytes[] calldata _otherImmutableArgsArray, bytes[] calldata _initDataArray ) public returns (bool success) { uint256 length = _implementations.length; { bool sameLengths = (length == _hatIds.length && length == _otherImmutableArgsArray.length && length == _initDataArray.length); if (!sameLengths) revert BatchArrayLengthMismatch(); } for (uint256 i = 0; i < length;) { createHatsModule(_implementations[i], _hatIds[i], _otherImmutableArgsArray[i], _initDataArray[i]); unchecked { ++i; } } success = true; } /** * @notice Predicts the address of a HatsModule instance for a given hat * @param _hatId The hat for which to predict the HatsModule instance address * @return The predicted address of the deployed instance */ function getHatsModuleAddress(address _implementation, uint256 _hatId, bytes calldata _otherImmutableArgs) public view returns (address) { // prepare the unique inputs bytes memory args = _encodeArgs(_implementation, _hatId, _otherImmutableArgs); bytes32 _salt = _calculateSalt(args); // predict the address return _getHatsModuleAddress(_implementation, args, _salt); } /** * @notice Checks if a HatsModule instance has already been deployed for a given hat * @param _hatId The hat for which to check for an existing instance * @param _otherImmutableArgs Other immutable args to pass to the clone as immutable storage. * @return True if an instance has already been deployed for the given hat */ function deployed(address _implementation, uint256 _hatId, bytes calldata _otherImmutableArgs) public view returns (bool) { // check for contract code at the predicted address return getHatsModuleAddress(_implementation, _hatId, _otherImmutableArgs).code.length > 0; } /*////////////////////////////////////////////////////////////// INTERNAL FUNCTIONS //////////////////////////////////////////////////////////////*/ /** * @notice Predicts the address of a HatsModule contract given the encoded arguments and salt * @param _args The encoded arguments to pass to the clone as immutable storage * @param _salt The salt to use when deploying the clone * @return The predicted address of the deployed HatsModule */ function _getHatsModuleAddress(address _implementation, bytes memory _args, bytes32 _salt) internal view returns (address) { return LibClone.predictDeterministicAddress(_implementation, _args, _salt, address(this)); } /** * @notice Encodes the arguments to pass to the clone as immutable storage. The arguments are: * - The address of the implementation * - The address of the Hats Protocol * - The`_hatId` * - Any `_otherImmutableArgs` * @return The encoded arguments */ function _encodeArgs(address _implementation, uint256 _hatId, bytes calldata _otherImmutableArgs) internal view returns (bytes memory) { return abi.encodePacked(_implementation, HATS, _hatId, _otherImmutableArgs); } /** * @notice Calculates the salt to use when deploying the clone. The (packed) inputs are: * - The address of the this contract, `FACTORY` (passed as part of `_args`) * - The address of the Hats Protocol, `HATS` (passed as part of `_args`) * - The `_hatId` (passed as part of `_args`) * - Any `_otherImmutableArgs` (passed as part of `_args`) * - The chain ID of the current network, to avoid confusion across networks since the same hat trees * on different networks may have different wearers/admins * @param _args The encoded arguments to pass to the clone as immutable storage * @return The salt to use when deploying the clone */ function _calculateSalt(bytes memory _args) internal view returns (bytes32) { return keccak256(abi.encodePacked(_args, block.chainid)); } }
// SPDX-License-Identifier: AGPL-3.0 // Copyright (C) 2023 Haberdasher Labs // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <https://www.gnu.org/licenses/>. pragma solidity >=0.8.13; import "./IHatsIdUtilities.sol"; import "./HatsErrors.sol"; import "./HatsEvents.sol"; interface IHats is IHatsIdUtilities, HatsErrors, HatsEvents { function mintTopHat(address _target, string memory _details, string memory _imageURI) external returns (uint256 topHatId); function createHat( uint256 _admin, string calldata _details, uint32 _maxSupply, address _eligibility, address _toggle, bool _mutable, string calldata _imageURI ) external returns (uint256 newHatId); function batchCreateHats( uint256[] calldata _admins, string[] calldata _details, uint32[] calldata _maxSupplies, address[] memory _eligibilityModules, address[] memory _toggleModules, bool[] calldata _mutables, string[] calldata _imageURIs ) external returns (bool success); function getNextId(uint256 _admin) external view returns (uint256 nextId); function mintHat(uint256 _hatId, address _wearer) external returns (bool success); function batchMintHats(uint256[] calldata _hatIds, address[] calldata _wearers) external returns (bool success); function setHatStatus(uint256 _hatId, bool _newStatus) external returns (bool toggled); function checkHatStatus(uint256 _hatId) external returns (bool toggled); function setHatWearerStatus(uint256 _hatId, address _wearer, bool _eligible, bool _standing) external returns (bool updated); function checkHatWearerStatus(uint256 _hatId, address _wearer) external returns (bool updated); function renounceHat(uint256 _hatId) external; function transferHat(uint256 _hatId, address _from, address _to) external; /*////////////////////////////////////////////////////////////// HATS ADMIN FUNCTIONS //////////////////////////////////////////////////////////////*/ function makeHatImmutable(uint256 _hatId) external; function changeHatDetails(uint256 _hatId, string memory _newDetails) external; function changeHatEligibility(uint256 _hatId, address _newEligibility) external; function changeHatToggle(uint256 _hatId, address _newToggle) external; function changeHatImageURI(uint256 _hatId, string memory _newImageURI) external; function changeHatMaxSupply(uint256 _hatId, uint32 _newMaxSupply) external; function requestLinkTopHatToTree(uint32 _topHatId, uint256 _newAdminHat) external; function approveLinkTopHatToTree( uint32 _topHatId, uint256 _newAdminHat, address _eligibility, address _toggle, string calldata _details, string calldata _imageURI ) external; function unlinkTopHatFromTree(uint32 _topHatId, address _wearer) external; function relinkTopHatWithinTree( uint32 _topHatDomain, uint256 _newAdminHat, address _eligibility, address _toggle, string calldata _details, string calldata _imageURI ) external; /*////////////////////////////////////////////////////////////// VIEW FUNCTIONS //////////////////////////////////////////////////////////////*/ function viewHat(uint256 _hatId) external view returns ( string memory details, uint32 maxSupply, uint32 supply, address eligibility, address toggle, string memory imageURI, uint16 lastHatId, bool mutable_, bool active ); function isWearerOfHat(address _user, uint256 _hatId) external view returns (bool isWearer); function isAdminOfHat(address _user, uint256 _hatId) external view returns (bool isAdmin); function isInGoodStanding(address _wearer, uint256 _hatId) external view returns (bool standing); function isEligible(address _wearer, uint256 _hatId) external view returns (bool eligible); function getHatEligibilityModule(uint256 _hatId) external view returns (address eligibility); function getHatToggleModule(uint256 _hatId) external view returns (address toggle); function getHatMaxSupply(uint256 _hatId) external view returns (uint32 maxSupply); function hatSupply(uint256 _hatId) external view returns (uint32 supply); function getImageURIForHat(uint256 _hatId) external view returns (string memory _uri); function balanceOf(address wearer, uint256 hatId) external view returns (uint256 balance); function balanceOfBatch(address[] calldata _wearers, uint256[] calldata _hatIds) external view returns (uint256[] memory); function uri(uint256 id) external view returns (string memory _uri); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import { IHats } from "hats-protocol/Interfaces/IHats.sol"; interface IHatsModule { /// @notice Hats Protocol address function HATS() external pure returns (IHats); /// @notice The address of the implementation contract of which this instance is a clone function IMPLEMENTATION() external pure returns (address); /// @notice The hat id for which this HatsModule instance has been deployed function hatId() external pure returns (uint256); /** * @notice Sets up this instance with initial operational values (`_initData`) * @dev This function can only be called once, on initialization * @param _initData Data to set up initial operational values for this instance */ function setUp(bytes memory _initData) external; /// @notice The version of this HatsModule /// @dev Used only for the implementation contract; for clones, use {version} function version_() external view returns (string memory); /// @notice The version of this HatsModule function version() external view returns (string memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Class with helper read functions for clone with immutable args. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Clone.sol) /// @author Adapted from clones with immutable args by zefram.eth, Saw-mon & Natalie /// (https://github.com/Saw-mon-and-Natalie/clones-with-immutable-args) abstract contract Clone { /// @dev Reads all of the immutable args. function _getArgBytes() internal pure returns (bytes memory arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := mload(0x40) let length := sub(calldatasize(), add(2, offset)) // 2 bytes are used for the length. mstore(arg, length) // Store the length. calldatacopy(add(arg, 0x20), offset, length) let o := add(add(arg, 0x20), length) mstore(o, 0) // Zeroize the slot after the bytes. mstore(0x40, add(o, 0x20)) // Allocate the memory. } } /// @dev Reads an immutable arg with type bytes. function _getArgBytes(uint256 argOffset, uint256 length) internal pure returns (bytes memory arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := mload(0x40) mstore(arg, length) // Store the length. calldatacopy(add(arg, 0x20), add(offset, argOffset), length) let o := add(add(arg, 0x20), length) mstore(o, 0) // Zeroize the slot after the bytes. mstore(0x40, add(o, 0x20)) // Allocate the memory. } } /// @dev Reads an immutable arg with type address. function _getArgAddress(uint256 argOffset) internal pure returns (address arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(96, calldataload(add(offset, argOffset))) } } /// @dev Reads a uint256 array stored in the immutable args. function _getArgUint256Array(uint256 argOffset, uint256 length) internal pure returns (uint256[] memory arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := mload(0x40) mstore(arg, length) // Store the length. calldatacopy(add(arg, 0x20), add(offset, argOffset), shl(5, length)) mstore(0x40, add(add(arg, 0x20), shl(5, length))) // Allocate the memory. } } /// @dev Reads a bytes32 array stored in the immutable args. function _getArgBytes32Array(uint256 argOffset, uint256 length) internal pure returns (bytes32[] memory arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := mload(0x40) mstore(arg, length) // Store the length. calldatacopy(add(arg, 0x20), add(offset, argOffset), shl(5, length)) mstore(0x40, add(add(arg, 0x20), shl(5, length))) // Allocate the memory. } } /// @dev Reads an immutable arg with type bytes32. function _getArgBytes32(uint256 argOffset) internal pure returns (bytes32 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := calldataload(add(offset, argOffset)) } } /// @dev Reads an immutable arg with type uint256. function _getArgUint256(uint256 argOffset) internal pure returns (uint256 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := calldataload(add(offset, argOffset)) } } /// @dev Reads an immutable arg with type uint248. function _getArgUint248(uint256 argOffset) internal pure returns (uint248 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(8, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint240. function _getArgUint240(uint256 argOffset) internal pure returns (uint240 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(16, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint232. function _getArgUint232(uint256 argOffset) internal pure returns (uint232 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(24, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint224. function _getArgUint224(uint256 argOffset) internal pure returns (uint224 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(0x20, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint216. function _getArgUint216(uint256 argOffset) internal pure returns (uint216 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(40, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint208. function _getArgUint208(uint256 argOffset) internal pure returns (uint208 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(48, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint200. function _getArgUint200(uint256 argOffset) internal pure returns (uint200 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(56, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint192. function _getArgUint192(uint256 argOffset) internal pure returns (uint192 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(64, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint184. function _getArgUint184(uint256 argOffset) internal pure returns (uint184 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(72, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint176. function _getArgUint176(uint256 argOffset) internal pure returns (uint176 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(80, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint168. function _getArgUint168(uint256 argOffset) internal pure returns (uint168 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(88, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint160. function _getArgUint160(uint256 argOffset) internal pure returns (uint160 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(96, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint152. function _getArgUint152(uint256 argOffset) internal pure returns (uint152 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(104, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint144. function _getArgUint144(uint256 argOffset) internal pure returns (uint144 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(112, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint136. function _getArgUint136(uint256 argOffset) internal pure returns (uint136 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(120, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint128. function _getArgUint128(uint256 argOffset) internal pure returns (uint128 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(128, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint120. function _getArgUint120(uint256 argOffset) internal pure returns (uint120 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(136, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint112. function _getArgUint112(uint256 argOffset) internal pure returns (uint112 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(144, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint104. function _getArgUint104(uint256 argOffset) internal pure returns (uint104 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(152, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint96. function _getArgUint96(uint256 argOffset) internal pure returns (uint96 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(160, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint88. function _getArgUint88(uint256 argOffset) internal pure returns (uint88 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(168, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint80. function _getArgUint80(uint256 argOffset) internal pure returns (uint80 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(176, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint72. function _getArgUint72(uint256 argOffset) internal pure returns (uint72 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(184, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint64. function _getArgUint64(uint256 argOffset) internal pure returns (uint64 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(192, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint56. function _getArgUint56(uint256 argOffset) internal pure returns (uint56 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(200, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint48. function _getArgUint48(uint256 argOffset) internal pure returns (uint48 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(208, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint40. function _getArgUint40(uint256 argOffset) internal pure returns (uint40 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(216, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint32. function _getArgUint32(uint256 argOffset) internal pure returns (uint32 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(224, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint24. function _getArgUint24(uint256 argOffset) internal pure returns (uint24 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(232, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint16. function _getArgUint16(uint256 argOffset) internal pure returns (uint16 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(240, calldataload(add(offset, argOffset))) } } /// @dev Reads an immutable arg with type uint8. function _getArgUint8(uint256 argOffset) internal pure returns (uint8 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(248, calldataload(add(offset, argOffset))) } } /// @return offset The offset of the packed immutable args in calldata. function _getImmutableArgsOffset() internal pure returns (uint256 offset) { /// @solidity memory-safe-assembly assembly { offset := sub(calldatasize(), shr(240, calldataload(sub(calldatasize(), 2)))) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/Address.sol"; /** * @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 Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 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 functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _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 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _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() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @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 { require(!_initializing, "Initializable: contract is initializing"); if (_initialized != type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Minimal proxy library. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibClone.sol) /// @author Minimal proxy by 0age (https://github.com/0age) /// @author Clones with immutable args by wighawag, zefram.eth, Saw-mon & Natalie /// (https://github.com/Saw-mon-and-Natalie/clones-with-immutable-args) /// /// @dev Minimal proxy: /// Although the sw0nt pattern saves 5 gas over the erc-1167 pattern during runtime, /// it is not supported out-of-the-box on Etherscan. Hence, we choose to use the 0age pattern, /// which saves 4 gas over the erc-1167 pattern during runtime, and has the smallest bytecode. /// /// @dev Minimal proxy (PUSH0 variant): /// This is a new minimal proxy that uses the PUSH0 opcode introduced during Shanghai. /// It is optimized first for minimal runtime gas, then for minimal bytecode. /// The PUSH0 clone functions are intentionally postfixed with a jarring "_PUSH0" as /// many EVM chains may not support the PUSH0 opcode in the early months after Shanghai. /// Please use with caution. /// /// @dev Clones with immutable args (CWIA): /// The implementation of CWIA here implements a `receive()` method that emits the /// `ReceiveETH(uint256)` event. This skips the `DELEGATECALL` when there is no calldata, /// enabling us to accept hard gas-capped `sends` & `transfers` for maximum backwards /// composability. The minimal proxy implementation does not offer this feature. library LibClone { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Unable to deploy the clone. error DeploymentFailed(); /// @dev The salt must start with either the zero address or the caller. error SaltDoesNotStartWithCaller(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MINIMAL PROXY OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Deploys a clone of `implementation`. function clone(address implementation) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { /** * --------------------------------------------------------------------------+ * CREATION (9 bytes) | * --------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * --------------------------------------------------------------------------| * 60 runSize | PUSH1 runSize | r | | * 3d | RETURNDATASIZE | 0 r | | * 81 | DUP2 | r 0 r | | * 60 offset | PUSH1 offset | o r 0 r | | * 3d | RETURNDATASIZE | 0 o r 0 r | | * 39 | CODECOPY | 0 r | [0..runSize): runtime code | * f3 | RETURN | | [0..runSize): runtime code | * --------------------------------------------------------------------------| * RUNTIME (44 bytes) | * --------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * --------------------------------------------------------------------------| * | * ::: keep some values in stack ::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | 0 | | * 3d | RETURNDATASIZE | 0 0 | | * 3d | RETURNDATASIZE | 0 0 0 | | * 3d | RETURNDATASIZE | 0 0 0 0 | | * | * ::: copy calldata to memory ::::::::::::::::::::::::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds 0 0 0 0 | | * 3d | RETURNDATASIZE | 0 cds 0 0 0 0 | | * 3d | RETURNDATASIZE | 0 0 cds 0 0 0 0 | | * 37 | CALLDATACOPY | 0 0 0 0 | [0..cds): calldata | * | * ::: delegate call to the implementation contract :::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds 0 0 0 0 | [0..cds): calldata | * 3d | RETURNDATASIZE | 0 cds 0 0 0 0 | [0..cds): calldata | * 73 addr | PUSH20 addr | addr 0 cds 0 0 0 0 | [0..cds): calldata | * 5a | GAS | gas addr 0 cds 0 0 0 0 | [0..cds): calldata | * f4 | DELEGATECALL | success 0 0 | [0..cds): calldata | * | * ::: copy return data to memory :::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | rds success 0 0 | [0..cds): calldata | * 3d | RETURNDATASIZE | rds rds success 0 0 | [0..cds): calldata | * 93 | SWAP4 | 0 rds success 0 rds | [0..cds): calldata | * 80 | DUP1 | 0 0 rds success 0 rds | [0..cds): calldata | * 3e | RETURNDATACOPY | success 0 rds | [0..rds): returndata | * | * 60 0x2a | PUSH1 0x2a | 0x2a success 0 rds | [0..rds): returndata | * 57 | JUMPI | 0 rds | [0..rds): returndata | * | * ::: revert :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * fd | REVERT | | [0..rds): returndata | * | * ::: return :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 5b | JUMPDEST | 0 rds | [0..rds): returndata | * f3 | RETURN | | [0..rds): returndata | * --------------------------------------------------------------------------+ */ mstore(0x21, 0x5af43d3d93803e602a57fd5bf3) mstore(0x14, implementation) mstore(0x00, 0x602c3d8160093d39f33d3d3d3d363d3d37363d73) instance := create(0, 0x0c, 0x35) // If `instance` is zero, revert. if iszero(instance) { // Store the function selector of `DeploymentFailed()`. mstore(0x00, 0x30116425) // Revert with (offset, size). revert(0x1c, 0x04) } // Restore the part of the free memory pointer that has been overwritten. mstore(0x21, 0) } } /// @dev Deploys a deterministic clone of `implementation` with `salt`. function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { mstore(0x21, 0x5af43d3d93803e602a57fd5bf3) mstore(0x14, implementation) mstore(0x00, 0x602c3d8160093d39f33d3d3d3d363d3d37363d73) instance := create2(0, 0x0c, 0x35, salt) // If `instance` is zero, revert. if iszero(instance) { // Store the function selector of `DeploymentFailed()`. mstore(0x00, 0x30116425) // Revert with (offset, size). revert(0x1c, 0x04) } // Restore the part of the free memory pointer that has been overwritten. mstore(0x21, 0) } } /// @dev Returns the initialization code hash of the clone of `implementation`. /// Used for mining vanity addresses with create2crunch. function initCodeHash(address implementation) internal pure returns (bytes32 hash) { /// @solidity memory-safe-assembly assembly { mstore(0x21, 0x5af43d3d93803e602a57fd5bf3) mstore(0x14, implementation) mstore(0x00, 0x602c3d8160093d39f33d3d3d3d363d3d37363d73) hash := keccak256(0x0c, 0x35) // Restore the part of the free memory pointer that has been overwritten. mstore(0x21, 0) } } /// @dev Returns the address of the deterministic clone of `implementation`, /// with `salt` by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddress(address implementation, bytes32 salt, address deployer) internal pure returns (address predicted) { bytes32 hash = initCodeHash(implementation); predicted = predictDeterministicAddress(hash, salt, deployer); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MINIMAL PROXY OPERATIONS (PUSH0 VARIANT) */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Deploys a PUSH0 clone of `implementation`. function clone_PUSH0(address implementation) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { /** * --------------------------------------------------------------------------+ * CREATION (9 bytes) | * --------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * --------------------------------------------------------------------------| * 60 runSize | PUSH1 runSize | r | | * 5f | PUSH0 | 0 r | | * 81 | DUP2 | r 0 r | | * 60 offset | PUSH1 offset | o r 0 r | | * 5f | PUSH0 | 0 o r 0 r | | * 39 | CODECOPY | 0 r | [0..runSize): runtime code | * f3 | RETURN | | [0..runSize): runtime code | * --------------------------------------------------------------------------| * RUNTIME (45 bytes) | * --------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * --------------------------------------------------------------------------| * | * ::: keep some values in stack ::::::::::::::::::::::::::::::::::::::::::: | * 5f | PUSH0 | 0 | | * 5f | PUSH0 | 0 0 | | * | * ::: copy calldata to memory ::::::::::::::::::::::::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds 0 0 | | * 5f | PUSH0 | 0 cds 0 0 | | * 5f | PUSH0 | 0 0 cds 0 0 | | * 37 | CALLDATACOPY | 0 0 | [0..cds): calldata | * | * ::: delegate call to the implementation contract :::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds 0 0 | [0..cds): calldata | * 5f | PUSH0 | 0 cds 0 0 | [0..cds): calldata | * 73 addr | PUSH20 addr | addr 0 cds 0 0 | [0..cds): calldata | * 5a | GAS | gas addr 0 cds 0 0 | [0..cds): calldata | * f4 | DELEGATECALL | success | [0..cds): calldata | * | * ::: copy return data to memory :::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | rds success | [0..cds): calldata | * 5f | PUSH0 | 0 rds success | [0..cds): calldata | * 5f | PUSH0 | 0 0 rds success | [0..cds): calldata | * 3e | RETURNDATACOPY | success | [0..rds): returndata | * | * 60 0x29 | PUSH1 0x29 | 0x29 success | [0..rds): returndata | * 57 | JUMPI | | [0..rds): returndata | * | * ::: revert :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | rds | [0..rds): returndata | * 5f | PUSH0 | 0 rds | [0..rds): returndata | * fd | REVERT | | [0..rds): returndata | * | * ::: return :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 5b | JUMPDEST | | [0..rds): returndata | * 3d | RETURNDATASIZE | rds | [0..rds): returndata | * 5f | PUSH0 | 0 rds | [0..rds): returndata | * f3 | RETURN | | [0..rds): returndata | * --------------------------------------------------------------------------+ */ mstore(0x24, 0x5af43d5f5f3e6029573d5ffd5b3d5ff3) // 16 mstore(0x14, implementation) // 20 mstore(0x00, 0x602d5f8160095f39f35f5f365f5f37365f73) // 9 + 9 instance := create(0, 0x0e, 0x36) // If `instance` is zero, revert. if iszero(instance) { // Store the function selector of `DeploymentFailed()`. mstore(0x00, 0x30116425) // Revert with (offset, size). revert(0x1c, 0x04) } // Restore the part of the free memory pointer that has been overwritten. mstore(0x24, 0) } } /// @dev Deploys a deterministic PUSH0 clone of `implementation` with `salt`. function cloneDeterministic_PUSH0(address implementation, bytes32 salt) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { mstore(0x24, 0x5af43d5f5f3e6029573d5ffd5b3d5ff3) // 16 mstore(0x14, implementation) // 20 mstore(0x00, 0x602d5f8160095f39f35f5f365f5f37365f73) // 9 + 9 instance := create2(0, 0x0e, 0x36, salt) // If `instance` is zero, revert. if iszero(instance) { // Store the function selector of `DeploymentFailed()`. mstore(0x00, 0x30116425) // Revert with (offset, size). revert(0x1c, 0x04) } // Restore the part of the free memory pointer that has been overwritten. mstore(0x24, 0) } } /// @dev Returns the initialization code hash of the PUSH0 clone of `implementation`. /// Used for mining vanity addresses with create2crunch. function initCodeHash_PUSH0(address implementation) internal pure returns (bytes32 hash) { /// @solidity memory-safe-assembly assembly { mstore(0x24, 0x5af43d5f5f3e6029573d5ffd5b3d5ff3) // 16 mstore(0x14, implementation) // 20 mstore(0x00, 0x602d5f8160095f39f35f5f365f5f37365f73) // 9 + 9 hash := keccak256(0x0e, 0x36) // Restore the part of the free memory pointer that has been overwritten. mstore(0x24, 0) } } /// @dev Returns the address of the deterministic PUSH0 clone of `implementation`, /// with `salt` by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddress_PUSH0( address implementation, bytes32 salt, address deployer ) internal pure returns (address predicted) { bytes32 hash = initCodeHash_PUSH0(implementation); predicted = predictDeterministicAddress(hash, salt, deployer); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CLONES WITH IMMUTABLE ARGS OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Deploys a minimal proxy with `implementation`, /// using immutable arguments encoded in `data`. /// /// Note: This implementation of CWIA differs from the original implementation. /// If the calldata is empty, it will emit a `ReceiveETH(uint256)` event and skip the `DELEGATECALL`. function clone(address implementation, bytes memory data) internal returns (address instance) { assembly { // Compute the boundaries of the data and cache the memory slots around it. let mBefore3 := mload(sub(data, 0x60)) let mBefore2 := mload(sub(data, 0x40)) let mBefore1 := mload(sub(data, 0x20)) let dataLength := mload(data) let dataEnd := add(add(data, 0x20), dataLength) let mAfter1 := mload(dataEnd) // +2 bytes for telling how much data there is appended to the call. let extraLength := add(dataLength, 2) // The `creationSize` is `extraLength + 108` // The `runSize` is `creationSize - 10`. /** * ---------------------------------------------------------------------------------------------------+ * CREATION (10 bytes) | * ---------------------------------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * ---------------------------------------------------------------------------------------------------| * 61 runSize | PUSH2 runSize | r | | * 3d | RETURNDATASIZE | 0 r | | * 81 | DUP2 | r 0 r | | * 60 offset | PUSH1 offset | o r 0 r | | * 3d | RETURNDATASIZE | 0 o r 0 r | | * 39 | CODECOPY | 0 r | [0..runSize): runtime code | * f3 | RETURN | | [0..runSize): runtime code | * ---------------------------------------------------------------------------------------------------| * RUNTIME (98 bytes + extraLength) | * ---------------------------------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * ---------------------------------------------------------------------------------------------------| * | * ::: if no calldata, emit event & return w/o `DELEGATECALL` ::::::::::::::::::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds | | * 60 0x2c | PUSH1 0x2c | 0x2c cds | | * 57 | JUMPI | | | * 34 | CALLVALUE | cv | | * 3d | RETURNDATASIZE | 0 cv | | * 52 | MSTORE | | [0..0x20): callvalue | * 7f sig | PUSH32 0x9e.. | sig | [0..0x20): callvalue | * 59 | MSIZE | 0x20 sig | [0..0x20): callvalue | * 3d | RETURNDATASIZE | 0 0x20 sig | [0..0x20): callvalue | * a1 | LOG1 | | [0..0x20): callvalue | * 00 | STOP | | [0..0x20): callvalue | * 5b | JUMPDEST | | | * | * ::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds | | * 3d | RETURNDATASIZE | 0 cds | | * 3d | RETURNDATASIZE | 0 0 cds | | * 37 | CALLDATACOPY | | [0..cds): calldata | * | * ::: keep some values in stack :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | 0 | [0..cds): calldata | * 3d | RETURNDATASIZE | 0 0 | [0..cds): calldata | * 3d | RETURNDATASIZE | 0 0 0 | [0..cds): calldata | * 3d | RETURNDATASIZE | 0 0 0 0 | [0..cds): calldata | * 61 extra | PUSH2 extra | e 0 0 0 0 | [0..cds): calldata | * | * ::: copy extra data to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 80 | DUP1 | e e 0 0 0 0 | [0..cds): calldata | * 60 0x62 | PUSH1 0x62 | 0x62 e e 0 0 0 0 | [0..cds): calldata | * 36 | CALLDATASIZE | cds 0x62 e e 0 0 0 0 | [0..cds): calldata | * 39 | CODECOPY | e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * | * ::: delegate call to the implementation contract ::::::::::::::::::::::::::::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * 01 | ADD | cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * 3d | RETURNDATASIZE | 0 cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * 73 addr | PUSH20 addr | addr 0 cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * 5a | GAS | gas addr 0 cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * f4 | DELEGATECALL | success 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * | * ::: copy return data to memory ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | rds success 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * 3d | RETURNDATASIZE | rds rds success 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * 93 | SWAP4 | 0 rds success 0 rds | [0..cds): calldata, [cds..cds+e): extraData | * 80 | DUP1 | 0 0 rds success 0 rds | [0..cds): calldata, [cds..cds+e): extraData | * 3e | RETURNDATACOPY | success 0 rds | [0..rds): returndata | * | * 60 0x60 | PUSH1 0x60 | 0x60 success 0 rds | [0..rds): returndata | * 57 | JUMPI | 0 rds | [0..rds): returndata | * | * ::: revert ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * fd | REVERT | | [0..rds): returndata | * | * ::: return ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 5b | JUMPDEST | 0 rds | [0..rds): returndata | * f3 | RETURN | | [0..rds): returndata | * ---------------------------------------------------------------------------------------------------+ */ // Write the bytecode before the data. mstore(data, 0x5af43d3d93803e606057fd5bf3) // Write the address of the implementation. mstore(sub(data, 0x0d), implementation) // Write the rest of the bytecode. mstore( sub(data, 0x21), or(shl(0x48, extraLength), 0x593da1005b363d3d373d3d3d3d610000806062363936013d73) ) // `keccak256("ReceiveETH(uint256)")` mstore( sub(data, 0x3a), 0x9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff ) mstore( // Do a out-of-gas revert if `extraLength` is too big. 0xffff - 0x62 + 0x01 = 0xff9e. // The actual EVM limit may be smaller and may change over time. sub(data, add(0x59, lt(extraLength, 0xff9e))), or(shl(0x78, add(extraLength, 0x62)), 0xfd6100003d81600a3d39f336602c57343d527f) ) mstore(dataEnd, shl(0xf0, extraLength)) // Create the instance. instance := create(0, sub(data, 0x4c), add(extraLength, 0x6c)) // If `instance` is zero, revert. if iszero(instance) { // Store the function selector of `DeploymentFailed()`. mstore(0x00, 0x30116425) // Revert with (offset, size). revert(0x1c, 0x04) } // Restore the overwritten memory surrounding `data`. mstore(dataEnd, mAfter1) mstore(data, dataLength) mstore(sub(data, 0x20), mBefore1) mstore(sub(data, 0x40), mBefore2) mstore(sub(data, 0x60), mBefore3) } } /// @dev Deploys a deterministic clone of `implementation`, /// using immutable arguments encoded in `data`, with `salt`. /// /// Note: This implementation of CWIA differs from the original implementation. /// If the calldata is empty, it will emit a `ReceiveETH(uint256)` event and skip the `DELEGATECALL`. function cloneDeterministic(address implementation, bytes memory data, bytes32 salt) internal returns (address instance) { assembly { // Compute the boundaries of the data and cache the memory slots around it. let mBefore3 := mload(sub(data, 0x60)) let mBefore2 := mload(sub(data, 0x40)) let mBefore1 := mload(sub(data, 0x20)) let dataLength := mload(data) let dataEnd := add(add(data, 0x20), dataLength) let mAfter1 := mload(dataEnd) // +2 bytes for telling how much data there is appended to the call. let extraLength := add(dataLength, 2) // Write the bytecode before the data. mstore(data, 0x5af43d3d93803e606057fd5bf3) // Write the address of the implementation. mstore(sub(data, 0x0d), implementation) // Write the rest of the bytecode. mstore( sub(data, 0x21), or(shl(0x48, extraLength), 0x593da1005b363d3d373d3d3d3d610000806062363936013d73) ) // `keccak256("ReceiveETH(uint256)")` mstore( sub(data, 0x3a), 0x9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff ) mstore( // Do a out-of-gas revert if `extraLength` is too big. 0xffff - 0x62 + 0x01 = 0xff9e. // The actual EVM limit may be smaller and may change over time. sub(data, add(0x59, lt(extraLength, 0xff9e))), or(shl(0x78, add(extraLength, 0x62)), 0xfd6100003d81600a3d39f336602c57343d527f) ) mstore(dataEnd, shl(0xf0, extraLength)) // Create the instance. instance := create2(0, sub(data, 0x4c), add(extraLength, 0x6c), salt) // If `instance` is zero, revert. if iszero(instance) { // Store the function selector of `DeploymentFailed()`. mstore(0x00, 0x30116425) // Revert with (offset, size). revert(0x1c, 0x04) } // Restore the overwritten memory surrounding `data`. mstore(dataEnd, mAfter1) mstore(data, dataLength) mstore(sub(data, 0x20), mBefore1) mstore(sub(data, 0x40), mBefore2) mstore(sub(data, 0x60), mBefore3) } } /// @dev Returns the initialization code hash of the clone of `implementation` /// using immutable arguments encoded in `data`. /// Used for mining vanity addresses with create2crunch. function initCodeHash(address implementation, bytes memory data) internal pure returns (bytes32 hash) { assembly { // Compute the boundaries of the data and cache the memory slots around it. let mBefore3 := mload(sub(data, 0x60)) let mBefore2 := mload(sub(data, 0x40)) let mBefore1 := mload(sub(data, 0x20)) let dataLength := mload(data) let dataEnd := add(add(data, 0x20), dataLength) let mAfter1 := mload(dataEnd) // Do a out-of-gas revert if `dataLength` is too big. 0xffff - 0x02 - 0x62 = 0xff9b. // The actual EVM limit may be smaller and may change over time. returndatacopy(returndatasize(), returndatasize(), gt(dataLength, 0xff9b)) // +2 bytes for telling how much data there is appended to the call. let extraLength := add(dataLength, 2) // Write the bytecode before the data. mstore(data, 0x5af43d3d93803e606057fd5bf3) // Write the address of the implementation. mstore(sub(data, 0x0d), implementation) // Write the rest of the bytecode. mstore( sub(data, 0x21), or(shl(0x48, extraLength), 0x593da1005b363d3d373d3d3d3d610000806062363936013d73) ) // `keccak256("ReceiveETH(uint256)")` mstore( sub(data, 0x3a), 0x9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff ) mstore( sub(data, 0x5a), or(shl(0x78, add(extraLength, 0x62)), 0x6100003d81600a3d39f336602c57343d527f) ) mstore(dataEnd, shl(0xf0, extraLength)) // Compute and store the bytecode hash. hash := keccak256(sub(data, 0x4c), add(extraLength, 0x6c)) // Restore the overwritten memory surrounding `data`. mstore(dataEnd, mAfter1) mstore(data, dataLength) mstore(sub(data, 0x20), mBefore1) mstore(sub(data, 0x40), mBefore2) mstore(sub(data, 0x60), mBefore3) } } /// @dev Returns the address of the deterministic clone of /// `implementation` using immutable arguments encoded in `data`, with `salt`, by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddress( address implementation, bytes memory data, bytes32 salt, address deployer ) internal pure returns (address predicted) { bytes32 hash = initCodeHash(implementation, data); predicted = predictDeterministicAddress(hash, salt, deployer); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* OTHER OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the address when a contract with initialization code hash, /// `hash`, is deployed with `salt`, by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddress(bytes32 hash, bytes32 salt, address deployer) internal pure returns (address predicted) { /// @solidity memory-safe-assembly assembly { // Compute and store the bytecode hash. mstore8(0x00, 0xff) // Write the prefix. mstore(0x35, hash) mstore(0x01, shl(96, deployer)) mstore(0x15, salt) predicted := keccak256(0x00, 0x55) // Restore the part of the free memory pointer that has been overwritten. mstore(0x35, 0) } } /// @dev Reverts if `salt` does not start with either the zero address or the caller. function checkStartsWithCaller(bytes32 salt) internal view { /// @solidity memory-safe-assembly assembly { // If the salt does not start with the zero address or the caller. if iszero(or(iszero(shr(96, salt)), eq(caller(), shr(96, salt)))) { // Store the function selector of `SaltDoesNotStartWithCaller()`. mstore(0x00, 0x2f634836) // Revert with (offset, size). revert(0x1c, 0x04) } } } }
// SPDX-License-Identifier: AGPL-3.0 // Copyright (C) 2023 Haberdasher Labs // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <https://www.gnu.org/licenses/>. pragma solidity >=0.8.13; interface IHatsIdUtilities { function buildHatId(uint256 _admin, uint16 _newHat) external pure returns (uint256 id); function getHatLevel(uint256 _hatId) external view returns (uint32 level); function getLocalHatLevel(uint256 _hatId) external pure returns (uint32 level); function isTopHat(uint256 _hatId) external view returns (bool _topHat); function isLocalTopHat(uint256 _hatId) external pure returns (bool _localTopHat); function isValidHatId(uint256 _hatId) external view returns (bool validHatId); function getAdminAtLevel(uint256 _hatId, uint32 _level) external view returns (uint256 admin); function getAdminAtLocalLevel(uint256 _hatId, uint32 _level) external pure returns (uint256 admin); function getTopHatDomain(uint256 _hatId) external view returns (uint32 domain); function getTippyTopHatDomain(uint32 _topHatDomain) external view returns (uint32 domain); function noCircularLinkage(uint32 _topHatDomain, uint256 _linkedAdmin) external view returns (bool notCircular); function sameTippyTopHatDomain(uint32 _topHatDomain, uint256 _newAdminHat) external view returns (bool sameDomain); }
// SPDX-License-Identifier: AGPL-3.0 // Copyright (C) 2023 Haberdasher Labs // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <https://www.gnu.org/licenses/>. pragma solidity >=0.8.13; interface HatsErrors { /// @notice Emitted when `user` is attempting to perform an action on `hatId` but is not wearing one of `hatId`'s admin hats /// @dev Can be equivalent to `NotHatWearer(buildHatId(hatId))`, such as when emitted by `approveLinkTopHatToTree` or `relinkTopHatToTree` error NotAdmin(address user, uint256 hatId); /// @notice Emitted when attempting to perform an action as or for an account that is not a wearer of a given hat error NotHatWearer(); /// @notice Emitted when attempting to perform an action that requires being either an admin or wearer of a given hat error NotAdminOrWearer(); /// @notice Emitted when attempting to mint `hatId` but `hatId`'s maxSupply has been reached error AllHatsWorn(uint256 hatId); /// @notice Emitted when attempting to create a hat with a level 14 hat as its admin error MaxLevelsReached(); /// @notice Emitted when an attempted hat id has empty intermediate level(s) error InvalidHatId(); /// @notice Emitted when attempting to mint `hatId` to a `wearer` who is already wearing the hat error AlreadyWearingHat(address wearer, uint256 hatId); /// @notice Emitted when attempting to mint a non-existant hat error HatDoesNotExist(uint256 hatId); /// @notice Emmitted when attempting to mint or transfer a hat that is not active error HatNotActive(); /// @notice Emitted when attempting to mint or transfer a hat to an ineligible wearer error NotEligible(); /// @notice Emitted when attempting to check or set a hat's status from an account that is not that hat's toggle module error NotHatsToggle(); /// @notice Emitted when attempting to check or set a hat wearer's status from an account that is not that hat's eligibility module error NotHatsEligibility(); /// @notice Emitted when array arguments to a batch function have mismatching lengths error BatchArrayLengthMismatch(); /// @notice Emitted when attempting to mutate or transfer an immutable hat error Immutable(); /// @notice Emitted when attempting to change a hat's maxSupply to a value lower than its current supply error NewMaxSupplyTooLow(); /// @notice Emitted when attempting to link a tophat to a new admin for which the tophat serves as an admin error CircularLinkage(); /// @notice Emitted when attempting to link or relink a tophat to a separate tree error CrossTreeLinkage(); /// @notice Emitted when attempting to link a tophat without a request error LinkageNotRequested(); /// @notice Emitted when attempting to unlink a tophat that does not have a wearer /// @dev This ensures that unlinking never results in a bricked tophat error InvalidUnlink(); /// @notice Emmited when attempting to change a hat's eligibility or toggle module to the zero address error ZeroAddress(); /// @notice Emmitted when attempting to change a hat's details or imageURI to a string with over 7000 bytes (~characters) /// @dev This protects against a DOS attack where an admin iteratively extend's a hat's details or imageURI /// to be so long that reading it exceeds the block gas limit, breaking `uri()` and `viewHat()` error StringTooLong(); }
// SPDX-License-Identifier: AGPL-3.0 // Copyright (C) 2023 Haberdasher Labs // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <https://www.gnu.org/licenses/>. pragma solidity >=0.8.13; interface HatsEvents { /// @notice Emitted when a new hat is created /// @param id The id for the new hat /// @param details A description of the Hat /// @param maxSupply The total instances of the Hat that can be worn at once /// @param eligibility The address that can report on the Hat wearer's status /// @param toggle The address that can deactivate the Hat /// @param mutable_ Whether the hat's properties are changeable after creation /// @param imageURI The image uri for this hat and the fallback for its event HatCreated( uint256 id, string details, uint32 maxSupply, address eligibility, address toggle, bool mutable_, string imageURI ); /// @notice Emitted when a hat wearer's standing is updated /// @dev Eligibility is excluded since the source of truth for eligibility is the eligibility module and may change without a transaction /// @param hatId The id of the wearer's hat /// @param wearer The wearer's address /// @param wearerStanding Whether the wearer is in good standing for the hat event WearerStandingChanged(uint256 hatId, address wearer, bool wearerStanding); /// @notice Emitted when a hat's status is updated /// @param hatId The id of the hat /// @param newStatus Whether the hat is active event HatStatusChanged(uint256 hatId, bool newStatus); /// @notice Emitted when a hat's details are updated /// @param hatId The id of the hat /// @param newDetails The updated details event HatDetailsChanged(uint256 hatId, string newDetails); /// @notice Emitted when a hat's eligibility module is updated /// @param hatId The id of the hat /// @param newEligibility The updated eligibiliy module event HatEligibilityChanged(uint256 hatId, address newEligibility); /// @notice Emitted when a hat's toggle module is updated /// @param hatId The id of the hat /// @param newToggle The updated toggle module event HatToggleChanged(uint256 hatId, address newToggle); /// @notice Emitted when a hat's mutability is updated /// @param hatId The id of the hat event HatMutabilityChanged(uint256 hatId); /// @notice Emitted when a hat's maximum supply is updated /// @param hatId The id of the hat /// @param newMaxSupply The updated max supply event HatMaxSupplyChanged(uint256 hatId, uint32 newMaxSupply); /// @notice Emitted when a hat's image URI is updated /// @param hatId The id of the hat /// @param newImageURI The updated image URI event HatImageURIChanged(uint256 hatId, string newImageURI); /// @notice Emitted when a tophat linkage is requested by its admin /// @param domain The domain of the tree tophat to link /// @param newAdmin The tophat's would-be admin in the parent tree event TopHatLinkRequested(uint32 domain, uint256 newAdmin); /// @notice Emitted when a tophat is linked to a another tree /// @param domain The domain of the newly-linked tophat /// @param newAdmin The tophat's new admin in the parent tree event TopHatLinked(uint32 domain, uint256 newAdmin); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @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.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @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, it is bubbled up by this * function (like regular Solidity function calls). * * 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. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @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`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) 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(errorMessage); } } }
{ "remappings": [ "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "hats-module/=lib/hats-module/src/", "@openzeppelin-contracts/=lib/hats-module/lib/openzeppelin-contracts/", "ERC1155/=lib/hats-module/lib/hats-protocol/lib/ERC1155/", "hats-protocol/=lib/hats-module/lib/hats-protocol/src/", "openzeppelin-contracts/=lib/hats-module/lib/openzeppelin-contracts/", "solady/=lib/hats-module/lib/solady/src/", "solbase/=lib/hats-module/lib/hats-protocol/lib/solbase/src/", "solmate/=lib/hats-module/lib/solady/lib/solmate/src/", "utils/=lib/hats-module/lib/hats-protocol/lib/utils/", "multi-claims-hatter/=lib/multi-claims-hatter/src/", "erc4626-tests/=lib/hats-module/lib/openzeppelin-contracts/lib/erc4626-tests/", "openzeppelin/=lib/hats-module/lib/openzeppelin-contracts/contracts/" ], "optimizer": { "enabled": true, "runs": 1000000 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "none", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "libraries": {} }
[{"inputs":[{"internalType":"string","name":"_version","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AgreementEligibility_NotArbitrator","type":"error"},{"inputs":[],"name":"AgreementEligibility_NotOwner","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"agreement","type":"string"},{"indexed":false,"internalType":"uint256","name":"grace","type":"uint256"}],"name":"AgreementEligibility_AgreementSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"signer","type":"address"},{"indexed":false,"internalType":"string","name":"agreement","type":"string"}],"name":"AgreementEligibility_AgreementSigned","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"claimer","type":"address"},{"indexed":false,"internalType":"uint256","name":"hatId","type":"uint256"},{"indexed":false,"internalType":"string","name":"agreement","type":"string"}],"name":"AgreementEligibility_HatClaimedWithAgreement","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"inputs":[],"name":"ARBITRATOR_HAT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"HATS","outputs":[{"internalType":"contract IHats","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"IMPLEMENTATION","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"OWNER_HAT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"claimer","type":"address"}],"name":"claimerAgreements","outputs":[{"internalType":"uint256","name":"agreementId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentAgreement","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentAgreementId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wearer","type":"address"}],"name":"forgive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wearer","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"getWearerStatus","outputs":[{"internalType":"bool","name":"eligible","type":"bool"},{"internalType":"bool","name":"standing","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"graceEndsAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hatId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_wearer","type":"address"}],"name":"revoke","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_agreement","type":"string"},{"internalType":"uint256","name":"_grace","type":"uint256"}],"name":"setAgreement","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_initData","type":"bytes"}],"name":"setUp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"signAgreement","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_claimsHatter","type":"address"}],"name":"signAgreementAndClaimHat","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version_","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wearer","type":"address"}],"name":"wearerStanding","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
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.