Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
Loading...
Loading
Contract Name:
Registry
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 400 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.19; // External Libraries import "lib/openzeppelin-contracts-upgradeable/contracts/access/AccessControlUpgradeable.sol"; import "lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol"; import {ERC20} from "lib/solady/src/tokens/ERC20.sol"; // Interfaces import "./interfaces/IRegistry.sol"; // Internal Libraries import {Anchor} from "./Anchor.sol"; import {Errors} from "./libraries/Errors.sol"; import {Metadata} from "./libraries/Metadata.sol"; import "./libraries/Native.sol"; import "./libraries/Transfer.sol"; // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⢿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⡟⠘⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⣾⠻⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⡿⠀⠀⠸⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⢀⣠⣴⣴⣶⣶⣶⣦⣦⣀⡀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⡿⠃⠀⠙⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠁⠀⠀⠀⢻⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⡀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠘⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⠃⠀⠀⠀⠀⠈⢿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⣰⣿⣿⣿⡿⠋⠁⠀⠀⠈⠘⠹⣿⣿⣿⣿⣆⠀⠀⠀ // ⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠈⢿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡀⠀⠀ // ⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣟⠀⡀⢀⠀⡀⢀⠀⡀⢈⢿⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⠀ // ⠀⠀⣠⣿⣿⣿⣿⣿⣿⡿⠋⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⡿⢿⠿⠿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣷⡀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠸⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠂⠀⠀ // ⠀⠀⠙⠛⠿⠻⠻⠛⠉⠀⠀⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣧⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⢻⣿⣿⣿⣷⣀⢀⠀⠀⠀⡀⣰⣾⣿⣿⣿⠏⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣧⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠹⢿⣿⣿⣿⣿⣾⣾⣷⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠙⠋⠛⠙⠋⠛⠙⠋⠛⠙⠋⠃⠀⠀⠀⠀⠀⠀⠀⠀⠠⠿⠻⠟⠿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠟⠿⠟⠿⠆⠀⠸⠿⠿⠟⠯⠀⠀⠀⠸⠿⠿⠿⠏⠀⠀⠀⠀⠀⠈⠉⠻⠻⡿⣿⢿⡿⡿⠿⠛⠁⠀⠀⠀⠀⠀⠀ // allo.gitcoin.co /// @title Registry Contract /// @author @thelostone-mc <[email protected]>, @0xKurt <[email protected]>, @codenamejason <[email protected]>, @0xZakk <[email protected]>, @nfrgosselin <[email protected]> /// @notice Registry contract for creating and managing profiles /// @dev This contract is used to create and manage profiles for the Allo protocol /// It is also used to deploy the anchor contract for each profile which acts as a proxy /// for the profile and is used to receive funds and execute transactions on behalf of the profile /// The Registry is also used to add and remove members from a profile and update the profile 'Metadata' contract Registry is IRegistry, Initializable, Native, AccessControlUpgradeable, Transfer, Errors { /// ========================== /// === Storage Variables ==== /// ========================== /// @notice This maps the anchor address to the profile ID /// @dev anchor -> Profile.id mapping(address => bytes32) public anchorToProfileId; /// @notice This maps the profile ID to the profile details /// @dev Profile.id -> Profile mapping(bytes32 => Profile) public profilesById; /// @notice This maps the profile ID to the pending owner /// @dev Profile.id -> pending owner mapping(bytes32 => address) public profileIdToPendingOwner; /// @notice Allo Owner Role for fund recovery bytes32 public constant ALLO_OWNER = keccak256("ALLO_OWNER"); /// ==================================== /// =========== Modifier =============== /// ==================================== /// @notice Checks if the caller is the profile owner /// @dev Reverts `UNAUTHORIZED()` if the caller is not the profile owner /// @param _profileId The ID of the profile modifier onlyProfileOwner(bytes32 _profileId) { _checkOnlyProfileOwner(_profileId); _; } // ==================================== // =========== Initializer ============= // ==================================== /// @notice Initializes the contract after an upgrade /// @dev During upgrade -> a higher version should be passed to reinitializer. Reverts if the '_owner' is the 'address(0)' /// @param _owner The owner of the contract function initialize(address _owner) external reinitializer(1) { // Make sure the owner is not 'address(0)' if (_owner == address(0)) revert ZERO_ADDRESS(); // Grant the role to the owner _grantRole(ALLO_OWNER, _owner); } /// ==================================== /// ==== External/Public Functions ===== /// ==================================== /// @notice Retrieve profile by profileId /// @dev Used when you have the 'profileId' and want to retrieve the profile /// @param _profileId The ID of the profile /// @return The Profile details for the `_profileId` function getProfileById(bytes32 _profileId) external view returns (Profile memory) { return profilesById[_profileId]; } /// @notice Retrieve profile by anchor /// @dev Used when you have the 'anchor' address and want to retrieve the profile /// @param _anchor The anchor of the profile /// @return Profile details for the `_anchor` function getProfileByAnchor(address _anchor) external view returns (Profile memory) { bytes32 profileId = anchorToProfileId[_anchor]; return profilesById[profileId]; } /// @notice Creates a new profile /// @dev This will also generate the 'profileId' and 'anchor' address, emits a 'ProfileCreated()' event /// Note: The 'nonce' is used to generate the 'profileId' and should be unique for each profile /// Note: The 'name' and 'profileId' are used to generate the 'anchor' address /// @param _nonce Nonce used to generate profileId. Can be any integer, but should be unique /// for each profile. /// @param _name The name of the profile /// @param _metadata The metadata of the profile /// @param _owner The owner of the profile /// @param _members The members of the profile (can be set only if msg.sender == _owner) /// @return The ID for the created profile function createProfile( uint256 _nonce, string memory _name, Metadata memory _metadata, address _owner, address[] memory _members ) external returns (bytes32) { // Generate a profile ID using a nonce and the msg.sender bytes32 profileId = _generateProfileId(_nonce, _owner); // Make sure the nonce is available if (profilesById[profileId].anchor != address(0)) revert NONCE_NOT_AVAILABLE(); // Make sure the owner is not the zero address if (_owner == address(0)) revert ZERO_ADDRESS(); // Create a new Profile instance, also generates the anchor address Profile memory profile = Profile({ id: profileId, nonce: _nonce, name: _name, metadata: _metadata, owner: _owner, anchor: _generateAnchor(profileId, _name) }); profilesById[profileId] = profile; anchorToProfileId[profile.anchor] = profileId; // Assign roles for the profile members uint256 memberLength = _members.length; // Only profile owner can add members if (memberLength > 0 && _owner != msg.sender) { revert UNAUTHORIZED(); } for (uint256 i; i < memberLength;) { address member = _members[i]; // Will revert if any of the addresses are a zero address if (member == address(0)) revert ZERO_ADDRESS(); // Grant the role to the member and emit the event for each member _grantRole(profileId, member); unchecked { ++i; } } // Emit the event that the profile was created emit ProfileCreated(profileId, profile.nonce, profile.name, profile.metadata, profile.owner, profile.anchor); // Return the profile ID return profileId; } /// @notice Updates the name of the profile and generates new anchor. /// Emits a 'ProfileNameUpdated()' event. /// @dev Use caution when updating your profile name as it will generate a new anchor address. You can always update the name /// back to the original name to get the original anchor address. 'msg.sender' must be the owner of the profile. /// @param _profileId The profileId of the profile /// @param _name The new name of the profile /// @return anchor The new anchor function updateProfileName(bytes32 _profileId, string memory _name) external onlyProfileOwner(_profileId) returns (address anchor) { // Generate a new anchor address anchor = _generateAnchor(_profileId, _name); // Get the profile using the profileId from the mapping Profile storage profile = profilesById[_profileId]; // Set the new name profile.name = _name; // Remove old anchor anchorToProfileId[profile.anchor] = bytes32(0); // Set the new anchor profile.anchor = anchor; anchorToProfileId[anchor] = _profileId; // Emit the event that the name was updated with the new data emit ProfileNameUpdated(_profileId, _name, anchor); // Return the new anchor return anchor; } /// @notice Update the 'Metadata' of the profile. Emits a 'ProfileMetadataUpdated()' event. /// @dev 'msg.sender' must be the owner of the profile. /// @param _profileId The ID of the profile /// @param _metadata The new 'Metadata' of the profile function updateProfileMetadata(bytes32 _profileId, Metadata memory _metadata) external onlyProfileOwner(_profileId) { // Get the profile using the 'profileId' from the mapping and update the 'Metadata' value profilesById[_profileId].metadata = _metadata; // Emit the event that the 'Metadata' was updated emit ProfileMetadataUpdated(_profileId, _metadata); } /// @notice Checks if the address is an owner or member of the profile /// @param _profileId The ID of the profile /// @param _account The address to check /// @return 'true' if the address is an owner or member of the profile, otherwise 'false' function isOwnerOrMemberOfProfile(bytes32 _profileId, address _account) external view returns (bool) { return _isOwnerOfProfile(_profileId, _account) || _isMemberOfProfile(_profileId, _account); } /// @notice Checks if the given address is an owner of the profile /// @param _profileId The ID of the profile /// @param _owner The address to check /// @return 'true' if the address is an owner of the profile, otherwise 'false' function isOwnerOfProfile(bytes32 _profileId, address _owner) external view returns (bool) { return _isOwnerOfProfile(_profileId, _owner); } /// @notice Checks if the given address is a member of the profile /// @param _profileId The ID of the profile /// @param _member The address to check /// @return 'true' if the address is a member of the profile, otherwise 'false' function isMemberOfProfile(bytes32 _profileId, address _member) external view returns (bool) { return _isMemberOfProfile(_profileId, _member); } /// @notice Updates the pending owner of the profile. Emits a 'ProfilePendingOwnership()' event. /// @dev 'msg.sender' must be the owner of the profile. [1]*This is step one of two when transferring ownership. /// @param _profileId The ID of the profile /// @param _pendingOwner The new pending owner function updateProfilePendingOwner(bytes32 _profileId, address _pendingOwner) external onlyProfileOwner(_profileId) { // Set the pending owner to the profile profileIdToPendingOwner[_profileId] = _pendingOwner; // Emit the event that the pending owner was updated emit ProfilePendingOwnerUpdated(_profileId, _pendingOwner); } /// @notice Transfers the ownership of the profile to the pending owner and Emits a 'ProfileOwnerUdpated()' event. /// @dev 'msg.sender' must be the pending owner of the profile. [2]*This is step two of two when transferring ownership. /// @param _profileId The ID of the profile function acceptProfileOwnership(bytes32 _profileId) external { // Get the profile from the mapping Profile storage profile = profilesById[_profileId]; // Get the pending owner from the mapping that was set when the owner was updated address newOwner = profileIdToPendingOwner[_profileId]; // Revert if the 'msg.sender' is not the pending owner if (msg.sender != newOwner) revert NOT_PENDING_OWNER(); // Set the new owner and delete the pending owner from the mapping profile.owner = newOwner; delete profileIdToPendingOwner[_profileId]; // Emit the event that the owner was accepted and updated emit ProfileOwnerUpdated(_profileId, profile.owner); } /// @notice Adds members to the profile /// @dev 'msg.sender' must be the owner of the profile. /// @param _profileId The ID of the profile /// @param _members The members to add function addMembers(bytes32 _profileId, address[] memory _members) external onlyProfileOwner(_profileId) { uint256 memberLength = _members.length; // Loop through the members and add them to the profile by granting the role for (uint256 i; i < memberLength;) { address member = _members[i]; // Will revert if any of the addresses are a zero address if (member == address(0)) revert ZERO_ADDRESS(); // Grant the role to the member and emit the event for each member _grantRole(_profileId, member); unchecked { ++i; } } } /// @notice Removes members from the profile /// @dev 'msg.sender' must be the pending owner of the profile. /// @param _profileId The ID of the profile /// @param _members The members to remove function removeMembers(bytes32 _profileId, address[] memory _members) external onlyProfileOwner(_profileId) { uint256 memberLength = _members.length; // Loop through the members and remove them from the profile by revoking the role for (uint256 i; i < memberLength;) { // Revoke the role from the member and emit the event for each member _revokeRole(_profileId, _members[i]); unchecked { ++i; } } } /// ==================================== /// ======== Internal Functions ======== /// ==================================== /// @notice Checks if the caller is the owner of the profile /// @dev Internal function used by modifier 'onlyProfileOwner' /// @param _profileId The ID of the profile function _checkOnlyProfileOwner(bytes32 _profileId) internal view { if (!_isOwnerOfProfile(_profileId, msg.sender)) revert UNAUTHORIZED(); } /// @notice Generates and deploys the anchor for the given 'profileId' and name /// @dev Internal function used by 'createProfile()' and 'updateProfileName()' to create and anchor. /// @param _profileId The ID of the profile /// @param _name The name of the profile /// @return anchor The address of the deployed anchor contract function _generateAnchor(bytes32 _profileId, string memory _name) internal returns (address anchor) { bytes memory encodedData = abi.encode(_profileId, _name); bytes memory encodedConstructorArgs = abi.encode(_profileId, address(this)); bytes memory bytecode = abi.encodePacked(type(Anchor).creationCode, encodedConstructorArgs); bytes32 salt = keccak256(encodedData); address preComputedAddress = address( uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(this), salt, keccak256(bytecode))))) ); // Try to deploy the anchor contract, if it fails then the anchor already exists try new Anchor{salt: salt}(_profileId, address(this)) returns (Anchor _anchor) { anchor = address(_anchor); } catch { if (Anchor(payable(preComputedAddress)).profileId() != _profileId) revert ANCHOR_ERROR(); anchor = preComputedAddress; } } /// @notice Generates the 'profileId' based on msg.sender and nonce /// @dev Internal function used by 'createProfile()' to generate profileId. /// @param _nonce Nonce provided by the caller to generate 'profileId' /// @param _owner The owner of the profile /// @return 'profileId' The ID of the profile function _generateProfileId(uint256 _nonce, address _owner) internal pure returns (bytes32) { return keccak256(abi.encodePacked(_nonce, _owner)); } /// @notice Checks if an address is the owner of the profile /// @dev Internal function used to determine if an address is the profile owner /// @param _profileId The 'profileId' of the profile /// @param _owner The address to check /// @return 'true' if the address is an owner of the profile, otherwise 'false' function _isOwnerOfProfile(bytes32 _profileId, address _owner) internal view returns (bool) { return profilesById[_profileId].owner == _owner; } /// @notice Checks if an address is a member of the profile /// @dev Internal function used to determine if an address is a member of the profile /// @param _profileId The 'profileId' of the profile /// @param _member The address to check /// @return 'true' if the address is a member of the profile, otherwise 'false' function _isMemberOfProfile(bytes32 _profileId, address _member) internal view returns (bool) { return hasRole(_profileId, _member); } /// @notice Transfers any fund balance in Allo to the recipient /// @dev 'msg.sender' must be the Allo owner /// @param _token The address of the token to transfer /// @param _recipient The address of the recipient function recoverFunds(address _token, address _recipient) external onlyRole(ALLO_OWNER) { if (_recipient == address(0)) revert ZERO_ADDRESS(); uint256 amount = _token == NATIVE ? address(this).balance : ERC20(_token).balanceOf(address(this)); _transferAmount(_token, _recipient, amount); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.19; import "lib/openzeppelin-contracts/contracts/token/ERC721/utils/ERC721Holder.sol"; import "lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Holder.sol"; // Core Contracts import {Registry} from "./Registry.sol"; // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⢿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⡟⠘⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⣾⠻⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⡿⠀⠀⠸⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⢀⣠⣴⣴⣶⣶⣶⣦⣦⣀⡀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⡿⠃⠀⠙⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠁⠀⠀⠀⢻⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⡀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠘⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⠃⠀⠀⠀⠀⠈⢿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⣰⣿⣿⣿⡿⠋⠁⠀⠀⠈⠘⠹⣿⣿⣿⣿⣆⠀⠀⠀ // ⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠈⢿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡀⠀⠀ // ⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣟⠀⡀⢀⠀⡀⢀⠀⡀⢈⢿⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⠀ // ⠀⠀⣠⣿⣿⣿⣿⣿⣿⡿⠋⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⡿⢿⠿⠿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣷⡀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠸⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠂⠀⠀ // ⠀⠀⠙⠛⠿⠻⠻⠛⠉⠀⠀⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣧⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⢻⣿⣿⣿⣷⣀⢀⠀⠀⠀⡀⣰⣾⣿⣿⣿⠏⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣧⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠹⢿⣿⣿⣿⣿⣾⣾⣷⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠙⠋⠛⠙⠋⠛⠙⠋⠛⠙⠋⠃⠀⠀⠀⠀⠀⠀⠀⠀⠠⠿⠻⠟⠿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠟⠿⠟⠿⠆⠀⠸⠿⠿⠟⠯⠀⠀⠀⠸⠿⠿⠿⠏⠀⠀⠀⠀⠀⠈⠉⠻⠻⡿⣿⢿⡿⡿⠿⠛⠁⠀⠀⠀⠀⠀⠀ // allo.gitcoin.co /// @title Anchor contract /// @author @thelostone-mc <[email protected]>, @0xKurt <[email protected]>, @codenamejason <[email protected]>, @0xZakk <[email protected]>, @nfrgosselin <[email protected]> /// @notice Anchors are associated with profiles and are accessible exclusively by the profile owner. This contract ensures secure /// and authorized interaction with external addresses, enhancing the capabilities of profiles and enabling controlled /// execution of operations. The contract leverages the `Registry` contract for ownership verification and access control. contract Anchor is ERC721Holder, ERC1155Holder { /// ========================== /// === Storage Variables ==== /// ========================== /// @notice The registry contract on any given network/chain Registry public immutable registry; /// @notice The profileId of the allowed profile to execute calls bytes32 public immutable profileId; /// ========================== /// ======== Errors ========== /// ========================== /// @notice Throws when the caller is not the owner of the profile error UNAUTHORIZED(); /// @notice Throws when the call to the target address fails error CALL_FAILED(); /// ========================== /// ======= Constructor ====== /// ========================== /// @notice Constructor /// @dev We create an instance of the 'Registry' contract using the 'msg.sender' and set the profileId. /// @param _profileId The ID of the allowed profile to execute calls constructor(bytes32 _profileId, address _registry) { registry = Registry(_registry); profileId = _profileId; } /// ========================== /// ======== External ======== /// ========================== /// @notice Execute a call to a target address /// @dev 'msg.sender' must be profile owner /// @param _target The target address to call /// @param _value The amount of native token to send /// @param _data The data to send to the target address /// @return Data returned from the target address function execute(address _target, uint256 _value, bytes memory _data) external returns (bytes memory) { // Check if the caller is the owner of the profile and revert if not if (!registry.isOwnerOfProfile(profileId, msg.sender)) revert UNAUTHORIZED(); // Check if the target address is the zero address and revert if it is if (_target == address(0)) revert CALL_FAILED(); // Call the target address and return the data (bool success, bytes memory data) = _target.call{value: _value}(_data); // Check if the call was successful and revert if not if (!success) revert CALL_FAILED(); return data; } /// @notice This contract should be able to receive native token receive() external payable {} }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; // Internal Libraries import {Metadata} from "../libraries/Metadata.sol"; // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⢿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⡟⠘⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⣾⠻⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⡿⠀⠀⠸⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⢀⣠⣴⣴⣶⣶⣶⣦⣦⣀⡀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⡿⠃⠀⠙⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠁⠀⠀⠀⢻⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⡀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠘⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⠃⠀⠀⠀⠀⠈⢿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⣰⣿⣿⣿⡿⠋⠁⠀⠀⠈⠘⠹⣿⣿⣿⣿⣆⠀⠀⠀ // ⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠈⢿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡀⠀⠀ // ⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣟⠀⡀⢀⠀⡀⢀⠀⡀⢈⢿⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⠀ // ⠀⠀⣠⣿⣿⣿⣿⣿⣿⡿⠋⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⡿⢿⠿⠿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣷⡀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠸⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠂⠀⠀ // ⠀⠀⠙⠛⠿⠻⠻⠛⠉⠀⠀⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣧⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⢻⣿⣿⣿⣷⣀⢀⠀⠀⠀⡀⣰⣾⣿⣿⣿⠏⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣧⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠹⢿⣿⣿⣿⣿⣾⣾⣷⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠙⠋⠛⠙⠋⠛⠙⠋⠛⠙⠋⠃⠀⠀⠀⠀⠀⠀⠀⠀⠠⠿⠻⠟⠿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠟⠿⠟⠿⠆⠀⠸⠿⠿⠟⠯⠀⠀⠀⠸⠿⠿⠿⠏⠀⠀⠀⠀⠀⠈⠉⠻⠻⡿⣿⢿⡿⡿⠿⠛⠁⠀⠀⠀⠀⠀⠀ // allo.gitcoin.co /// @title IRegistry Interface /// @author @thelostone-mc <[email protected]>, @0xKurt <[email protected]>, @codenamejason <[email protected]>, @0xZakk <[email protected]>, @nfrgosselin <[email protected]> /// @notice Interface for the Registry contract and exposes all functions needed to use the Registry /// within the Allo protocol. /// @dev The Registry Interface is used to interact with the Allo protocol and create profiles /// that can be used to interact with the Allo protocol. The Registry is the main contract /// that all other contracts interact with to get the 'Profile' information needed to /// interact with the Allo protocol. The Registry is also used to create new profiles /// and update existing profiles. The Registry is also used to add and remove members /// from a profile. The Registry will not always be used in a strategy and will depend on /// the strategy being used. interface IRegistry { /// ====================== /// ======= Structs ====== /// ====================== /// @dev The Profile struct that all profiles are based from struct Profile { bytes32 id; uint256 nonce; string name; Metadata metadata; address owner; address anchor; } /// ====================== /// ======= Events ======= /// ====================== /// @dev Emitted when a profile is created. This will return your anchor address. event ProfileCreated( bytes32 indexed profileId, uint256 nonce, string name, Metadata metadata, address owner, address anchor ); /// @dev Emitted when a profile name is updated. This will update the anchor when the name is updated and return it. event ProfileNameUpdated(bytes32 indexed profileId, string name, address anchor); /// @dev Emitted when a profile's metadata is updated. event ProfileMetadataUpdated(bytes32 indexed profileId, Metadata metadata); /// @dev Emitted when a profile owner is updated. event ProfileOwnerUpdated(bytes32 indexed profileId, address owner); /// @dev Emitted when a profile pending owner is updated. event ProfilePendingOwnerUpdated(bytes32 indexed profileId, address pendingOwner); /// ========================= /// ==== View Functions ===== /// ========================= /// @dev Returns the 'Profile' for a '_profileId' passed /// @param _profileId The 'profileId' to return the 'Profile' for /// @return profile The 'Profile' for the '_profileId' passed function getProfileById(bytes32 _profileId) external view returns (Profile memory profile); /// @dev Returns the 'Profile' for an '_anchor' passed /// @param _anchor The 'anchor' to return the 'Profile' for /// @return profile The 'Profile' for the '_anchor' passed function getProfileByAnchor(address _anchor) external view returns (Profile memory profile); /// @dev Returns a boolean if the '_account' is a member or owner of the '_profileId' passed in /// @param _profileId The 'profileId' to check if the '_account' is a member or owner of /// @param _account The 'account' to check if they are a member or owner of the '_profileId' passed in /// @return isOwnerOrMemberOfProfile A boolean if the '_account' is a member or owner of the '_profileId' passed in function isOwnerOrMemberOfProfile(bytes32 _profileId, address _account) external view returns (bool isOwnerOrMemberOfProfile); /// @dev Returns a boolean if the '_account' is an owner of the '_profileId' passed in /// @param _profileId The 'profileId' to check if the '_account' is an owner of /// @param _owner The 'owner' to check if they are an owner of the '_profileId' passed in /// @return isOwnerOfProfile A boolean if the '_account' is an owner of the '_profileId' passed in function isOwnerOfProfile(bytes32 _profileId, address _owner) external view returns (bool isOwnerOfProfile); /// @dev Returns a boolean if the '_account' is a member of the '_profileId' passed in /// @param _profileId The 'profileId' to check if the '_account' is a member of /// @param _member The 'member' to check if they are a member of the '_profileId' passed in /// @return isMemberOfProfile A boolean if the '_account' is a member of the '_profileId' passed in function isMemberOfProfile(bytes32 _profileId, address _member) external view returns (bool isMemberOfProfile); /// ==================================== /// ==== External/Public Functions ===== /// ==================================== /// @dev Creates a new 'Profile' and returns the 'profileId' of the new profile /// /// Note: The 'name' and 'nonce' are used to generate the 'anchor' address /// /// Requirements: None, anyone can create a new profile /// /// @param _nonce The nonce to use to generate the 'anchor' address /// @param _name The name to use to generate the 'anchor' address /// @param _metadata The 'Metadata' to use to generate the 'anchor' address /// @param _owner The 'owner' to use to generate the 'anchor' address /// @param _members The 'members' to use to generate the 'anchor' address /// @return profileId The 'profileId' of the new profile function createProfile( uint256 _nonce, string memory _name, Metadata memory _metadata, address _owner, address[] memory _members ) external returns (bytes32 profileId); /// @dev Updates the 'name' of the '_profileId' passed in and returns the new 'anchor' address /// /// Requirements: Only the 'Profile' owner can update the name /// /// Note: The 'name' and 'nonce' are used to generate the 'anchor' address and this will update the 'anchor' /// so please use caution. You can always recreate your 'anchor' address by updating the name back /// to the original name used to create the profile. /// /// @param _profileId The 'profileId' to update the name for /// @param _name The new 'name' value /// @return anchor The new 'anchor' address function updateProfileName(bytes32 _profileId, string memory _name) external returns (address anchor); /// @dev Updates the 'Metadata' of the '_profileId' passed in /// /// Requirements: Only the 'Profile' owner can update the metadata /// /// @param _profileId The 'profileId' to update the metadata for /// @param _metadata The new 'Metadata' value function updateProfileMetadata(bytes32 _profileId, Metadata memory _metadata) external; /// @dev Updates the pending 'owner' of the '_profileId' passed in /// /// Requirements: Only the 'Profile' owner can update the pending owner /// /// @param _profileId The 'profileId' to update the pending owner for /// @param _pendingOwner The new pending 'owner' value function updateProfilePendingOwner(bytes32 _profileId, address _pendingOwner) external; /// @dev Accepts the pending 'owner' of the '_profileId' passed in /// /// Requirements: Only the pending owner can accept the ownership /// /// @param _profileId The 'profileId' to accept the ownership for function acceptProfileOwnership(bytes32 _profileId) external; /// @dev Adds members to the '_profileId' passed in /// /// Requirements: Only the 'Profile' owner can add members /// /// @param _profileId The 'profileId' to add members to /// @param _members The members to add to the '_profileId' passed in function addMembers(bytes32 _profileId, address[] memory _members) external; /// @dev Removes members from the '_profileId' passed in /// /// Requirements: Only the 'Profile' owner can remove members /// /// @param _profileId The 'profileId' to remove members from /// @param _members The members to remove from the '_profileId' passed in function removeMembers(bytes32 _profileId, address[] memory _members) external; /// @dev Recovers funds from the contract /// /// Requirements: Must be the Allo owner /// /// @param _token The token you want to use to recover funds /// @param _recipient The recipient of the recovered funds function recoverFunds(address _token, address _recipient) external; }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.19; // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⢿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⡟⠘⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⣾⠻⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⡿⠀⠀⠸⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⢀⣠⣴⣴⣶⣶⣶⣦⣦⣀⡀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⡿⠃⠀⠙⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠁⠀⠀⠀⢻⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⡀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠘⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⠃⠀⠀⠀⠀⠈⢿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⣰⣿⣿⣿⡿⠋⠁⠀⠀⠈⠘⠹⣿⣿⣿⣿⣆⠀⠀⠀ // ⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠈⢿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡀⠀⠀ // ⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣟⠀⡀⢀⠀⡀⢀⠀⡀⢈⢿⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⠀ // ⠀⠀⣠⣿⣿⣿⣿⣿⣿⡿⠋⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⡿⢿⠿⠿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣷⡀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠸⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠂⠀⠀ // ⠀⠀⠙⠛⠿⠻⠻⠛⠉⠀⠀⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣧⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⢻⣿⣿⣿⣷⣀⢀⠀⠀⠀⡀⣰⣾⣿⣿⣿⠏⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣧⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠹⢿⣿⣿⣿⣿⣾⣾⣷⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠙⠋⠛⠙⠋⠛⠙⠋⠛⠙⠋⠃⠀⠀⠀⠀⠀⠀⠀⠀⠠⠿⠻⠟⠿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠟⠿⠟⠿⠆⠀⠸⠿⠿⠟⠯⠀⠀⠀⠸⠿⠿⠿⠏⠀⠀⠀⠀⠀⠈⠉⠻⠻⡿⣿⢿⡿⡿⠿⠛⠁⠀⠀⠀⠀⠀⠀ // allo.gitcoin.co /// @title Errors /// @author @thelostone-mc <[email protected]>, @KurtMerbeth <[email protected]>, @codenamejason <[email protected]> /// @notice Library containing all custom errors the protocol may revert with. contract Errors { /// ====================== /// ====== Generic ======= /// ====================== /// @notice Thrown as a general error when input / data is invalid error INVALID(); /// @notice Thrown when mismatch in decoding data error MISMATCH(); /// @notice Thrown when not enough funds are available error NOT_ENOUGH_FUNDS(); /// @notice Thrown when user is not authorized error UNAUTHORIZED(); /// @notice Thrown when address is the zero address error ZERO_ADDRESS(); /// @notice Thrown when the function is not implemented error NOT_IMPLEMENTED(); /// ====================== /// ====== Registry ====== /// ====================== /// @dev Thrown when the nonce passed has been used or not available error NONCE_NOT_AVAILABLE(); /// @dev Thrown when the 'msg.sender' is not the pending owner on ownership transfer error NOT_PENDING_OWNER(); /// @dev Thrown if the anchor creation fails error ANCHOR_ERROR(); /// ====================== /// ======== Allo ======== /// ====================== /// @notice Thrown when the strategy is not approved error NOT_APPROVED_STRATEGY(); /// @notice Thrown when the strategy is approved and should be cloned error IS_APPROVED_STRATEGY(); /// @notice Thrown when the fee is below 1e18 which is the fee percentage denominator error INVALID_FEE(); /// ====================== /// ===== IStrategy ====== /// ====================== /// @notice Thrown when data is already intialized error ALREADY_INITIALIZED(); /// @notice Thrown when data is yet to be initialized error NOT_INITIALIZED(); /// @notice Thrown when an invalid address is used error INVALID_ADDRESS(); /// @notice Thrown when a pool is inactive error POOL_INACTIVE(); /// @notice Thrown when a pool is already active error POOL_ACTIVE(); /// @notice Thrown when two arrays length are not equal error ARRAY_MISMATCH(); /// @notice Thrown when the registration is invalid. error INVALID_REGISTRATION(); /// @notice Thrown when the metadata is invalid. error INVALID_METADATA(); /// @notice Thrown when the recipient is not accepted. error RECIPIENT_NOT_ACCEPTED(); /// @notice Thrown when recipient is already accepted. error RECIPIENT_ALREADY_ACCEPTED(); /// @notice Thrown when registration is not active. error REGISTRATION_NOT_ACTIVE(); /// @notice Thrown when registration is active. error REGISTRATION_ACTIVE(); /// @notice Thrown when there is an error in recipient. error RECIPIENT_ERROR(address recipientId); /// @notice Thrown when the allocation is not active. error ALLOCATION_NOT_ACTIVE(); /// @notice Thrown when the allocation is not ended. error ALLOCATION_NOT_ENDED(); /// @notice Thrown when the allocation is active. error ALLOCATION_ACTIVE(); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.19; // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⢿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⡟⠘⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⣾⠻⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⡿⠀⠀⠸⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⢀⣠⣴⣴⣶⣶⣶⣦⣦⣀⡀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⡿⠃⠀⠙⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠁⠀⠀⠀⢻⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⡀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠘⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⠃⠀⠀⠀⠀⠈⢿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⣰⣿⣿⣿⡿⠋⠁⠀⠀⠈⠘⠹⣿⣿⣿⣿⣆⠀⠀⠀ // ⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠈⢿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡀⠀⠀ // ⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣟⠀⡀⢀⠀⡀⢀⠀⡀⢈⢿⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⠀ // ⠀⠀⣠⣿⣿⣿⣿⣿⣿⡿⠋⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⡿⢿⠿⠿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣷⡀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠸⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠂⠀⠀ // ⠀⠀⠙⠛⠿⠻⠻⠛⠉⠀⠀⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣧⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⢻⣿⣿⣿⣷⣀⢀⠀⠀⠀⡀⣰⣾⣿⣿⣿⠏⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣧⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠹⢿⣿⣿⣿⣿⣾⣾⣷⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠙⠋⠛⠙⠋⠛⠙⠋⠛⠙⠋⠃⠀⠀⠀⠀⠀⠀⠀⠀⠠⠿⠻⠟⠿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠟⠿⠟⠿⠆⠀⠸⠿⠿⠟⠯⠀⠀⠀⠸⠿⠿⠿⠏⠀⠀⠀⠀⠀⠈⠉⠻⠻⡿⣿⢿⡿⡿⠿⠛⠁⠀⠀⠀⠀⠀⠀ // allo.gitcoin.co /// @title Metadata /// @author @thelostone-mc <[email protected]>, @0xKurt <[email protected]>, @codenamejason <[email protected]>, @0xZakk <[email protected]>, @nfrgosselin <[email protected]> /// @notice Metadata is used to define the metadata for the protocol that is used throughout the system. struct Metadata { /// @notice Protocol ID corresponding to a specific protocol (currently using IPFS = 1) uint256 protocol; /// @notice Pointer (hash) to fetch metadata for the specified protocol string pointer; }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.19; // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⢿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⡟⠘⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⣾⠻⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⡿⠀⠀⠸⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⢀⣠⣴⣴⣶⣶⣶⣦⣦⣀⡀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⡿⠃⠀⠙⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠁⠀⠀⠀⢻⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⡀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠘⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⠃⠀⠀⠀⠀⠈⢿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⣰⣿⣿⣿⡿⠋⠁⠀⠀⠈⠘⠹⣿⣿⣿⣿⣆⠀⠀⠀ // ⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠈⢿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡀⠀⠀ // ⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣟⠀⡀⢀⠀⡀⢀⠀⡀⢈⢿⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⠀ // ⠀⠀⣠⣿⣿⣿⣿⣿⣿⡿⠋⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⡿⢿⠿⠿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣷⡀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠸⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠂⠀⠀ // ⠀⠀⠙⠛⠿⠻⠻⠛⠉⠀⠀⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣧⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⢻⣿⣿⣿⣷⣀⢀⠀⠀⠀⡀⣰⣾⣿⣿⣿⠏⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣧⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠹⢿⣿⣿⣿⣿⣾⣾⣷⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠙⠋⠛⠙⠋⠛⠙⠋⠛⠙⠋⠃⠀⠀⠀⠀⠀⠀⠀⠀⠠⠿⠻⠟⠿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠟⠿⠟⠿⠆⠀⠸⠿⠿⠟⠯⠀⠀⠀⠸⠿⠿⠿⠏⠀⠀⠀⠀⠀⠈⠉⠻⠻⡿⣿⢿⡿⡿⠿⠛⠁⠀⠀⠀⠀⠀⠀ // allo.gitcoin.co /// @title Native token information /// @author @thelostone-mc <[email protected]>, @0xKurt <[email protected]>, @codenamejason <[email protected]>, @0xZakk <[email protected]>, @nfrgosselin <[email protected]> /// @notice This is used to define the address of the native token for the protocol contract Native { /// @notice Address of the native token address public constant NATIVE = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.19; // External Libraries import {SafeTransferLib} from "lib/solady/src/utils/SafeTransferLib.sol"; // Internal Libraries import "./Native.sol"; // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⢿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⡟⠘⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⣾⠻⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⡿⠀⠀⠸⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠀⠀⢀⣠⣴⣴⣶⣶⣶⣦⣦⣀⡀⠀⠀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⡿⠃⠀⠙⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠁⠀⠀⠀⢻⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⡀⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠘⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⠃⠀⠀⠀⠀⠈⢿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⣰⣿⣿⣿⡿⠋⠁⠀⠀⠈⠘⠹⣿⣿⣿⣿⣆⠀⠀⠀ // ⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠈⢿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⡀⠀⠀ // ⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣟⠀⡀⢀⠀⡀⢀⠀⡀⢈⢿⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⠀ // ⠀⠀⣠⣿⣿⣿⣿⣿⣿⡿⠋⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⡿⢿⠿⠿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣷⡀⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠸⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠂⠀⠀ // ⠀⠀⠙⠛⠿⠻⠻⠛⠉⠀⠀⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣧⠀⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⢻⣿⣿⣿⣷⣀⢀⠀⠀⠀⡀⣰⣾⣿⣿⣿⠏⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣧⠀⠀⢸⣿⣿⣿⣗⠀⠀⠀⢸⣿⣿⣿⡯⠀⠀⠀⠀⠹⢿⣿⣿⣿⣿⣾⣾⣷⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀ // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠙⠋⠛⠙⠋⠛⠙⠋⠛⠙⠋⠃⠀⠀⠀⠀⠀⠀⠀⠀⠠⠿⠻⠟⠿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠟⠿⠟⠿⠆⠀⠸⠿⠿⠟⠯⠀⠀⠀⠸⠿⠿⠿⠏⠀⠀⠀⠀⠀⠈⠉⠻⠻⡿⣿⢿⡿⡿⠿⠛⠁⠀⠀⠀⠀⠀⠀ // allo.gitcoin.co /// @title Transfer contract /// @author @thelostone-mc <[email protected]>, @0xKurt <[email protected]>, @codenamejason <[email protected]>, @0xZakk <[email protected]>, @nfrgosselin <[email protected]> /// @notice A helper contract to transfer tokens within Allo protocol /// @dev Handles the transfer of tokens to an address contract Transfer is Native { /// @notice Thrown when the amount of tokens sent does not match the amount of tokens expected error AMOUNT_MISMATCH(); /// @notice This holds the details for a transfer struct TransferData { address from; address to; uint256 amount; } /// @notice Transfer an amount of a token to an array of addresses /// @param _token The address of the token /// @param _transferData TransferData[] /// @return Whether the transfer was successful or not function _transferAmountsFrom(address _token, TransferData[] memory _transferData) internal virtual returns (bool) { uint256 msgValue = msg.value; for (uint256 i; i < _transferData.length;) { TransferData memory transferData = _transferData[i]; if (_token == NATIVE) { msgValue -= transferData.amount; SafeTransferLib.safeTransferETH(transferData.to, transferData.amount); } else { SafeTransferLib.safeTransferFrom(_token, transferData.from, transferData.to, transferData.amount); } unchecked { i++; } } if (msgValue != 0) revert AMOUNT_MISMATCH(); return true; } /// @notice Transfer an amount of a token to an address /// @param _token The address of the token /// @param _transferData Individual TransferData /// @return Whether the transfer was successful or not function _transferAmountFrom(address _token, TransferData memory _transferData) internal virtual returns (bool) { uint256 amount = _transferData.amount; if (_token == NATIVE) { // Native Token if (msg.value < amount) revert AMOUNT_MISMATCH(); SafeTransferLib.safeTransferETH(_transferData.to, amount); } else { SafeTransferLib.safeTransferFrom(_token, _transferData.from, _transferData.to, amount); } return true; } /// @notice Transfer an amount of a token to an address /// @param _token The token to transfer /// @param _to The address to transfer to /// @param _amount The amount to transfer function _transferAmount(address _token, address _to, uint256 _amount) internal virtual { if (_token == NATIVE) { SafeTransferLib.safeTransferETH(_to, _amount); } else { SafeTransferLib.safeTransfer(_token, _to, _amount); } } /// @notice Get the balance of a token for an account /// @param _token The token to get the balance of /// @param _account The account to get the balance for /// @return The balance of the token for the account function _getBalance(address _token, address _account) internal view returns (uint256) { if (_token == NATIVE) { return payable(_account).balance; } else { return SafeTransferLib.balanceOf(_token, _account); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol) pragma solidity ^0.8.0; import "./IAccessControlUpgradeable.sol"; import "../utils/ContextUpgradeable.sol"; import "../utils/StringsUpgradeable.sol"; import "../utils/introspection/ERC165Upgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ```solidity * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ```solidity * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} * to enforce additional security measures for this role. */ abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControlUpgradeable, ERC165Upgradeable { function __AccessControl_init() internal onlyInitializing { } function __AccessControl_init_unchained() internal onlyInitializing { } struct RoleData { mapping(address => bool) members; bytes32 adminRole; } mapping(bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with a standardized message including the required role. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ * * _Available since v4.1._ */ modifier onlyRole(bytes32 role) { _checkRole(role); _; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControlUpgradeable).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual override returns (bool) { return _roles[role].members[account]; } /** * @dev Revert with a standard message if `_msgSender()` is missing `role`. * Overriding this function changes the behavior of the {onlyRole} modifier. * * Format of the revert message is described in {_checkRole}. * * _Available since v4.6._ */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Revert with a standard message if `account` is missing `role`. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert( string( abi.encodePacked( "AccessControl: account ", StringsUpgradeable.toHexString(account), " is missing role ", StringsUpgradeable.toHexString(uint256(role), 32) ) ) ); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleGranted} event. */ function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleRevoked} event. */ function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address account) public virtual override { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * May emit a {RoleGranted} event. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== * * NOTE: This function is deprecated in favor of {_grantRole}. */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { bytes32 previousAdminRole = getRoleAdmin(role); _roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Grants `role` to `account`. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual { if (!hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, _msgSender()); } } /** * @dev Revokes `role` from `account`. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, _msgSender()); } } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControlUpgradeable { /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.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) || (!AddressUpgradeable.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 // 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 AddressUpgradeable { /** * @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); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165Upgradeable.sol"; import "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable { function __ERC165_init() internal onlyInitializing { } function __ERC165_init_unchained() internal onlyInitializing { } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165Upgradeable).interfaceId; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165Upgradeable { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library MathUpgradeable { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.0; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMathUpgradeable { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/MathUpgradeable.sol"; import "./math/SignedMathUpgradeable.sol"; /** * @dev String operations. */ library StringsUpgradeable { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = MathUpgradeable.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toString(int256 value) internal pure returns (string memory) { return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMathUpgradeable.abs(value)))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, MathUpgradeable.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev _Available since v3.1._ */ interface IERC1155Receiver is IERC165 { /** * @dev Handles the receipt of a single ERC1155 token type. This function is * called at the end of a `safeTransferFrom` after the balance has been updated. * * NOTE: To accept the transfer, this must return * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` * (i.e. 0xf23a6e61, or its own function selector). * * @param operator The address which initiated the transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param id The ID of the token being transferred * @param value The amount of tokens being transferred * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed */ function onERC1155Received( address operator, address from, uint256 id, uint256 value, bytes calldata data ) external returns (bytes4); /** * @dev Handles the receipt of a multiple ERC1155 token types. This function * is called at the end of a `safeBatchTransferFrom` after the balances have * been updated. * * NOTE: To accept the transfer(s), this must return * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` * (i.e. 0xbc197c81, or its own function selector). * * @param operator The address which initiated the batch transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param ids An array containing ids of each token being transferred (order and length must match values array) * @param values An array containing amounts of each token being transferred (order and length must match ids array) * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed */ function onERC1155BatchReceived( address operator, address from, uint256[] calldata ids, uint256[] calldata values, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/utils/ERC1155Holder.sol) pragma solidity ^0.8.0; import "./ERC1155Receiver.sol"; /** * Simple implementation of `ERC1155Receiver` that will allow a contract to hold ERC1155 tokens. * * IMPORTANT: When inheriting this contract, you must include a way to use the received tokens, otherwise they will be * stuck. * * @dev _Available since v3.1._ */ contract ERC1155Holder is ERC1155Receiver { function onERC1155Received( address, address, uint256, uint256, bytes memory ) public virtual override returns (bytes4) { return this.onERC1155Received.selector; } function onERC1155BatchReceived( address, address, uint256[] memory, uint256[] memory, bytes memory ) public virtual override returns (bytes4) { return this.onERC1155BatchReceived.selector; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC1155/utils/ERC1155Receiver.sol) pragma solidity ^0.8.0; import "../IERC1155Receiver.sol"; import "../../../utils/introspection/ERC165.sol"; /** * @dev _Available since v3.1._ */ abstract contract ERC1155Receiver is ERC165, IERC1155Receiver { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/utils/ERC721Holder.sol) pragma solidity ^0.8.0; import "../IERC721Receiver.sol"; /** * @dev Implementation of the {IERC721Receiver} interface. * * Accepts all token transfers. * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}. */ contract ERC721Holder is IERC721Receiver { /** * @dev See {IERC721Receiver-onERC721Received}. * * Always returns `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received(address, address, uint256, bytes memory) public virtual override returns (bytes4) { return this.onERC721Received.selector; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple ERC20 + EIP-2612 implementation. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC20.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol) /// /// @dev Note: /// The ERC20 standard allows minting and transferring to and from the zero address, /// minting and transferring zero tokens, as well as self-approvals. /// For performance, this implementation WILL NOT revert for such actions. /// Please add any checks with overrides if desired. abstract contract ERC20 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The total supply has overflowed. error TotalSupplyOverflow(); /// @dev The allowance has overflowed. error AllowanceOverflow(); /// @dev The allowance has underflowed. error AllowanceUnderflow(); /// @dev Insufficient balance. error InsufficientBalance(); /// @dev Insufficient allowance. error InsufficientAllowance(); /// @dev The permit is invalid. error InvalidPermit(); /// @dev The permit has expired. error PermitExpired(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Emitted when `amount` tokens is transferred from `from` to `to`. event Transfer(address indexed from, address indexed to, uint256 amount); /// @dev Emitted when `amount` tokens is approved by `owner` to be used by `spender`. event Approval(address indexed owner, address indexed spender, uint256 amount); /// @dev `keccak256(bytes("Transfer(address,address,uint256)"))`. uint256 private constant _TRANSFER_EVENT_SIGNATURE = 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef; /// @dev `keccak256(bytes("Approval(address,address,uint256)"))`. uint256 private constant _APPROVAL_EVENT_SIGNATURE = 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The storage slot for the total supply. uint256 private constant _TOTAL_SUPPLY_SLOT = 0x05345cdf77eb68f44c; /// @dev The balance slot of `owner` is given by: /// ``` /// mstore(0x0c, _BALANCE_SLOT_SEED) /// mstore(0x00, owner) /// let balanceSlot := keccak256(0x0c, 0x20) /// ``` uint256 private constant _BALANCE_SLOT_SEED = 0x87a211a2; /// @dev The allowance slot of (`owner`, `spender`) is given by: /// ``` /// mstore(0x20, spender) /// mstore(0x0c, _ALLOWANCE_SLOT_SEED) /// mstore(0x00, owner) /// let allowanceSlot := keccak256(0x0c, 0x34) /// ``` uint256 private constant _ALLOWANCE_SLOT_SEED = 0x7f5e9f20; /// @dev The nonce slot of `owner` is given by: /// ``` /// mstore(0x0c, _NONCES_SLOT_SEED) /// mstore(0x00, owner) /// let nonceSlot := keccak256(0x0c, 0x20) /// ``` uint256 private constant _NONCES_SLOT_SEED = 0x38377508; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC20 METADATA */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the name of the token. function name() public view virtual returns (string memory); /// @dev Returns the symbol of the token. function symbol() public view virtual returns (string memory); /// @dev Returns the decimals places of the token. function decimals() public view virtual returns (uint8) { return 18; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC20 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the amount of tokens in existence. function totalSupply() public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { result := sload(_TOTAL_SUPPLY_SLOT) } } /// @dev Returns the amount of tokens owned by `owner`. function balanceOf(address owner) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { mstore(0x0c, _BALANCE_SLOT_SEED) mstore(0x00, owner) result := sload(keccak256(0x0c, 0x20)) } } /// @dev Returns the amount of tokens that `spender` can spend on behalf of `owner`. function allowance(address owner, address spender) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { mstore(0x20, spender) mstore(0x0c, _ALLOWANCE_SLOT_SEED) mstore(0x00, owner) result := sload(keccak256(0x0c, 0x34)) } } /// @dev Sets `amount` as the allowance of `spender` over the caller's tokens. /// /// Emits a {Approval} event. function approve(address spender, uint256 amount) public virtual returns (bool) { /// @solidity memory-safe-assembly assembly { // Compute the allowance slot and store the amount. mstore(0x20, spender) mstore(0x0c, _ALLOWANCE_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x34), amount) // Emit the {Approval} event. mstore(0x00, amount) log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, caller(), shr(96, mload(0x2c))) } return true; } /// @dev Atomically increases the allowance granted to `spender` by the caller. /// /// Emits a {Approval} event. function increaseAllowance(address spender, uint256 difference) public virtual returns (bool) { /// @solidity memory-safe-assembly assembly { // Compute the allowance slot and load its value. mstore(0x20, spender) mstore(0x0c, _ALLOWANCE_SLOT_SEED) mstore(0x00, caller()) let allowanceSlot := keccak256(0x0c, 0x34) let allowanceBefore := sload(allowanceSlot) // Add to the allowance. let allowanceAfter := add(allowanceBefore, difference) // Revert upon overflow. if lt(allowanceAfter, allowanceBefore) { mstore(0x00, 0xf9067066) // `AllowanceOverflow()`. revert(0x1c, 0x04) } // Store the updated allowance. sstore(allowanceSlot, allowanceAfter) // Emit the {Approval} event. mstore(0x00, allowanceAfter) log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, caller(), shr(96, mload(0x2c))) } return true; } /// @dev Atomically decreases the allowance granted to `spender` by the caller. /// /// Emits a {Approval} event. function decreaseAllowance(address spender, uint256 difference) public virtual returns (bool) { /// @solidity memory-safe-assembly assembly { // Compute the allowance slot and load its value. mstore(0x20, spender) mstore(0x0c, _ALLOWANCE_SLOT_SEED) mstore(0x00, caller()) let allowanceSlot := keccak256(0x0c, 0x34) let allowanceBefore := sload(allowanceSlot) // Revert if will underflow. if lt(allowanceBefore, difference) { mstore(0x00, 0x8301ab38) // `AllowanceUnderflow()`. revert(0x1c, 0x04) } // Subtract and store the updated allowance. let allowanceAfter := sub(allowanceBefore, difference) sstore(allowanceSlot, allowanceAfter) // Emit the {Approval} event. mstore(0x00, allowanceAfter) log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, caller(), shr(96, mload(0x2c))) } return true; } /// @dev Transfer `amount` tokens from the caller to `to`. /// /// Requirements: /// - `from` must at least have `amount`. /// /// Emits a {Transfer} event. function transfer(address to, uint256 amount) public virtual returns (bool) { _beforeTokenTransfer(msg.sender, to, amount); /// @solidity memory-safe-assembly assembly { // Compute the balance slot and load its value. mstore(0x0c, _BALANCE_SLOT_SEED) mstore(0x00, caller()) let fromBalanceSlot := keccak256(0x0c, 0x20) let fromBalance := sload(fromBalanceSlot) // Revert if insufficient balance. if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } // Subtract and store the updated balance. sstore(fromBalanceSlot, sub(fromBalance, amount)) // Compute the balance slot of `to`. mstore(0x00, to) let toBalanceSlot := keccak256(0x0c, 0x20) // Add and store the updated balance of `to`. // Will not overflow because the sum of all user balances // cannot exceed the maximum uint256 value. sstore(toBalanceSlot, add(sload(toBalanceSlot), amount)) // Emit the {Transfer} event. mstore(0x20, amount) log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, caller(), shr(96, mload(0x0c))) } _afterTokenTransfer(msg.sender, to, amount); return true; } /// @dev Transfers `amount` tokens from `from` to `to`. /// /// Note: Does not update the allowance if it is the maximum uint256 value. /// /// Requirements: /// - `from` must at least have `amount`. /// - The caller must have at least `amount` of allowance to transfer the tokens of `from`. /// /// Emits a {Transfer} event. function transferFrom(address from, address to, uint256 amount) public virtual returns (bool) { _beforeTokenTransfer(from, to, amount); /// @solidity memory-safe-assembly assembly { let from_ := shl(96, from) // Compute the allowance slot and load its value. mstore(0x20, caller()) mstore(0x0c, or(from_, _ALLOWANCE_SLOT_SEED)) let allowanceSlot := keccak256(0x0c, 0x34) let allowance_ := sload(allowanceSlot) // If the allowance is not the maximum uint256 value. if iszero(eq(allowance_, not(0))) { // Revert if the amount to be transferred exceeds the allowance. if gt(amount, allowance_) { mstore(0x00, 0x13be252b) // `InsufficientAllowance()`. revert(0x1c, 0x04) } // Subtract and store the updated allowance. sstore(allowanceSlot, sub(allowance_, amount)) } // Compute the balance slot and load its value. mstore(0x0c, or(from_, _BALANCE_SLOT_SEED)) let fromBalanceSlot := keccak256(0x0c, 0x20) let fromBalance := sload(fromBalanceSlot) // Revert if insufficient balance. if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } // Subtract and store the updated balance. sstore(fromBalanceSlot, sub(fromBalance, amount)) // Compute the balance slot of `to`. mstore(0x00, to) let toBalanceSlot := keccak256(0x0c, 0x20) // Add and store the updated balance of `to`. // Will not overflow because the sum of all user balances // cannot exceed the maximum uint256 value. sstore(toBalanceSlot, add(sload(toBalanceSlot), amount)) // Emit the {Transfer} event. mstore(0x20, amount) log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, from_), shr(96, mload(0x0c))) } _afterTokenTransfer(from, to, amount); return true; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EIP-2612 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the current nonce for `owner`. /// This value is used to compute the signature for EIP-2612 permit. function nonces(address owner) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { // Compute the nonce slot and load its value. mstore(0x0c, _NONCES_SLOT_SEED) mstore(0x00, owner) result := sload(keccak256(0x0c, 0x20)) } } /// @dev Sets `value` as the allowance of `spender` over the tokens of `owner`, /// authorized by a signed approval by `owner`. /// /// Emits a {Approval} event. function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual { bytes32 domainSeparator = DOMAIN_SEPARATOR(); /// @solidity memory-safe-assembly assembly { // Grab the free memory pointer. let m := mload(0x40) // Revert if the block timestamp greater than `deadline`. if gt(timestamp(), deadline) { mstore(0x00, 0x1a15a3cc) // `PermitExpired()`. revert(0x1c, 0x04) } // Clean the upper 96 bits. owner := shr(96, shl(96, owner)) spender := shr(96, shl(96, spender)) // Compute the nonce slot and load its value. mstore(0x0c, _NONCES_SLOT_SEED) mstore(0x00, owner) let nonceSlot := keccak256(0x0c, 0x20) let nonceValue := sload(nonceSlot) // Increment and store the updated nonce. sstore(nonceSlot, add(nonceValue, 1)) // Prepare the inner hash. // `keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)")`. // forgefmt: disable-next-item mstore(m, 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9) mstore(add(m, 0x20), owner) mstore(add(m, 0x40), spender) mstore(add(m, 0x60), value) mstore(add(m, 0x80), nonceValue) mstore(add(m, 0xa0), deadline) // Prepare the outer hash. mstore(0, 0x1901) mstore(0x20, domainSeparator) mstore(0x40, keccak256(m, 0xc0)) // Prepare the ecrecover calldata. mstore(0, keccak256(0x1e, 0x42)) mstore(0x20, and(0xff, v)) mstore(0x40, r) mstore(0x60, s) pop(staticcall(gas(), 1, 0, 0x80, 0x20, 0x20)) // If the ecrecover fails, the returndatasize will be 0x00, // `owner` will be be checked if it equals the hash at 0x00, // which evaluates to false (i.e. 0), and we will revert. // If the ecrecover succeeds, the returndatasize will be 0x20, // `owner` will be compared against the returned address at 0x20. if iszero(eq(mload(returndatasize()), owner)) { mstore(0x00, 0xddafbaef) // `InvalidPermit()`. revert(0x1c, 0x04) } // Compute the allowance slot and store the value. // The `owner` is already at slot 0x20. mstore(0x40, or(shl(160, _ALLOWANCE_SLOT_SEED), spender)) sstore(keccak256(0x2c, 0x34), value) // Emit the {Approval} event. log3(add(m, 0x60), 0x20, _APPROVAL_EVENT_SIGNATURE, owner, spender) mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero pointer. } } /// @dev Returns the EIP-2612 domains separator. function DOMAIN_SEPARATOR() public view virtual returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) // Grab the free memory pointer. } // We simply calculate it on-the-fly to allow for cases where the `name` may change. bytes32 nameHash = keccak256(bytes(name())); /// @solidity memory-safe-assembly assembly { let m := result // `keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")`. // forgefmt: disable-next-item mstore(m, 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f) mstore(add(m, 0x20), nameHash) // `keccak256("1")`. // forgefmt: disable-next-item mstore(add(m, 0x40), 0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6) mstore(add(m, 0x60), chainid()) mstore(add(m, 0x80), address()) result := keccak256(m, 0xa0) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL MINT FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Mints `amount` tokens to `to`, increasing the total supply. /// /// Emits a {Transfer} event. function _mint(address to, uint256 amount) internal virtual { _beforeTokenTransfer(address(0), to, amount); /// @solidity memory-safe-assembly assembly { let totalSupplyBefore := sload(_TOTAL_SUPPLY_SLOT) let totalSupplyAfter := add(totalSupplyBefore, amount) // Revert if the total supply overflows. if lt(totalSupplyAfter, totalSupplyBefore) { mstore(0x00, 0xe5cfe957) // `TotalSupplyOverflow()`. revert(0x1c, 0x04) } // Store the updated total supply. sstore(_TOTAL_SUPPLY_SLOT, totalSupplyAfter) // Compute the balance slot and load its value. mstore(0x0c, _BALANCE_SLOT_SEED) mstore(0x00, to) let toBalanceSlot := keccak256(0x0c, 0x20) // Add and store the updated balance. sstore(toBalanceSlot, add(sload(toBalanceSlot), amount)) // Emit the {Transfer} event. mstore(0x20, amount) log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, 0, shr(96, mload(0x0c))) } _afterTokenTransfer(address(0), to, amount); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL BURN FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Burns `amount` tokens from `from`, reducing the total supply. /// /// Emits a {Transfer} event. function _burn(address from, uint256 amount) internal virtual { _beforeTokenTransfer(from, address(0), amount); /// @solidity memory-safe-assembly assembly { // Compute the balance slot and load its value. mstore(0x0c, _BALANCE_SLOT_SEED) mstore(0x00, from) let fromBalanceSlot := keccak256(0x0c, 0x20) let fromBalance := sload(fromBalanceSlot) // Revert if insufficient balance. if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } // Subtract and store the updated balance. sstore(fromBalanceSlot, sub(fromBalance, amount)) // Subtract and store the updated total supply. sstore(_TOTAL_SUPPLY_SLOT, sub(sload(_TOTAL_SUPPLY_SLOT), amount)) // Emit the {Transfer} event. mstore(0x00, amount) log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, shl(96, from)), 0) } _afterTokenTransfer(from, address(0), amount); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL TRANSFER FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Moves `amount` of tokens from `from` to `to`. function _transfer(address from, address to, uint256 amount) internal virtual { _beforeTokenTransfer(from, to, amount); /// @solidity memory-safe-assembly assembly { let from_ := shl(96, from) // Compute the balance slot and load its value. mstore(0x0c, or(from_, _BALANCE_SLOT_SEED)) let fromBalanceSlot := keccak256(0x0c, 0x20) let fromBalance := sload(fromBalanceSlot) // Revert if insufficient balance. if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } // Subtract and store the updated balance. sstore(fromBalanceSlot, sub(fromBalance, amount)) // Compute the balance slot of `to`. mstore(0x00, to) let toBalanceSlot := keccak256(0x0c, 0x20) // Add and store the updated balance of `to`. // Will not overflow because the sum of all user balances // cannot exceed the maximum uint256 value. sstore(toBalanceSlot, add(sload(toBalanceSlot), amount)) // Emit the {Transfer} event. mstore(0x20, amount) log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, from_), shr(96, mload(0x0c))) } _afterTokenTransfer(from, to, amount); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL ALLOWANCE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Updates the allowance of `owner` for `spender` based on spent `amount`. function _spendAllowance(address owner, address spender, uint256 amount) internal virtual { /// @solidity memory-safe-assembly assembly { // Compute the allowance slot and load its value. mstore(0x20, spender) mstore(0x0c, _ALLOWANCE_SLOT_SEED) mstore(0x00, owner) let allowanceSlot := keccak256(0x0c, 0x34) let allowance_ := sload(allowanceSlot) // If the allowance is not the maximum uint256 value. if iszero(eq(allowance_, not(0))) { // Revert if the amount to be transferred exceeds the allowance. if gt(amount, allowance_) { mstore(0x00, 0x13be252b) // `InsufficientAllowance()`. revert(0x1c, 0x04) } // Subtract and store the updated allowance. sstore(allowanceSlot, sub(allowance_, amount)) } } } /// @dev Sets `amount` as the allowance of `spender` over the tokens of `owner`. /// /// Emits a {Approval} event. function _approve(address owner, address spender, uint256 amount) internal virtual { /// @solidity memory-safe-assembly assembly { let owner_ := shl(96, owner) // Compute the allowance slot and store the amount. mstore(0x20, spender) mstore(0x0c, or(owner_, _ALLOWANCE_SLOT_SEED)) sstore(keccak256(0x0c, 0x34), amount) // Emit the {Approval} event. mstore(0x00, amount) log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, shr(96, owner_), shr(96, mload(0x2c))) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HOOKS TO OVERRIDE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Hook that is called before any transfer of tokens. /// This includes minting and burning. function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {} /// @dev Hook that is called after any transfer of tokens. /// This includes minting and burning. function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {} }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol) /// /// @dev Note: /// - For ETH transfers, please use `forceSafeTransferETH` for gas griefing protection. /// - For ERC20s, this implementation won't check that a token has code, /// responsibility is delegated to the caller. library SafeTransferLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ETH transfer has failed. error ETHTransferFailed(); /// @dev The ERC20 `transferFrom` has failed. error TransferFromFailed(); /// @dev The ERC20 `transfer` has failed. error TransferFailed(); /// @dev The ERC20 `approve` has failed. error ApproveFailed(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Suggested gas stipend for contract receiving ETH /// that disallows any storage writes. uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300; /// @dev Suggested gas stipend for contract receiving ETH to perform a few /// storage reads and writes, but low enough to prevent griefing. /// Multiply by a small constant (e.g. 2), if needed. uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ETH OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Sends `amount` (in wei) ETH to `to`. /// Reverts upon failure. /// /// Note: This implementation does NOT protect against gas griefing. /// Please use `forceSafeTransferETH` for gas griefing protection. function safeTransferETH(address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { // Transfer the ETH and check if it succeeded or not. if iszero(call(gas(), to, amount, 0x00, 0x00, 0x00, 0x00)) { // Store the function selector of `ETHTransferFailed()`. mstore(0x00, 0xb12d13eb) // Revert with (offset, size). revert(0x1c, 0x04) } } } /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`. /// The `gasStipend` can be set to a low enough value to prevent /// storage writes or gas griefing. /// /// If sending via the normal procedure fails, force sends the ETH by /// creating a temporary contract which uses `SELFDESTRUCT` to force send the ETH. /// /// Reverts if the current contract has insufficient balance. function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal { /// @solidity memory-safe-assembly assembly { // If insufficient balance, revert. if lt(selfbalance(), amount) { // Store the function selector of `ETHTransferFailed()`. mstore(0x00, 0xb12d13eb) // Revert with (offset, size). revert(0x1c, 0x04) } // Transfer the ETH and check if it succeeded or not. if iszero(call(gasStipend, to, amount, 0x00, 0x00, 0x00, 0x00)) { mstore(0x00, to) // Store the address in scratch space. mstore8(0x0b, 0x73) // Opcode `PUSH20`. mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`. // We can directly use `SELFDESTRUCT` in the contract creation. // Compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758 if iszero(create(amount, 0x0b, 0x16)) { // To coerce gas estimation to provide enough gas for the `create` above. if iszero(gt(gas(), 1000000)) { revert(0x00, 0x00) } } } } } /// @dev Force sends `amount` (in wei) ETH to `to`, with a gas stipend /// equal to `GAS_STIPEND_NO_GRIEF`. This gas stipend is a reasonable default /// for 99% of cases and can be overridden with the three-argument version of this /// function if necessary. /// /// If sending via the normal procedure fails, force sends the ETH by /// creating a temporary contract which uses `SELFDESTRUCT` to force send the ETH. /// /// Reverts if the current contract has insufficient balance. function forceSafeTransferETH(address to, uint256 amount) internal { // Manually inlined because the compiler doesn't inline functions with branches. /// @solidity memory-safe-assembly assembly { // If insufficient balance, revert. if lt(selfbalance(), amount) { // Store the function selector of `ETHTransferFailed()`. mstore(0x00, 0xb12d13eb) // Revert with (offset, size). revert(0x1c, 0x04) } // Transfer the ETH and check if it succeeded or not. if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, 0x00, 0x00, 0x00, 0x00)) { mstore(0x00, to) // Store the address in scratch space. mstore8(0x0b, 0x73) // Opcode `PUSH20`. mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`. // We can directly use `SELFDESTRUCT` in the contract creation. // Compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758 if iszero(create(amount, 0x0b, 0x16)) { // To coerce gas estimation to provide enough gas for the `create` above. if iszero(gt(gas(), 1000000)) { revert(0x00, 0x00) } } } } } /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`. /// The `gasStipend` can be set to a low enough value to prevent /// storage writes or gas griefing. /// /// Simply use `gasleft()` for `gasStipend` if you don't need a gas stipend. /// /// Note: Does NOT revert upon failure. /// Returns whether the transfer of ETH is successful instead. function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal returns (bool success) { /// @solidity memory-safe-assembly assembly { // Transfer the ETH and check if it succeeded or not. success := call(gasStipend, to, amount, 0x00, 0x00, 0x00, 0x00) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC20 OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Sends `amount` of ERC20 `token` from `from` to `to`. /// Reverts upon failure. /// /// The `from` account must have at least `amount` approved for /// the current contract to manage. function safeTransferFrom(address token, address from, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, amount) // Store the `amount` argument. mstore(0x40, to) // Store the `to` argument. mstore(0x2c, shl(96, from)) // Store the `from` argument. // Store the function selector of `transferFrom(address,address,uint256)`. mstore(0x0c, 0x23b872dd000000000000000000000000) if iszero( and( // The arguments of `and` are evaluated from right to left. // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20) ) ) { // Store the function selector of `TransferFromFailed()`. mstore(0x00, 0x7939f424) // Revert with (offset, size). revert(0x1c, 0x04) } mstore(0x60, 0) // Restore the zero slot to zero. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Sends all of ERC20 `token` from `from` to `to`. /// Reverts upon failure. /// /// The `from` account must have their entire balance approved for /// the current contract to manage. function safeTransferAllFrom(address token, address from, address to) internal returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x40, to) // Store the `to` argument. mstore(0x2c, shl(96, from)) // Store the `from` argument. // Store the function selector of `balanceOf(address)`. mstore(0x0c, 0x70a08231000000000000000000000000) if iszero( and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20) ) ) { // Store the function selector of `TransferFromFailed()`. mstore(0x00, 0x7939f424) // Revert with (offset, size). revert(0x1c, 0x04) } // Store the function selector of `transferFrom(address,address,uint256)`. mstore(0x00, 0x23b872dd) // The `amount` is already at 0x60. Load it for the function's return value. amount := mload(0x60) if iszero( and( // The arguments of `and` are evaluated from right to left. // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20) ) ) { // Store the function selector of `TransferFromFailed()`. mstore(0x00, 0x7939f424) // Revert with (offset, size). revert(0x1c, 0x04) } mstore(0x60, 0) // Restore the zero slot to zero. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`. /// Reverts upon failure. function safeTransfer(address token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { mstore(0x14, to) // Store the `to` argument. mstore(0x34, amount) // Store the `amount` argument. // Store the function selector of `transfer(address,uint256)`. mstore(0x00, 0xa9059cbb000000000000000000000000) if iszero( and( // The arguments of `and` are evaluated from right to left. // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { // Store the function selector of `TransferFailed()`. mstore(0x00, 0x90b8ec18) // Revert with (offset, size). revert(0x1c, 0x04) } // Restore the part of the free memory pointer that was overwritten. mstore(0x34, 0) } } /// @dev Sends all of ERC20 `token` from the current contract to `to`. /// Reverts upon failure. function safeTransferAll(address token, address to) internal returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`. mstore(0x20, address()) // Store the address of the current contract. if iszero( and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20) ) ) { // Store the function selector of `TransferFailed()`. mstore(0x00, 0x90b8ec18) // Revert with (offset, size). revert(0x1c, 0x04) } mstore(0x14, to) // Store the `to` argument. // The `amount` is already at 0x34. Load it for the function's return value. amount := mload(0x34) // Store the function selector of `transfer(address,uint256)`. mstore(0x00, 0xa9059cbb000000000000000000000000) if iszero( and( // The arguments of `and` are evaluated from right to left. // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { // Store the function selector of `TransferFailed()`. mstore(0x00, 0x90b8ec18) // Revert with (offset, size). revert(0x1c, 0x04) } // Restore the part of the free memory pointer that was overwritten. mstore(0x34, 0) } } /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract. /// Reverts upon failure. function safeApprove(address token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { mstore(0x14, to) // Store the `to` argument. mstore(0x34, amount) // Store the `amount` argument. // Store the function selector of `approve(address,uint256)`. mstore(0x00, 0x095ea7b3000000000000000000000000) if iszero( and( // The arguments of `and` are evaluated from right to left. // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { // Store the function selector of `ApproveFailed()`. mstore(0x00, 0x3e3f8f73) // Revert with (offset, size). revert(0x1c, 0x04) } // Restore the part of the free memory pointer that was overwritten. mstore(0x34, 0) } } /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract. /// If the initial attempt to approve fails, attempts to reset the approved amount to zero, /// then retries the approval again (some tokens, e.g. USDT, requires this). /// Reverts upon failure. function safeApproveWithRetry(address token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { mstore(0x14, to) // Store the `to` argument. mstore(0x34, amount) // Store the `amount` argument. // Store the function selector of `approve(address,uint256)`. mstore(0x00, 0x095ea7b3000000000000000000000000) if iszero( and( // The arguments of `and` are evaluated from right to left. // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { mstore(0x34, 0) // Store 0 for the `amount`. mstore(0x00, 0x095ea7b3000000000000000000000000) // Store the function selector. // We can ignore the result of this call. Just need to check the next call. pop(call(gas(), token, 0, 0x10, 0x44, 0x00, 0x00)) mstore(0x34, amount) // Store back the original `amount`. if iszero( and( or(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { // Store the function selector of `ApproveFailed()`. mstore(0x00, 0x3e3f8f73) // Revert with (offset, size). revert(0x1c, 0x04) } } // Restore the part of the free memory pointer that was overwritten. mstore(0x34, 0) } } /// @dev Returns the amount of ERC20 `token` owned by `account`. /// Returns zero if the `token` does not exist. function balanceOf(address token, address account) internal view returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { mstore(0x14, account) // Store the `account` argument. // Store the function selector of `balanceOf(address)`. mstore(0x00, 0x70a08231000000000000000000000000) amount := mul( mload(0x20), and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20) ) ) } } }
{ "optimizer": { "enabled": true, "runs": 400 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
[{"inputs":[],"name":"ALLOCATION_ACTIVE","type":"error"},{"inputs":[],"name":"ALLOCATION_NOT_ACTIVE","type":"error"},{"inputs":[],"name":"ALLOCATION_NOT_ENDED","type":"error"},{"inputs":[],"name":"ALREADY_INITIALIZED","type":"error"},{"inputs":[],"name":"AMOUNT_MISMATCH","type":"error"},{"inputs":[],"name":"ANCHOR_ERROR","type":"error"},{"inputs":[],"name":"ARRAY_MISMATCH","type":"error"},{"inputs":[],"name":"INVALID","type":"error"},{"inputs":[],"name":"INVALID_ADDRESS","type":"error"},{"inputs":[],"name":"INVALID_FEE","type":"error"},{"inputs":[],"name":"INVALID_METADATA","type":"error"},{"inputs":[],"name":"INVALID_REGISTRATION","type":"error"},{"inputs":[],"name":"IS_APPROVED_STRATEGY","type":"error"},{"inputs":[],"name":"MISMATCH","type":"error"},{"inputs":[],"name":"NONCE_NOT_AVAILABLE","type":"error"},{"inputs":[],"name":"NOT_APPROVED_STRATEGY","type":"error"},{"inputs":[],"name":"NOT_ENOUGH_FUNDS","type":"error"},{"inputs":[],"name":"NOT_IMPLEMENTED","type":"error"},{"inputs":[],"name":"NOT_INITIALIZED","type":"error"},{"inputs":[],"name":"NOT_PENDING_OWNER","type":"error"},{"inputs":[],"name":"POOL_ACTIVE","type":"error"},{"inputs":[],"name":"POOL_INACTIVE","type":"error"},{"inputs":[],"name":"RECIPIENT_ALREADY_ACCEPTED","type":"error"},{"inputs":[{"internalType":"address","name":"recipientId","type":"address"}],"name":"RECIPIENT_ERROR","type":"error"},{"inputs":[],"name":"RECIPIENT_NOT_ACCEPTED","type":"error"},{"inputs":[],"name":"REGISTRATION_ACTIVE","type":"error"},{"inputs":[],"name":"REGISTRATION_NOT_ACTIVE","type":"error"},{"inputs":[],"name":"UNAUTHORIZED","type":"error"},{"inputs":[],"name":"ZERO_ADDRESS","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"profileId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"components":[{"internalType":"uint256","name":"protocol","type":"uint256"},{"internalType":"string","name":"pointer","type":"string"}],"indexed":false,"internalType":"struct Metadata","name":"metadata","type":"tuple"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"address","name":"anchor","type":"address"}],"name":"ProfileCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"profileId","type":"bytes32"},{"components":[{"internalType":"uint256","name":"protocol","type":"uint256"},{"internalType":"string","name":"pointer","type":"string"}],"indexed":false,"internalType":"struct Metadata","name":"metadata","type":"tuple"}],"name":"ProfileMetadataUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"profileId","type":"bytes32"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"address","name":"anchor","type":"address"}],"name":"ProfileNameUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"profileId","type":"bytes32"},{"indexed":false,"internalType":"address","name":"owner","type":"address"}],"name":"ProfileOwnerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"profileId","type":"bytes32"},{"indexed":false,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ProfilePendingOwnerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"ALLO_OWNER","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NATIVE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_profileId","type":"bytes32"}],"name":"acceptProfileOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_profileId","type":"bytes32"},{"internalType":"address[]","name":"_members","type":"address[]"}],"name":"addMembers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"anchorToProfileId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nonce","type":"uint256"},{"internalType":"string","name":"_name","type":"string"},{"components":[{"internalType":"uint256","name":"protocol","type":"uint256"},{"internalType":"string","name":"pointer","type":"string"}],"internalType":"struct Metadata","name":"_metadata","type":"tuple"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address[]","name":"_members","type":"address[]"}],"name":"createProfile","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_anchor","type":"address"}],"name":"getProfileByAnchor","outputs":[{"components":[{"internalType":"bytes32","name":"id","type":"bytes32"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"string","name":"name","type":"string"},{"components":[{"internalType":"uint256","name":"protocol","type":"uint256"},{"internalType":"string","name":"pointer","type":"string"}],"internalType":"struct Metadata","name":"metadata","type":"tuple"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"anchor","type":"address"}],"internalType":"struct IRegistry.Profile","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_profileId","type":"bytes32"}],"name":"getProfileById","outputs":[{"components":[{"internalType":"bytes32","name":"id","type":"bytes32"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"string","name":"name","type":"string"},{"components":[{"internalType":"uint256","name":"protocol","type":"uint256"},{"internalType":"string","name":"pointer","type":"string"}],"internalType":"struct Metadata","name":"metadata","type":"tuple"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"anchor","type":"address"}],"internalType":"struct IRegistry.Profile","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_profileId","type":"bytes32"},{"internalType":"address","name":"_member","type":"address"}],"name":"isMemberOfProfile","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_profileId","type":"bytes32"},{"internalType":"address","name":"_owner","type":"address"}],"name":"isOwnerOfProfile","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_profileId","type":"bytes32"},{"internalType":"address","name":"_account","type":"address"}],"name":"isOwnerOrMemberOfProfile","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"profileIdToPendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"profilesById","outputs":[{"internalType":"bytes32","name":"id","type":"bytes32"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"string","name":"name","type":"string"},{"components":[{"internalType":"uint256","name":"protocol","type":"uint256"},{"internalType":"string","name":"pointer","type":"string"}],"internalType":"struct Metadata","name":"metadata","type":"tuple"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"anchor","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"recoverFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_profileId","type":"bytes32"},{"internalType":"address[]","name":"_members","type":"address[]"}],"name":"removeMembers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_profileId","type":"bytes32"},{"components":[{"internalType":"uint256","name":"protocol","type":"uint256"},{"internalType":"string","name":"pointer","type":"string"}],"internalType":"struct Metadata","name":"_metadata","type":"tuple"}],"name":"updateProfileMetadata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_profileId","type":"bytes32"},{"internalType":"string","name":"_name","type":"string"}],"name":"updateProfileName","outputs":[{"internalType":"address","name":"anchor","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_profileId","type":"bytes32"},{"internalType":"address","name":"_pendingOwner","type":"address"}],"name":"updateProfilePendingOwner","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50612c4f806100206000396000f3fe60806040523480156200001157600080fd5b5060043610620001d15760003560e01c806350d005e01162000101578063c4d66de811620000a3578063d547741f116200007a578063d547741f1462000480578063dd93da431462000497578063e0cf1e4c14620004ae578063ee88819614620004c557600080fd5b8063c4d66de8146200042a578063cf189ff21462000441578063cfda7e0a146200045857600080fd5b8063a0cf0aea11620000d8578063a0cf0aea14620003ee578063a217fddf146200040a578063ac402839146200041357600080fd5b806350d005e014620003565780635e8a7915146200039b57806391d1485414620003b257600080fd5b80632f2ff15d11620001775780633a92f65f116200014e5780633a92f65f14620002ee5780633b66dacd14620003055780634756487f146200031c5780635063f361146200033f57600080fd5b80632f2ff15d14620002a957806336568abe14620002c057806339b86b8c14620002d757600080fd5b8063248a9ca311620001ac578063248a9ca314620002445780632497f3c6146200027957806324ae6a27146200029257600080fd5b80630114cf0a14620001d657806301ffc9a714620002055780630ec1fbac146200022d575b600080fd5b620001ed620001e736600462001aa0565b620004f0565b604051620001fc919062001b37565b60405180910390f35b6200021c6200021636600462001bb8565b620006a7565b6040519015158152602001620001fc565b6200021c6200023e36600462001c01565b620006df565b6200026a6200025536600462001aa0565b60009081526065602052604090206001015490565b604051908152602001620001fc565b620002906200028a36600462001aa0565b620006f4565b005b62000290620002a336600462001c30565b620007ad565b62000290620002ba36600462001c01565b620008b0565b62000290620002d136600462001c01565b620008de565b6200021c620002e836600462001c01565b62000964565b6200026a620002ff36600462001e28565b6200098a565b620002906200031636600462001c01565b62000c15565b6200026a6200032d36600462001ed7565b60976020526000908152604090205481565b620002906200035036600462001ef5565b62000c7f565b620003826200036736600462001aa0565b6099602052600090815260409020546001600160a01b031681565b6040516001600160a01b039091168152602001620001fc565b6200021c620003ac36600462001c01565b62000d0b565b6200021c620003c336600462001c01565b60009182526065602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6200038273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b6200026a600081565b620002906200042436600462001f40565b62000d3e565b620002906200043b36600462001ed7565b62000db1565b620003826200045236600462001f81565b62000ee6565b6200026a7f815b5a78dc333d344c7df9da23c04dbd432015cc701876ddb9ffe850e688274781565b620002906200049136600462001c01565b62000fa7565b620001ed620004a836600462001ed7565b62000fd0565b62000290620004bf36600462001ef5565b62001199565b620004dc620004d636600462001aa0565b620011e4565b604051620001fc9695949392919062001fc2565b620004fa62001a3d565b609860008381526020019081526020016000206040518060c001604052908160008201548152602001600182015481526020016002820180546200053e906200201e565b80601f01602080910402602001604051908101604052809291908181526020018280546200056c906200201e565b8015620005bd5780601f106200059157610100808354040283529160200191620005bd565b820191906000526020600020905b8154815290600101906020018083116200059f57829003601f168201915b505050505081526020016003820160405180604001604052908160008201548152602001600182018054620005f2906200201e565b80601f016020809104026020016040519081016040528092919081815260200182805462000620906200201e565b8015620006715780601f10620006455761010080835404028352916020019162000671565b820191906000526020600020905b8154815290600101906020018083116200065357829003601f168201915b50505091909252505050815260058201546001600160a01b03908116602083015260069092015490911660409091015292915050565b60006001600160e01b03198216637965db0b60e01b1480620006d957506301ffc9a760e01b6001600160e01b03198316145b92915050565b6000620006ed838362001364565b9392505050565b60008181526098602090815260408083206099909252909120546001600160a01b03163381146200073857604051630b4d48c160e41b815260040160405180910390fd5b6005820180546001600160a01b038381166001600160a01b03199283161783556000868152609960209081526040918290208054909416909355925492519216825284917ffd9ad63830df7bdf1586c8293dc88a30864cb43e9037e7afdb2c7210facf217d91015b60405180910390a2505050565b7f815b5a78dc333d344c7df9da23c04dbd432015cc701876ddb9ffe850e6882747620007d98162001390565b6001600160a01b038216620008015760405163538ba4f960e01b815260040160405180910390fd5b60006001600160a01b03841673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1462000899576040516370a0823160e01b81523060048201526001600160a01b038516906370a0823190602401602060405180830381865afa1580156200086d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200089391906200205a565b6200089b565b475b9050620008aa8484836200139f565b50505050565b600082815260656020526040902060010154620008cd8162001390565b620008d98383620013de565b505050565b6001600160a01b0381163314620009545760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b62000960828262001482565b5050565b6000828152609860205260408120600501546001600160a01b03838116911614620006ed565b60008062000999878562001506565b6000818152609860205260409020600601549091506001600160a01b031615620009d657604051630527e05960e41b815260040160405180910390fd5b6001600160a01b038416620009fe5760405163538ba4f960e01b815260040160405180910390fd5b60006040518060c00160405280838152602001898152602001888152602001878152602001866001600160a01b0316815260200162000a3e848a62001555565b6001600160a01b0316905260008381526098602090815260409182902083518155908301516001820155908201519192508291600282019062000a829082620020c6565b5060608201518051600383019081556020820151600484019062000aa79082620020c6565b50505060808201516005820180546001600160a01b03199081166001600160a01b039384161790915560a0938401516006909301805490911692821692909217909155908201511660009081526097602052604090208290558351801580159062000b1b57506001600160a01b0386163314155b1562000b3a5760405163075fd2b160e01b815260040160405180910390fd5b60005b8181101562000bb157600086828151811062000b5d5762000b5d62002193565b6020026020010151905060006001600160a01b0316816001600160a01b03160362000b9b5760405163538ba4f960e01b815260040160405180910390fd5b62000ba78582620013de565b5060010162000b3d565b50827f1e28352ff00d67474b59b87e6817d6ba65daa0130446266db8640214d8b8060983602001518460400151856060015186608001518760a0015160405162000c00959493929190620021a9565b60405180910390a25090979650505050505050565b8162000c21816200174a565b60008381526099602090815260409182902080546001600160a01b0319166001600160a01b038616908117909155915191825284917f21fe5cd61055ef88f636a264885b927f3ec2b380b6053a6b4a7495a6336a95c89101620007a0565b8162000c8b816200174a565b815160005b8181101562000d0457600084828151811062000cb05762000cb062002193565b6020026020010151905060006001600160a01b0316816001600160a01b03160362000cee5760405163538ba4f960e01b815260040160405180910390fd5b62000cfa8682620013de565b5060010162000c90565b5050505050565b6000828152609860205260408120600501546001600160a01b0383811691161480620006ed5750620006ed838362001364565b8162000d4a816200174a565b6000838152609860209081526040909120835160038201908155918401518492916004019062000d7b9082620020c6565b50905050827fa366054a574e4f861cb295fd23b5440c5119c1ba329c36f5dfeb5643537cb0f383604051620007a09190620021fe565b600054600190610100900460ff1615801562000dd4575060005460ff8083169116105b62000e395760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016200094b565b6000805461ffff191660ff8316176101001790556001600160a01b03821662000e755760405163538ba4f960e01b815260040160405180910390fd5b62000ea17f815b5a78dc333d344c7df9da23c04dbd432015cc701876ddb9ffe850e688274783620013de565b6000805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b60008262000ef4816200174a565b62000f00848462001555565b60008581526098602052604090209092506002810162000f218582620020c6565b506006810180546001600160a01b0390811660009081526097602052604080822082905583546001600160a01b0319169287169283179093559081528190208690555185907f54cd733148631b9ff1cb945f2d0dcd33c0692e154763bfa2f35e2d10a76c432f9062000f97908790879062002213565b60405180910390a2505092915050565b60008281526065602052604090206001015462000fc48162001390565b620008d9838362001482565b62000fda62001a3d565b6001600160a01b0382166000908152609760209081526040808320548084526098835292819020815160c0810183528154815260018201549381019390935260028101805491928401916200102f906200201e565b80601f01602080910402602001604051908101604052809291908181526020018280546200105d906200201e565b8015620010ae5780601f106200108257610100808354040283529160200191620010ae565b820191906000526020600020905b8154815290600101906020018083116200109057829003601f168201915b505050505081526020016003820160405180604001604052908160008201548152602001600182018054620010e3906200201e565b80601f016020809104026020016040519081016040528092919081815260200182805462001111906200201e565b8015620011625780601f10620011365761010080835404028352916020019162001162565b820191906000526020600020905b8154815290600101906020018083116200114457829003601f168201915b50505091909252505050815260058201546001600160a01b0390811660208301526006909201549091166040909101529392505050565b81620011a5816200174a565b815160005b8181101562000d0457620011db85858381518110620011cd57620011cd62002193565b602002602001015162001482565b600101620011aa565b609860205260009081526040902080546001820154600283018054929391926200120e906200201e565b80601f01602080910402602001604051908101604052809291908181526020018280546200123c906200201e565b80156200128d5780601f1062001261576101008083540402835291602001916200128d565b820191906000526020600020905b8154815290600101906020018083116200126f57829003601f168201915b5050505050908060030160405180604001604052908160008201548152602001600182018054620012be906200201e565b80601f0160208091040260200160405190810160405280929190818152602001828054620012ec906200201e565b80156200133d5780601f1062001311576101008083540402835291602001916200133d565b820191906000526020600020905b8154815290600101906020018083116200131f57829003601f168201915b50505091909252505050600582015460069092015490916001600160a01b03908116911686565b60008281526065602090815260408083206001600160a01b038516845290915281205460ff16620006ed565b6200139c813362001785565b50565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03841601620013d157620008d9828262001803565b620008d983838362001820565b60008281526065602090815260408083206001600160a01b038516845290915290205460ff16620009605760008281526065602090815260408083206001600160a01b03851684529091529020805460ff191660011790556200143e3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b60008281526065602090815260408083206001600160a01b038516845290915290205460ff1615620009605760008281526065602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b600082826040516020016200153792919091825260601b6bffffffffffffffffffffffff1916602082015260340190565b60405160208183030381529060405280519060200120905092915050565b60008083836040516020016200156d92919062002240565b60408051808303601f1901815282825260208301879052308383015281518084038301815260608401928390529093509160009190620015b09060800162001a92565b601f1982820381018352601f909101166040819052620015d6919084906020016200225b565b60408051601f198184030181529082905284516020868101919091208251828401207fff00000000000000000000000000000000000000000000000000000000000000928501929092526bffffffffffffffffffffffff193060601b166021850152603584018190526055840191909152909250906000906075016040516020818303038152906040528051906020012060001c90508188306040516200167d9062001a92565b9182526001600160a01b031660208201526040018190604051809103906000f590508015620016a95760015b6200173c5787816001600160a01b03166308386eba6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620016ee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200171491906200205a565b146200173357604051630113b81f60e41b815260040160405180910390fd5b8095506200173f565b95505b505050505092915050565b6000818152609860205260409020600501546001600160a01b031633146200139c5760405163075fd2b160e01b815260040160405180910390fd5b60008281526065602090815260408083206001600160a01b038516845290915290205460ff166200096057620017bb8162001870565b620017c883602062001883565b604051602001620017db9291906200228e565b60408051601f198184030181529082905262461bcd60e51b82526200094b9160040162002313565b60008060008084865af1620009605763b12d13eb6000526004601cfd5b81601452806034526fa9059cbb00000000000000000000000060005260206000604460106000875af13d15600160005114171662001866576390b8ec186000526004601cfd5b6000603452505050565b6060620006d96001600160a01b03831660145b60606000620018948360026200233e565b620018a190600262002358565b67ffffffffffffffff811115620018bc57620018bc62001c5f565b6040519080825280601f01601f191660200182016040528015620018e7576020820181803683370190505b509050600360fc1b8160008151811062001905576200190562002193565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811062001937576200193762002193565b60200101906001600160f81b031916908160001a90535060006200195d8460026200233e565b6200196a90600162002358565b90505b6001811115620019ec576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110620019a257620019a262002193565b1a60f81b828281518110620019bb57620019bb62002193565b60200101906001600160f81b031916908160001a90535060049490941c93620019e4816200236e565b90506200196d565b508315620006ed5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016200094b565b6040518060c0016040528060008019168152602001600081526020016060815260200162001a7e604051806040016040528060008152602001606081525090565b815260006020820181905260409091015290565b610891806200238983390190565b60006020828403121562001ab357600080fd5b5035919050565b60005b8381101562001ad757818101518382015260200162001abd565b50506000910152565b6000815180845262001afa81602086016020860162001aba565b601f01601f19169290920160200192915050565b80518252600060208201516040602085015262001b2f604085018262001ae0565b949350505050565b6020815281516020820152602082015160408201526000604083015160c0606084015262001b6960e084018262001ae0565b90506060840151601f1984830301608085015262001b88828262001b0e565b91505060808401516001600160a01b0380821660a08601528060a08701511660c086015250508091505092915050565b60006020828403121562001bcb57600080fd5b81356001600160e01b031981168114620006ed57600080fd5b80356001600160a01b038116811462001bfc57600080fd5b919050565b6000806040838503121562001c1557600080fd5b8235915062001c276020840162001be4565b90509250929050565b6000806040838503121562001c4457600080fd5b62001c4f8362001be4565b915062001c276020840162001be4565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171562001ca15762001ca162001c5f565b604052919050565b600082601f83011262001cbb57600080fd5b813567ffffffffffffffff81111562001cd85762001cd862001c5f565b62001ced601f8201601f191660200162001c75565b81815284602083860101111562001d0357600080fd5b816020850160208301376000918101602001919091529392505050565b60006040828403121562001d3357600080fd5b6040516040810167ffffffffffffffff828210818311171562001d5a5762001d5a62001c5f565b8160405282935084358352602085013591508082111562001d7a57600080fd5b5062001d898582860162001ca9565b6020830152505092915050565b600082601f83011262001da857600080fd5b8135602067ffffffffffffffff82111562001dc75762001dc762001c5f565b8160051b62001dd882820162001c75565b928352848101820192828101908785111562001df357600080fd5b83870192505b8483101562001e1d5762001e0d8362001be4565b8252918301919083019062001df9565b979650505050505050565b600080600080600060a0868803121562001e4157600080fd5b85359450602086013567ffffffffffffffff8082111562001e6157600080fd5b62001e6f89838a0162001ca9565b9550604088013591508082111562001e8657600080fd5b62001e9489838a0162001d20565b945062001ea46060890162001be4565b9350608088013591508082111562001ebb57600080fd5b5062001eca8882890162001d96565b9150509295509295909350565b60006020828403121562001eea57600080fd5b620006ed8262001be4565b6000806040838503121562001f0957600080fd5b82359150602083013567ffffffffffffffff81111562001f2857600080fd5b62001f368582860162001d96565b9150509250929050565b6000806040838503121562001f5457600080fd5b82359150602083013567ffffffffffffffff81111562001f7357600080fd5b62001f368582860162001d20565b6000806040838503121562001f9557600080fd5b82359150602083013567ffffffffffffffff81111562001fb457600080fd5b62001f368582860162001ca9565b86815285602082015260c06040820152600062001fe360c083018762001ae0565b828103606084015262001ff7818762001b0e565b9150506001600160a01b03808516608084015280841660a084015250979650505050505050565b600181811c908216806200203357607f821691505b6020821081036200205457634e487b7160e01b600052602260045260246000fd5b50919050565b6000602082840312156200206d57600080fd5b5051919050565b601f821115620008d957600081815260208120601f850160051c810160208610156200209d5750805b601f850160051c820191505b81811015620020be57828155600101620020a9565b505050505050565b815167ffffffffffffffff811115620020e357620020e362001c5f565b620020fb81620020f484546200201e565b8462002074565b602080601f8311600181146200213357600084156200211a5750858301515b600019600386901b1c1916600185901b178555620020be565b600085815260208120601f198616915b82811015620021645788860151825594840194600190910190840162002143565b5085821015620021835787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052603260045260246000fd5b85815260a060208201526000620021c460a083018762001ae0565b8281036040840152620021d8818762001b0e565b9150506001600160a01b0380851660608401528084166080840152509695505050505050565b602081526000620006ed602083018462001b0e565b60408152600062002228604083018562001ae0565b90506001600160a01b03831660208301529392505050565b82815260406020820152600062001b2f604083018462001ae0565b600083516200226f81846020880162001aba565b8351908301906200228581836020880162001aba565b01949350505050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351620022c881601785016020880162001aba565b7f206973206d697373696e6720726f6c652000000000000000000000000000000060179184019182015283516200230781602884016020880162001aba565b01602801949350505050565b602081526000620006ed602083018462001ae0565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417620006d957620006d962002328565b80820180821115620006d957620006d962002328565b60008162002380576200238062002328565b50600019019056fe60c060405234801561001057600080fd5b5060405161089138038061089183398101604081905261002f91610043565b6001600160a01b031660805260a052610080565b6000806040838503121561005657600080fd5b825160208401519092506001600160a01b038116811461007557600080fd5b809150509250929050565b60805160a0516107df6100b26000396000818160c7015261025201526000818161014d015261028101526107df6000f3fe6080604052600436106100745760003560e01c80637b1039991161004e5780637b1039991461013b578063b61d27f614610187578063bc197c81146101b4578063f23a6e61146101e057600080fd5b806301ffc9a71461008057806308386eba146100b5578063150b7a02146100f757600080fd5b3661007b57005b600080fd5b34801561008c57600080fd5b506100a061009b3660046103c2565b61020c565b60405190151581526020015b60405180910390f35b3480156100c157600080fd5b506100e97f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020016100ac565b34801561010357600080fd5b506101226101123660046104c6565b630a85bd0160e11b949350505050565b6040516001600160e01b031990911681526020016100ac565b34801561014757600080fd5b5061016f7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100ac565b34801561019357600080fd5b506101a76101a236600461052e565b610243565b6040516100ac91906105a9565b3480156101c057600080fd5b506101226101cf36600461065c565b63bc197c8160e01b95945050505050565b3480156101ec57600080fd5b506101226101fb366004610706565b63f23a6e6160e01b95945050505050565b60006001600160e01b03198216630271189760e51b148061023d57506301ffc9a760e01b6001600160e01b03198316145b92915050565b604051630e6e1ae360e21b81527f000000000000000000000000000000000000000000000000000000000000000060048201523360248201526060907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906339b86b8c90604401602060405180830381865afa1580156102d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102f4919061076b565b6103115760405163075fd2b160e01b815260040160405180910390fd5b6001600160a01b038416610338576040516384aed38d60e01b815260040160405180910390fd5b600080856001600160a01b03168585604051610354919061078d565b60006040518083038185875af1925050503d8060008114610391576040519150601f19603f3d011682016040523d82523d6000602084013e610396565b606091505b5091509150816103b9576040516384aed38d60e01b815260040160405180910390fd5b95945050505050565b6000602082840312156103d457600080fd5b81356001600160e01b0319811681146103ec57600080fd5b9392505050565b80356001600160a01b038116811461040a57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561044e5761044e61040f565b604052919050565b600082601f83011261046757600080fd5b813567ffffffffffffffff8111156104815761048161040f565b610494601f8201601f1916602001610425565b8181528460208386010111156104a957600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080608085870312156104dc57600080fd5b6104e5856103f3565b93506104f3602086016103f3565b925060408501359150606085013567ffffffffffffffff81111561051657600080fd5b61052287828801610456565b91505092959194509250565b60008060006060848603121561054357600080fd5b61054c846103f3565b925060208401359150604084013567ffffffffffffffff81111561056f57600080fd5b61057b86828701610456565b9150509250925092565b60005b838110156105a0578181015183820152602001610588565b50506000910152565b60208152600082518060208401526105c8816040850160208701610585565b601f01601f19169190910160400192915050565b600082601f8301126105ed57600080fd5b8135602067ffffffffffffffff8211156106095761060961040f565b8160051b610618828201610425565b928352848101820192828101908785111561063257600080fd5b83870192505b8483101561065157823582529183019190830190610638565b979650505050505050565b600080600080600060a0868803121561067457600080fd5b61067d866103f3565b945061068b602087016103f3565b9350604086013567ffffffffffffffff808211156106a857600080fd5b6106b489838a016105dc565b945060608801359150808211156106ca57600080fd5b6106d689838a016105dc565b935060808801359150808211156106ec57600080fd5b506106f988828901610456565b9150509295509295909350565b600080600080600060a0868803121561071e57600080fd5b610727866103f3565b9450610735602087016103f3565b93506040860135925060608601359150608086013567ffffffffffffffff81111561075f57600080fd5b6106f988828901610456565b60006020828403121561077d57600080fd5b815180151581146103ec57600080fd5b6000825161079f818460208701610585565b919091019291505056fea26469706673582212207ec0550867c0ef079d60c4a3a1ad1deaa608e41615f8e1bbf8ac03e37e1890cf64736f6c63430008130033a264697066735822122031bd732f3d736a7e868be951b1bff492da85d1118ca2c8f77369e3b21c80301764736f6c63430008130033
Deployed Bytecode
0x60806040523480156200001157600080fd5b5060043610620001d15760003560e01c806350d005e01162000101578063c4d66de811620000a3578063d547741f116200007a578063d547741f1462000480578063dd93da431462000497578063e0cf1e4c14620004ae578063ee88819614620004c557600080fd5b8063c4d66de8146200042a578063cf189ff21462000441578063cfda7e0a146200045857600080fd5b8063a0cf0aea11620000d8578063a0cf0aea14620003ee578063a217fddf146200040a578063ac402839146200041357600080fd5b806350d005e014620003565780635e8a7915146200039b57806391d1485414620003b257600080fd5b80632f2ff15d11620001775780633a92f65f116200014e5780633a92f65f14620002ee5780633b66dacd14620003055780634756487f146200031c5780635063f361146200033f57600080fd5b80632f2ff15d14620002a957806336568abe14620002c057806339b86b8c14620002d757600080fd5b8063248a9ca311620001ac578063248a9ca314620002445780632497f3c6146200027957806324ae6a27146200029257600080fd5b80630114cf0a14620001d657806301ffc9a714620002055780630ec1fbac146200022d575b600080fd5b620001ed620001e736600462001aa0565b620004f0565b604051620001fc919062001b37565b60405180910390f35b6200021c6200021636600462001bb8565b620006a7565b6040519015158152602001620001fc565b6200021c6200023e36600462001c01565b620006df565b6200026a6200025536600462001aa0565b60009081526065602052604090206001015490565b604051908152602001620001fc565b620002906200028a36600462001aa0565b620006f4565b005b62000290620002a336600462001c30565b620007ad565b62000290620002ba36600462001c01565b620008b0565b62000290620002d136600462001c01565b620008de565b6200021c620002e836600462001c01565b62000964565b6200026a620002ff36600462001e28565b6200098a565b620002906200031636600462001c01565b62000c15565b6200026a6200032d36600462001ed7565b60976020526000908152604090205481565b620002906200035036600462001ef5565b62000c7f565b620003826200036736600462001aa0565b6099602052600090815260409020546001600160a01b031681565b6040516001600160a01b039091168152602001620001fc565b6200021c620003ac36600462001c01565b62000d0b565b6200021c620003c336600462001c01565b60009182526065602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6200038273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b6200026a600081565b620002906200042436600462001f40565b62000d3e565b620002906200043b36600462001ed7565b62000db1565b620003826200045236600462001f81565b62000ee6565b6200026a7f815b5a78dc333d344c7df9da23c04dbd432015cc701876ddb9ffe850e688274781565b620002906200049136600462001c01565b62000fa7565b620001ed620004a836600462001ed7565b62000fd0565b62000290620004bf36600462001ef5565b62001199565b620004dc620004d636600462001aa0565b620011e4565b604051620001fc9695949392919062001fc2565b620004fa62001a3d565b609860008381526020019081526020016000206040518060c001604052908160008201548152602001600182015481526020016002820180546200053e906200201e565b80601f01602080910402602001604051908101604052809291908181526020018280546200056c906200201e565b8015620005bd5780601f106200059157610100808354040283529160200191620005bd565b820191906000526020600020905b8154815290600101906020018083116200059f57829003601f168201915b505050505081526020016003820160405180604001604052908160008201548152602001600182018054620005f2906200201e565b80601f016020809104026020016040519081016040528092919081815260200182805462000620906200201e565b8015620006715780601f10620006455761010080835404028352916020019162000671565b820191906000526020600020905b8154815290600101906020018083116200065357829003601f168201915b50505091909252505050815260058201546001600160a01b03908116602083015260069092015490911660409091015292915050565b60006001600160e01b03198216637965db0b60e01b1480620006d957506301ffc9a760e01b6001600160e01b03198316145b92915050565b6000620006ed838362001364565b9392505050565b60008181526098602090815260408083206099909252909120546001600160a01b03163381146200073857604051630b4d48c160e41b815260040160405180910390fd5b6005820180546001600160a01b038381166001600160a01b03199283161783556000868152609960209081526040918290208054909416909355925492519216825284917ffd9ad63830df7bdf1586c8293dc88a30864cb43e9037e7afdb2c7210facf217d91015b60405180910390a2505050565b7f815b5a78dc333d344c7df9da23c04dbd432015cc701876ddb9ffe850e6882747620007d98162001390565b6001600160a01b038216620008015760405163538ba4f960e01b815260040160405180910390fd5b60006001600160a01b03841673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1462000899576040516370a0823160e01b81523060048201526001600160a01b038516906370a0823190602401602060405180830381865afa1580156200086d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200089391906200205a565b6200089b565b475b9050620008aa8484836200139f565b50505050565b600082815260656020526040902060010154620008cd8162001390565b620008d98383620013de565b505050565b6001600160a01b0381163314620009545760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b62000960828262001482565b5050565b6000828152609860205260408120600501546001600160a01b03838116911614620006ed565b60008062000999878562001506565b6000818152609860205260409020600601549091506001600160a01b031615620009d657604051630527e05960e41b815260040160405180910390fd5b6001600160a01b038416620009fe5760405163538ba4f960e01b815260040160405180910390fd5b60006040518060c00160405280838152602001898152602001888152602001878152602001866001600160a01b0316815260200162000a3e848a62001555565b6001600160a01b0316905260008381526098602090815260409182902083518155908301516001820155908201519192508291600282019062000a829082620020c6565b5060608201518051600383019081556020820151600484019062000aa79082620020c6565b50505060808201516005820180546001600160a01b03199081166001600160a01b039384161790915560a0938401516006909301805490911692821692909217909155908201511660009081526097602052604090208290558351801580159062000b1b57506001600160a01b0386163314155b1562000b3a5760405163075fd2b160e01b815260040160405180910390fd5b60005b8181101562000bb157600086828151811062000b5d5762000b5d62002193565b6020026020010151905060006001600160a01b0316816001600160a01b03160362000b9b5760405163538ba4f960e01b815260040160405180910390fd5b62000ba78582620013de565b5060010162000b3d565b50827f1e28352ff00d67474b59b87e6817d6ba65daa0130446266db8640214d8b8060983602001518460400151856060015186608001518760a0015160405162000c00959493929190620021a9565b60405180910390a25090979650505050505050565b8162000c21816200174a565b60008381526099602090815260409182902080546001600160a01b0319166001600160a01b038616908117909155915191825284917f21fe5cd61055ef88f636a264885b927f3ec2b380b6053a6b4a7495a6336a95c89101620007a0565b8162000c8b816200174a565b815160005b8181101562000d0457600084828151811062000cb05762000cb062002193565b6020026020010151905060006001600160a01b0316816001600160a01b03160362000cee5760405163538ba4f960e01b815260040160405180910390fd5b62000cfa8682620013de565b5060010162000c90565b5050505050565b6000828152609860205260408120600501546001600160a01b0383811691161480620006ed5750620006ed838362001364565b8162000d4a816200174a565b6000838152609860209081526040909120835160038201908155918401518492916004019062000d7b9082620020c6565b50905050827fa366054a574e4f861cb295fd23b5440c5119c1ba329c36f5dfeb5643537cb0f383604051620007a09190620021fe565b600054600190610100900460ff1615801562000dd4575060005460ff8083169116105b62000e395760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016200094b565b6000805461ffff191660ff8316176101001790556001600160a01b03821662000e755760405163538ba4f960e01b815260040160405180910390fd5b62000ea17f815b5a78dc333d344c7df9da23c04dbd432015cc701876ddb9ffe850e688274783620013de565b6000805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b60008262000ef4816200174a565b62000f00848462001555565b60008581526098602052604090209092506002810162000f218582620020c6565b506006810180546001600160a01b0390811660009081526097602052604080822082905583546001600160a01b0319169287169283179093559081528190208690555185907f54cd733148631b9ff1cb945f2d0dcd33c0692e154763bfa2f35e2d10a76c432f9062000f97908790879062002213565b60405180910390a2505092915050565b60008281526065602052604090206001015462000fc48162001390565b620008d9838362001482565b62000fda62001a3d565b6001600160a01b0382166000908152609760209081526040808320548084526098835292819020815160c0810183528154815260018201549381019390935260028101805491928401916200102f906200201e565b80601f01602080910402602001604051908101604052809291908181526020018280546200105d906200201e565b8015620010ae5780601f106200108257610100808354040283529160200191620010ae565b820191906000526020600020905b8154815290600101906020018083116200109057829003601f168201915b505050505081526020016003820160405180604001604052908160008201548152602001600182018054620010e3906200201e565b80601f016020809104026020016040519081016040528092919081815260200182805462001111906200201e565b8015620011625780601f10620011365761010080835404028352916020019162001162565b820191906000526020600020905b8154815290600101906020018083116200114457829003601f168201915b50505091909252505050815260058201546001600160a01b0390811660208301526006909201549091166040909101529392505050565b81620011a5816200174a565b815160005b8181101562000d0457620011db85858381518110620011cd57620011cd62002193565b602002602001015162001482565b600101620011aa565b609860205260009081526040902080546001820154600283018054929391926200120e906200201e565b80601f01602080910402602001604051908101604052809291908181526020018280546200123c906200201e565b80156200128d5780601f1062001261576101008083540402835291602001916200128d565b820191906000526020600020905b8154815290600101906020018083116200126f57829003601f168201915b5050505050908060030160405180604001604052908160008201548152602001600182018054620012be906200201e565b80601f0160208091040260200160405190810160405280929190818152602001828054620012ec906200201e565b80156200133d5780601f1062001311576101008083540402835291602001916200133d565b820191906000526020600020905b8154815290600101906020018083116200131f57829003601f168201915b50505091909252505050600582015460069092015490916001600160a01b03908116911686565b60008281526065602090815260408083206001600160a01b038516845290915281205460ff16620006ed565b6200139c813362001785565b50565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03841601620013d157620008d9828262001803565b620008d983838362001820565b60008281526065602090815260408083206001600160a01b038516845290915290205460ff16620009605760008281526065602090815260408083206001600160a01b03851684529091529020805460ff191660011790556200143e3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b60008281526065602090815260408083206001600160a01b038516845290915290205460ff1615620009605760008281526065602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b600082826040516020016200153792919091825260601b6bffffffffffffffffffffffff1916602082015260340190565b60405160208183030381529060405280519060200120905092915050565b60008083836040516020016200156d92919062002240565b60408051808303601f1901815282825260208301879052308383015281518084038301815260608401928390529093509160009190620015b09060800162001a92565b601f1982820381018352601f909101166040819052620015d6919084906020016200225b565b60408051601f198184030181529082905284516020868101919091208251828401207fff00000000000000000000000000000000000000000000000000000000000000928501929092526bffffffffffffffffffffffff193060601b166021850152603584018190526055840191909152909250906000906075016040516020818303038152906040528051906020012060001c90508188306040516200167d9062001a92565b9182526001600160a01b031660208201526040018190604051809103906000f590508015620016a95760015b6200173c5787816001600160a01b03166308386eba6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620016ee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200171491906200205a565b146200173357604051630113b81f60e41b815260040160405180910390fd5b8095506200173f565b95505b505050505092915050565b6000818152609860205260409020600501546001600160a01b031633146200139c5760405163075fd2b160e01b815260040160405180910390fd5b60008281526065602090815260408083206001600160a01b038516845290915290205460ff166200096057620017bb8162001870565b620017c883602062001883565b604051602001620017db9291906200228e565b60408051601f198184030181529082905262461bcd60e51b82526200094b9160040162002313565b60008060008084865af1620009605763b12d13eb6000526004601cfd5b81601452806034526fa9059cbb00000000000000000000000060005260206000604460106000875af13d15600160005114171662001866576390b8ec186000526004601cfd5b6000603452505050565b6060620006d96001600160a01b03831660145b60606000620018948360026200233e565b620018a190600262002358565b67ffffffffffffffff811115620018bc57620018bc62001c5f565b6040519080825280601f01601f191660200182016040528015620018e7576020820181803683370190505b509050600360fc1b8160008151811062001905576200190562002193565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811062001937576200193762002193565b60200101906001600160f81b031916908160001a90535060006200195d8460026200233e565b6200196a90600162002358565b90505b6001811115620019ec576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110620019a257620019a262002193565b1a60f81b828281518110620019bb57620019bb62002193565b60200101906001600160f81b031916908160001a90535060049490941c93620019e4816200236e565b90506200196d565b508315620006ed5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016200094b565b6040518060c0016040528060008019168152602001600081526020016060815260200162001a7e604051806040016040528060008152602001606081525090565b815260006020820181905260409091015290565b610891806200238983390190565b60006020828403121562001ab357600080fd5b5035919050565b60005b8381101562001ad757818101518382015260200162001abd565b50506000910152565b6000815180845262001afa81602086016020860162001aba565b601f01601f19169290920160200192915050565b80518252600060208201516040602085015262001b2f604085018262001ae0565b949350505050565b6020815281516020820152602082015160408201526000604083015160c0606084015262001b6960e084018262001ae0565b90506060840151601f1984830301608085015262001b88828262001b0e565b91505060808401516001600160a01b0380821660a08601528060a08701511660c086015250508091505092915050565b60006020828403121562001bcb57600080fd5b81356001600160e01b031981168114620006ed57600080fd5b80356001600160a01b038116811462001bfc57600080fd5b919050565b6000806040838503121562001c1557600080fd5b8235915062001c276020840162001be4565b90509250929050565b6000806040838503121562001c4457600080fd5b62001c4f8362001be4565b915062001c276020840162001be4565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171562001ca15762001ca162001c5f565b604052919050565b600082601f83011262001cbb57600080fd5b813567ffffffffffffffff81111562001cd85762001cd862001c5f565b62001ced601f8201601f191660200162001c75565b81815284602083860101111562001d0357600080fd5b816020850160208301376000918101602001919091529392505050565b60006040828403121562001d3357600080fd5b6040516040810167ffffffffffffffff828210818311171562001d5a5762001d5a62001c5f565b8160405282935084358352602085013591508082111562001d7a57600080fd5b5062001d898582860162001ca9565b6020830152505092915050565b600082601f83011262001da857600080fd5b8135602067ffffffffffffffff82111562001dc75762001dc762001c5f565b8160051b62001dd882820162001c75565b928352848101820192828101908785111562001df357600080fd5b83870192505b8483101562001e1d5762001e0d8362001be4565b8252918301919083019062001df9565b979650505050505050565b600080600080600060a0868803121562001e4157600080fd5b85359450602086013567ffffffffffffffff8082111562001e6157600080fd5b62001e6f89838a0162001ca9565b9550604088013591508082111562001e8657600080fd5b62001e9489838a0162001d20565b945062001ea46060890162001be4565b9350608088013591508082111562001ebb57600080fd5b5062001eca8882890162001d96565b9150509295509295909350565b60006020828403121562001eea57600080fd5b620006ed8262001be4565b6000806040838503121562001f0957600080fd5b82359150602083013567ffffffffffffffff81111562001f2857600080fd5b62001f368582860162001d96565b9150509250929050565b6000806040838503121562001f5457600080fd5b82359150602083013567ffffffffffffffff81111562001f7357600080fd5b62001f368582860162001d20565b6000806040838503121562001f9557600080fd5b82359150602083013567ffffffffffffffff81111562001fb457600080fd5b62001f368582860162001ca9565b86815285602082015260c06040820152600062001fe360c083018762001ae0565b828103606084015262001ff7818762001b0e565b9150506001600160a01b03808516608084015280841660a084015250979650505050505050565b600181811c908216806200203357607f821691505b6020821081036200205457634e487b7160e01b600052602260045260246000fd5b50919050565b6000602082840312156200206d57600080fd5b5051919050565b601f821115620008d957600081815260208120601f850160051c810160208610156200209d5750805b601f850160051c820191505b81811015620020be57828155600101620020a9565b505050505050565b815167ffffffffffffffff811115620020e357620020e362001c5f565b620020fb81620020f484546200201e565b8462002074565b602080601f8311600181146200213357600084156200211a5750858301515b600019600386901b1c1916600185901b178555620020be565b600085815260208120601f198616915b82811015620021645788860151825594840194600190910190840162002143565b5085821015620021835787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052603260045260246000fd5b85815260a060208201526000620021c460a083018762001ae0565b8281036040840152620021d8818762001b0e565b9150506001600160a01b0380851660608401528084166080840152509695505050505050565b602081526000620006ed602083018462001b0e565b60408152600062002228604083018562001ae0565b90506001600160a01b03831660208301529392505050565b82815260406020820152600062001b2f604083018462001ae0565b600083516200226f81846020880162001aba565b8351908301906200228581836020880162001aba565b01949350505050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351620022c881601785016020880162001aba565b7f206973206d697373696e6720726f6c652000000000000000000000000000000060179184019182015283516200230781602884016020880162001aba565b01602801949350505050565b602081526000620006ed602083018462001ae0565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417620006d957620006d962002328565b80820180821115620006d957620006d962002328565b60008162002380576200238062002328565b50600019019056fe60c060405234801561001057600080fd5b5060405161089138038061089183398101604081905261002f91610043565b6001600160a01b031660805260a052610080565b6000806040838503121561005657600080fd5b825160208401519092506001600160a01b038116811461007557600080fd5b809150509250929050565b60805160a0516107df6100b26000396000818160c7015261025201526000818161014d015261028101526107df6000f3fe6080604052600436106100745760003560e01c80637b1039991161004e5780637b1039991461013b578063b61d27f614610187578063bc197c81146101b4578063f23a6e61146101e057600080fd5b806301ffc9a71461008057806308386eba146100b5578063150b7a02146100f757600080fd5b3661007b57005b600080fd5b34801561008c57600080fd5b506100a061009b3660046103c2565b61020c565b60405190151581526020015b60405180910390f35b3480156100c157600080fd5b506100e97f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020016100ac565b34801561010357600080fd5b506101226101123660046104c6565b630a85bd0160e11b949350505050565b6040516001600160e01b031990911681526020016100ac565b34801561014757600080fd5b5061016f7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100ac565b34801561019357600080fd5b506101a76101a236600461052e565b610243565b6040516100ac91906105a9565b3480156101c057600080fd5b506101226101cf36600461065c565b63bc197c8160e01b95945050505050565b3480156101ec57600080fd5b506101226101fb366004610706565b63f23a6e6160e01b95945050505050565b60006001600160e01b03198216630271189760e51b148061023d57506301ffc9a760e01b6001600160e01b03198316145b92915050565b604051630e6e1ae360e21b81527f000000000000000000000000000000000000000000000000000000000000000060048201523360248201526060907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906339b86b8c90604401602060405180830381865afa1580156102d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102f4919061076b565b6103115760405163075fd2b160e01b815260040160405180910390fd5b6001600160a01b038416610338576040516384aed38d60e01b815260040160405180910390fd5b600080856001600160a01b03168585604051610354919061078d565b60006040518083038185875af1925050503d8060008114610391576040519150601f19603f3d011682016040523d82523d6000602084013e610396565b606091505b5091509150816103b9576040516384aed38d60e01b815260040160405180910390fd5b95945050505050565b6000602082840312156103d457600080fd5b81356001600160e01b0319811681146103ec57600080fd5b9392505050565b80356001600160a01b038116811461040a57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561044e5761044e61040f565b604052919050565b600082601f83011261046757600080fd5b813567ffffffffffffffff8111156104815761048161040f565b610494601f8201601f1916602001610425565b8181528460208386010111156104a957600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080608085870312156104dc57600080fd5b6104e5856103f3565b93506104f3602086016103f3565b925060408501359150606085013567ffffffffffffffff81111561051657600080fd5b61052287828801610456565b91505092959194509250565b60008060006060848603121561054357600080fd5b61054c846103f3565b925060208401359150604084013567ffffffffffffffff81111561056f57600080fd5b61057b86828701610456565b9150509250925092565b60005b838110156105a0578181015183820152602001610588565b50506000910152565b60208152600082518060208401526105c8816040850160208701610585565b601f01601f19169190910160400192915050565b600082601f8301126105ed57600080fd5b8135602067ffffffffffffffff8211156106095761060961040f565b8160051b610618828201610425565b928352848101820192828101908785111561063257600080fd5b83870192505b8483101561065157823582529183019190830190610638565b979650505050505050565b600080600080600060a0868803121561067457600080fd5b61067d866103f3565b945061068b602087016103f3565b9350604086013567ffffffffffffffff808211156106a857600080fd5b6106b489838a016105dc565b945060608801359150808211156106ca57600080fd5b6106d689838a016105dc565b935060808801359150808211156106ec57600080fd5b506106f988828901610456565b9150509295509295909350565b600080600080600060a0868803121561071e57600080fd5b610727866103f3565b9450610735602087016103f3565b93506040860135925060608601359150608086013567ffffffffffffffff81111561075f57600080fd5b6106f988828901610456565b60006020828403121561077d57600080fd5b815180151581146103ec57600080fd5b6000825161079f818460208701610585565b919091019291505056fea26469706673582212207ec0550867c0ef079d60c4a3a1ad1deaa608e41615f8e1bbf8ac03e37e1890cf64736f6c63430008130033a264697066735822122031bd732f3d736a7e868be951b1bff492da85d1118ca2c8f77369e3b21c80301764736f6c63430008130033
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.