// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
/**
* @title Constants
* @author OpenSocial Protocol
* @notice This library defines constants for the OpenSocial Protocol.
*/
library Constants {
string internal constant FOLLOW_NFT_NAME_SUFFIX = '-Follower';
string internal constant FOLLOW_NFT_SYMBOL_SUFFIX = '-Fl';
string internal constant JOIN_NFT_NAME_INFIX = '-Member';
string internal constant JOIN_NFT_SYMBOL_INFIX = '-Mb';
uint8 internal constant MAX_HANDLE_LENGTH = 15;
uint8 internal constant MIN_HANDLE_LENGTH = 4;
uint8 internal constant MAX_COMMUNITY_NAME_LENGTH = 63;
uint16 internal constant MAX_PROFILE_IMAGE_URI_LENGTH = 6000;
address internal constant ERC6551_REGISTRY = 0x000000006551c19487814612e58FE06813775758;
bytes32 internal constant COMMUNITY_TBA_SALT =
0xd51dafa9227bb21dd4efbc739a5c611e802dd0ec1ef35b3dc8da5ad2dca64ae6;
bytes32 internal constant APP_ADMIN = keccak256('APP_ADMIN');
bytes32 internal constant GOVERNANCE = keccak256('GOVERNANCE');
bytes32 internal constant OPERATION = keccak256('OPERATION');
bytes32 internal constant STATE_ADMIN = keccak256('STATE_ADMIN');
uint256 internal constant MAX_TAGS_NUMBER = 10;
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)
pragma solidity ^0.8.20;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev The `account` is missing a role.
*/
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
/**
* @dev The caller of a function is not the expected one.
*
* NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
*/
error AccessControlBadConfirmation();
/**
* @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.
*/
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 `callerConfirmation`.
*/
function renounceRole(bytes32 role, address callerConfirmation) external;
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
/// @title EIP-721 Metadata Update Extension
interface IERC4906 {
/// @dev This event emits when the metadata of a token is changed.
/// So that the third-party platforms such as NFT market could
/// timely update the images and related attributes of the NFT.
event MetadataUpdate(uint256 _tokenId);
/// @dev This event emits when the metadata of a range of tokens is changed.
/// So that the third-party platforms such as NFT market could
/// timely update the images and related attributes of the NFTs.
event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol)
pragma solidity ^0.8.20;
interface IERC5267 {
/**
* @dev MAY be emitted to signal that the domain could have changed.
*/
event EIP712DomainChanged();
/**
* @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
* signature.
*/
function eip712Domain()
external
view
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
import '../../../libraries/OspDataTypes.sol';
import '../../base/IERC4906.sol';
import '@openzeppelin/contracts/interfaces/IERC5267.sol';
import '../../../libraries/Constants.sol';
import '@openzeppelin/contracts/access/IAccessControl.sol';
/**
* @title IGovernanceLogic
* @author OpenSocial Protocol
*
* @dev This is the interface for the GovernanceLogic contract.
*/
interface IGovernanceLogic is IERC4906, IERC5267, IAccessControl {
/**
* @dev Initializes the Profile SBT, setting the initial governance address as well as the name and symbol.
*
* @param name The name to set for the osp NFT.
* @param symbol The symbol to set for the osp NFT.
*/
function initialize(
string calldata name,
string calldata symbol,
address followSBTImpl,
address joinNFTImpl,
address communityNFT
) external;
/**
* @dev Sets the protocol state to either a global pause, a publishing pause or an unpaused state. This function
* can only be called by the governance address or the emergency admin address.
*
* Note that this reverts if the emergency admin calls it if:
* 1. The emergency admin is attempting to unpause.
* 2. The emergency admin is calling while the protocol is already paused.
*
* @param newState The state to set, as a member of the ProtocolState enum.
*/
function setState(OspDataTypes.ProtocolState newState) external;
/**
*@dev Adds or removes a super community creator from the whitelist. This function can only be called by the current
* governance address.
*
* @param communityCreator The community creator address to add or remove from the whitelist.
* @param whitelist Whether or not the community creator should be whitelisted.
*/
function whitelistSuperCommunityCreator(address communityCreator, bool whitelist) external;
/**
* @dev Adds or removes a app from the whitelist. This function can only be called by the
* current governance address.
*
* @param app Reaction about the activity.
* @param whitelist Whether or not the reaction should be whitelisted.
*/
function whitelistApp(address app, bool whitelist) external;
/**
* @dev Adds or removes a ERC20 token from the whitelist. This function can only be called by the current
* governance address.
*
* @param token ERC20 token address
* @param whitelist whether or not the token should be whitelisted
*/
function whitelistToken(address token, bool whitelist) external;
/**
* @dev Adds or removes a reserve community handle.This function can only be called by the current governance address.
*
* @param handle The handle to reserve.
* @param isReserve Reserve or not the handle should be reserved.
*/
function reserveCommunityHandle(string calldata handle, bool isReserve) external;
/**
* @dev Sets the base URI for NFTs. This function can only be called by the current governance
* address.
*
* @param baseURI The base URI to set.
*/
function setBaseURI(string calldata baseURI) external;
function setERC6551AccountImpl(address accountImpl) external;
/// ************************
/// *****VIEW FUNCTIONS*****
/// ************************
/**
* @dev Returns whether or not a super community creator is whitelisted.
*
* @param communityCreator The address of the super community creator to check.
*
* @return bool True if the super community creator is whitelisted, false otherwise.
*/
function isSuperCommunityCreatorWhitelisted(
address communityCreator
) external view returns (bool);
function isAppWhitelisted(address app) external view returns (bool);
/**
* @dev Returns whether or not a token is whitelisted.
*
* @param token The address of the token to check.
*
* @return bool True if the the token whitelisted, false otherwise.
*/
function isTokenWhitelisted(address token) external view returns (bool);
/**
* @dev Returns whether or not a community handle is reserved.
*
* @param handle The handle to check.
*
* @return bool True if the the handle is reserved, false otherwise.
*/
function isReserveCommunityHandle(string calldata handle) external view returns (bool);
/**
* @dev Returns the base URI for the NFTs.
*
* @return string The base URI for the NFTs.
*/
function getBaseURI() external view returns (string memory);
/**
* @dev Returns the follow NFT implementation address.
*
* @return address The follow NFT implementation address.
*/
function getFollowSBTImpl() external view returns (address);
/**
* @dev Returns the join NFT implementation address.
*
* @return address The join NFT implementation address.
*/
function getJoinNFTImpl() external view returns (address);
/**
* @dev Returns the community NFT address.
*
* @return address The community NFT address.
*/
function getCommunityNFT() external view returns (address);
function getERC6551AccountImpl() external view returns (address);
/**
* @dev Returns the current protocol state.
*
* @return ProtocolState The Protocol state, an enum, where:
* 0: Unpaused
* 1: PublishingPaused
* 2: Paused
*/
function getState() external view returns (OspDataTypes.ProtocolState);
function updateMetadata() external;
/**
* @dev Update The treasure address.This function can only be called by the current governance.
*/
function setTreasureAddress(address treasure) external;
/**
* @dev Get The treasure address.
*/
function getTreasureAddress() external view returns (address);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
import {IGovernanceLogic} from '../core/logics/interfaces/IGovernanceLogic.sol';
import {Proxy} from '@openzeppelin/contracts/proxy/Proxy.sol';
import {Address} from '@openzeppelin/contracts/utils/Address.sol';
contract JoinNFTProxy is Proxy {
using Address for address;
address immutable OSP;
constructor(bytes memory data) {
OSP = msg.sender;
IGovernanceLogic(msg.sender).getJoinNFTImpl().functionDelegateCall(data);
}
function _implementation() internal view override returns (address) {
return IGovernanceLogic(OSP).getJoinNFTImpl();
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
/**
* @title OspDataTypes
* @author OpenSocial Protocol
*
* @dev The OspDataTypes library contains data types used throughout the OpenSocial Protocol.
*/
library OspDataTypes {
bytes32 internal constant EIP712_DOMAIN_TYPEHASH =
keccak256(
'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'
);
bytes32 internal constant CREATE_ACTIVITY_WITH_SIG_TYPEHASH =
keccak256(
'CreateActivityWithSig(uint256 profileId,uint256 communityId,string contentURI,bytes extensionInitCode,bytes referenceConditionInitCode,bytes ctx,uint256 nonce,uint256 deadline)'
);
bytes32 internal constant CREATE_OPEN_REACTION_WITH_SIG_TYPEHASH =
keccak256(
'CreateOpenReactionWithSig(uint256 profileId,uint256 communityId,uint256 referencedProfileId,uint256 referencedContentId,bytes reactionAndData,bytes referenceConditionData,bytes ctx,uint256 nonce,uint256 deadline)'
);
bytes32 internal constant CREATE_COMMENT_WITH_SIG_TYPEHASH =
keccak256(
'CreateCommentWithSig(uint256 profileId,uint256 communityId,string contentURI,uint256 referencedProfileId,uint256 referencedContentId,bytes referenceConditionInitCode,bytes referenceConditionData,bytes ctx,uint256 nonce,uint256 deadline)'
);
/*///////////////////////////////////////////////////////////////
Common Type
//////////////////////////////////////////////////////////////*/
/**
* @dev An enum containing the different states the protocol can be in, limiting certain actions.
*
* @param Unpaused The fully unpaused state.
* @param PublishingPaused The state where only content creation functions are paused.
* @param Paused The fully paused state.
*/
enum ProtocolState {
Unpaused,
PublishingPaused,
Paused
}
/**
* @dev A struct containing the necessary information to reconstruct an EIP-712 typed data signature.
*
* @param signature Signature
* @param deadline The signature's deadline
*/
struct EIP712Signature {
address signer;
bytes signature;
uint256 deadline;
}
/*///////////////////////////////////////////////////////////////
Storage Struct
//////////////////////////////////////////////////////////////*/
/**
* @dev A struct containing profile data.
*
* @param contentCount The number of publications made to this profile.
* @param followCondition The address of the current follow condition in use by this profile, can be empty.
* @param followSBT The address of the FollowSBT associated with this profile, can be empty..
* @param handle The profile's associated handle.
* @param owner The profile's owner.
* @param dispatcher The profile's dispatcher.
* @param mintTimestamp The timestamp at which this profile was minted.
*/
struct ProfileStruct {
uint256 contentCount;
address followCondition;
address followSBT;
string handle;
address owner;
uint96 mintTimestamp;
uint256 inviter;
}
/**
* @dev A struct containing community data.
* @param handle The community's associated handle.
* @param joinCondition The address of the current join condition in use by this community, can be empty.
* @param joinNFT The address of the JoinNFT associated with this community.
*/
struct CommunityStruct {
string handle;
address joinCondition;
address joinNFT;
}
struct ContentStruct {
uint256 communityId;
uint256 referencedProfileId;
uint256 referencedContentId;
string contentURI;
address extension;
address referenceCondition;
}
struct PluginStruct {
bool isEnable;
address tokenAddress;
uint256 amount;
}
/*///////////////////////////////////////////////////////////////
Call Params
//////////////////////////////////////////////////////////////*/
/**
* @dev A struct containing the parameters required for the `createProfile()` function.
*
* @param handle The handle to set for the profile, must be unique and non-empty.
* @param followCondition The follow condition to use, can be the zero address.
* @param followConditionInitData The follow condition initialization data, if any.
*/
struct CreateProfileData {
string handle;
bytes followConditionInitCode;
uint256 inviter;
bytes ctx;
}
/**
* Create Activity Data
* @param profileId The profile id of the creator.
* @param communityId The community id of the content, if zero then it's a global content.
* @param contentURI The URI of the content.
* @param extensionInitCode If set, the extension will be set.
* @param referenceConditionInitCode If set,the reference condition will be set. contains 20 bytes of condition address, followed by calldata.
* @param ctx The context data.
*/
struct CreateActivityData {
uint256 profileId;
uint256 communityId;
string contentURI;
bytes extensionInitCode;
bytes referenceConditionInitCode;
bytes ctx;
}
/**
* Create Comment Data
* @param profileId The profile id of the commenter.
* @param communityId
* @param contentURI
* @param referencedProfileId
* @param referencedContentId
* @param referenceConditionInitCode If set,the reference condition will be set. contains 20 bytes of condition address, followed by calldata.
* @param referenceConditionData The data passed to the reference condition.
* @param ctx The context data.
*/
struct CreateCommentData {
uint256 profileId;
uint256 communityId;
string contentURI;
uint256 referencedProfileId;
uint256 referencedContentId;
bytes referenceConditionInitCode;
bytes referenceConditionData;
bytes ctx;
}
/**
* @dev A struct containing the parameters required for the `createMegaphone()` function.
*
* @param profileId The profile ID of the user creating the megaphone.
* @param referencedProfileId The profile ID of the user who created the content being megaphoned.
* @param referencedContentId The content ID being megaphoned.
* @param tags The tags to associate with the megaphone.
* @param startTime The start time of the megaphone.
* @param duration The duration of the megaphone.
* @param currency The currency to use for the megaphone.
* @param amount The amount to pay for the megaphone.
* @param ctx The context data.
*/
struct CreateMegaphoneData {
uint256 profileId;
uint256 referencedProfileId;
uint256 referencedContentId;
string[] tags;
uint256 startTime;
uint256 duration;
address currency;
uint256 amount;
bytes ctx;
}
/**
* @dev A struct containing the parameters required for the `createOpenReaction()` function.
*
* @param profileId The profile ID of the user creating the reaction.
* @param communityId The community ID of the content being reacted to.
* @param referencedProfileId The profile ID of the user who created the content being reacted to.
* @param referencedContentId The content ID being reacted to.
* @param reactionAndData The reaction and data to use.
* @param referenceConditionData The reference condition data to use.
* @param ctx The context data.
*/
struct CreateOpenReactionData {
uint256 profileId;
uint256 communityId;
uint256 referencedProfileId;
uint256 referencedContentId;
uint256 reactionValue;
bytes reactionAndData;
bytes referenceConditionData;
bytes ctx;
}
/**
* @dev A struct containing the parameters required for the `createCommunity()` function.
*
* @param handle The handle to set for the community, must be unique and non-empty.
* @param communityConditionAndData The community condition and data to use, can be the zero address.
* @param joinConditionInitCode The join condition initialization data, if any.
* @param tags The tags to associate with the community.
* @param ctx The context data.
*/
struct CreateCommunityData {
string handle;
bytes communityConditionAndData;
bytes joinConditionInitCode;
string[] tags;
bytes ctx;
}
/**
* @dev A struct containing the parameters required for the `follow()` function.
*
* @param profileId The profile token ID to follow.
* @param data The data passed to the follow condition.
* @param ctx The context data.
*/
struct FollowData {
uint256 profileId;
bytes data;
bytes ctx;
}
/**
* @dev A struct containing the parameters required for the `batchFollow()` function.
*
* @param profileIds The array of profile token IDs to follow.
* @param datas The array of follow condition data parameters to pass to each profile's follow condition.
* @param ctx The context data.
*/
struct BatchFollowData {
uint256[] profileIds;
bytes[] datas;
uint256[] values;
bytes ctx;
}
/**
* @dev A struct containing the parameters required for the `join()` function.
*
* @param communityId The ID of the community to join.
* @param data The data passed to the join condition.
* @param ctx The context data.
*/
struct JoinData {
uint256 communityId;
bytes data;
bytes ctx;
}
/**
* @dev A struct containing the parameters required for the `batchJoin()` function.
* @param communityIds The array of community token IDs to join.
* @param datas The array of join condition data parameters to pass to each community's join condition.
* @param values The array of values to pass to each community's join condition.
* @param ctx The context data.
*/
struct BatchJoinData {
uint256[] communityIds;
bytes[] datas;
uint256[] values;
bytes ctx;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/Proxy.sol)
pragma solidity ^0.8.20;
/**
* @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
* instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
* be specified by overriding the virtual {_implementation} function.
*
* Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
* different contract through the {_delegate} function.
*
* The success and return data of the delegated call will be returned back to the caller of the proxy.
*/
abstract contract Proxy {
/**
* @dev Delegates the current call to `implementation`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _delegate(address implementation) internal virtual {
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
/**
* @dev This is a virtual function that should be overridden so it returns the address to which the fallback
* function and {_fallback} should delegate.
*/
function _implementation() internal view virtual returns (address);
/**
* @dev Delegates the current call to the address returned by `_implementation()`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _fallback() internal virtual {
_delegate(_implementation());
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
* function in the contract matches the call data.
*/
fallback() external payable virtual {
_fallback();
}
}
{
"compilationTarget": {
"contracts/upgradeability/JoinNFTProxy.sol": "JoinNFTProxy"
},
"evmVersion": "shanghai",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"stateMutability":"payable","type":"fallback"}]