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": {}
}Contract ABI
API[{"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
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.