编译器
0.8.20+commit.a1b79de6
文件 1 的 124:AccessControlUpgradeable.sol
pragma solidity ^0.8.20;
import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {ERC165Upgradeable} from "../utils/introspection/ERC165Upgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControl, ERC165Upgradeable {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
struct AccessControlStorage {
mapping(bytes32 role => RoleData) _roles;
}
bytes32 private constant AccessControlStorageLocation = 0x02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800;
function _getAccessControlStorage() private pure returns (AccessControlStorage storage $) {
assembly {
$.slot := AccessControlStorageLocation
}
}
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
function __AccessControl_init() internal onlyInitializing {
}
function __AccessControl_init_unchained() internal onlyInitializing {
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
function hasRole(bytes32 role, address account) public view virtual returns (bool) {
AccessControlStorage storage $ = _getAccessControlStorage();
return $._roles[role].hasRole[account];
}
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
AccessControlStorage storage $ = _getAccessControlStorage();
return $._roles[role].adminRole;
}
function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
AccessControlStorage storage $ = _getAccessControlStorage();
bytes32 previousAdminRole = getRoleAdmin(role);
$._roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
AccessControlStorage storage $ = _getAccessControlStorage();
if (!hasRole(role, account)) {
$._roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
AccessControlStorage storage $ = _getAccessControlStorage();
if (hasRole(role, account)) {
$._roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}
文件 2 的 124:ActivityConditionBase.sol
pragma solidity 0.8.20;
import {IActivityCondition} from '../../interfaces/IActivityCondition.sol';
import {IERC165} from '@openzeppelin/contracts/interfaces/IERC165.sol';
import {ConditionContext} from 'contracts/core/base/ConditionContext.sol';
abstract contract ActivityConditionBase is ConditionContext, IERC165, IActivityCondition {
constructor(
address osp,
address compositeCondition
) ConditionContext(osp, compositeCondition) {}
function initializeCommunityActivityCondition(
uint256 communityId,
bytes calldata data
) external onlyOspOrCompositeCondition {
_initializeCommunityActivityCondition(communityId, data);
}
function processActivity(
uint256 communityId,
address profileOwner,
uint256 profileId
) external onlyOspOrCompositeCondition {
_processActivity(communityId, profileOwner, profileId);
}
function _initializeCommunityActivityCondition(
uint256 communityId,
bytes calldata data
) internal virtual;
function _processActivity(
uint256 communityId,
address profileOwner,
uint256 profileId
) internal virtual;
function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {
return
interfaceId == type(IActivityCondition).interfaceId ||
interfaceId == type(IERC165).interfaceId;
}
}
文件 3 的 124:ActivityExtensionBase.sol
pragma solidity 0.8.20;
import {OspContext} from './OspContext.sol';
import {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';
import {IActivityExtension} from '../../interfaces/IActivityExtension.sol';
import {IActivityExtensionQueryable} from '../../interfaces/IActivityExtensionQueryable.sol';
abstract contract ActivityExtensionBase is OspContext, IActivityExtensionQueryable, IERC165 {
constructor(address osp) OspContext(osp) {}
function initializeActivityExtension(
uint256 profileId,
uint256 contentId,
bytes calldata initData
) external payable onlyOsp {
_initializeActivityExtension(profileId, contentId, initData);
}
function _initializeActivityExtension(
uint256 profileId,
uint256 contentId,
bytes calldata initData
) internal virtual;
function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {
return
interfaceId == type(IActivityExtension).interfaceId ||
interfaceId == type(IActivityExtensionQueryable).interfaceId ||
interfaceId == type(IERC165).interfaceId;
}
function getExtensionData(
uint256 profileId,
uint256 contentId
) external view virtual override returns (bytes memory) {
return '';
}
}
文件 4 的 124:Address.sol
pragma solidity ^0.8.20;
library Address {
error AddressInsufficientBalance(address account);
error AddressEmptyCode(address target);
error FailedInnerCall();
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();
}
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
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);
}
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);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
function _revert(bytes memory returndata) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}
文件 5 的 124:CommunityAccountProxy.sol
pragma solidity 0.8.20;
import {IGovernanceLogic} from '../core/logics/interfaces/IGovernanceLogic.sol';
import {Proxy} from '@openzeppelin/contracts/proxy/Proxy.sol';
contract CommunityAccountProxy is Proxy {
address immutable OSP;
constructor() {
OSP = msg.sender;
}
function _implementation() internal view override returns (address) {
return IGovernanceLogic(OSP).getERC6551AccountImpl();
}
}
文件 6 的 124:CommunityCondBase.sol
pragma solidity 0.8.20;
import {OspContext} from './OspContext.sol';
import {ICommunityCondition} from '../../interfaces/ICommunityCondition.sol';
import {IERC165} from '@openzeppelin/contracts/interfaces/IERC165.sol';
abstract contract CommunityCondBase is OspContext, ICommunityCondition, IERC165 {
constructor(address osp) OspContext(osp) {}
function processCreateCommunity(
address to,
string calldata handle,
bytes calldata data
) external payable override onlyOsp {
_processCreateCommunity(to, handle, data);
}
function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {
return
interfaceId == type(ICommunityCondition).interfaceId ||
interfaceId == type(IERC165).interfaceId;
}
function _processCreateCommunity(
address to,
string calldata handle,
bytes calldata data
) internal virtual;
}
文件 7 的 124:CommunityLogic.sol
pragma solidity 0.8.20;
import {OspLogicBase} from './OspLogicBase.sol';
import {ICommunityLogic} from './interfaces/ICommunityLogic.sol';
import {OspDataTypes} from 'contracts/libraries/OspDataTypes.sol';
import {OspErrors} from 'contracts/libraries/OspErrors.sol';
import {OspEvents} from 'contracts/libraries/OspEvents.sol';
import {Constants} from 'contracts/libraries/Constants.sol';
import {ICommunityNFT} from 'contracts/interfaces/ICommunityNFT.sol';
import {IJoinCondition} from 'contracts/interfaces/IJoinCondition.sol';
import {ICommunityCondition} from 'contracts/interfaces/ICommunityCondition.sol';
import {IActivityCondition} from 'contracts/interfaces/IActivityCondition.sol';
import {IViewPrivacyCondition} from 'contracts/interfaces/IViewPrivacyCondition.sol';
import {IERC6551Registry} from 'contracts/interfaces/IERC6551Registry.sol';
import {ERC6551Account} from 'contracts/core/base/ERC6551Account.sol';
import {JoinNFTProxy} from 'contracts/upgradeability/JoinNFTProxy.sol';
import {IJoinNFT} from 'contracts/interfaces/IJoinNFT.sol';
import {Strings} from '@openzeppelin/contracts/utils/Strings.sol';
import {IERC721} from '@openzeppelin/contracts/token/ERC721/IERC721.sol';
import {EnumerableSet} from '@openzeppelin/contracts/utils/structs/EnumerableSet.sol';
contract CommunityLogic is OspLogicBase, ICommunityLogic {
using Strings for uint256;
using EnumerableSet for EnumerableSet.AddressSet;
function createCommunity(
OspDataTypes.CreateCommunityData calldata vars
) external payable override whenNotPaused returns (uint256) {
return _createCommunity(vars);
}
function createCommunity(
OspDataTypes.CreateCommunityData calldata vars,
bytes calldata activityConditionInitCode,
bytes calldata viewPrivacyConditionInitCode
) external payable override whenNotPaused returns (uint256) {
uint256 communityId = _createCommunity(vars);
_setActivityCondition(communityId, activityConditionInitCode);
_setViewPrivacyCondition(communityId, viewPrivacyConditionInitCode);
return communityId;
}
function emitCommunityNFTTransferEvent(
uint256 communityId,
address from,
address to
) external override {
if (_getGovernanceStorage()._communityNFT != msg.sender) {
revert OspErrors.NotCommunityNFT();
}
emit OspEvents.CommunityNFTTransferred(communityId, from, to, block.timestamp);
}
function setJoinCondition(
uint256 communityId,
bytes calldata joinConditionInitCode
) external override whenNotPaused {
_validateCallerHasCommunityRole(communityId, Constants.COMMUNITY_ADMIN_ACCESS);
_setJoinCondition(communityId, joinConditionInitCode);
}
function setActivityCondition(
uint256 communityId,
bytes calldata activityConditionInitCode
) external override whenNotPaused {
_validateCallerHasCommunityRole(communityId, Constants.COMMUNITY_ADMIN_ACCESS);
_setActivityCondition(communityId, activityConditionInitCode);
}
function setViewPrivacyCondition(
uint256 communityId,
bytes calldata viewPrivacyConditionInitCode
) external override whenNotPaused {
_validateCallerHasCommunityRole(communityId, Constants.COMMUNITY_ADMIN_ACCESS);
_setViewPrivacyCondition(communityId, viewPrivacyConditionInitCode);
}
function isViewPrivacyAllowed(
uint256 communityId,
uint256 profileId
) external view returns (bool) {
return
IViewPrivacyCondition(
_getCommunityStorage()._communityById[communityId].viewPrivacyCondition
).isViewPrivacyAllowed(
communityId,
_getProfileStorage()._profileById[profileId].owner,
profileId
);
}
function updateTags(
uint256 communityId,
string[] calldata tags
) external override whenNotPaused {
_validateCallerHasCommunityRole(communityId, Constants.COMMUNITY_ADMIN_ACCESS);
if (tags.length > Constants.MAX_TAGS_NUMBER) revert OspErrors.TooManyTags();
emit OspEvents.CommunityTagsUpdated(communityId, msg.sender, tags, block.timestamp);
}
function setCommunityActivityExtensionWhitelist(
uint256 communityId,
address extension,
bool isWhitelist
) external override whenNotPaused {
_validateCallerHasCommunityRole(communityId, Constants.COMMUNITY_ADMIN_ACCESS);
if (extension != address(0)) {
_checkActivityExtension(extension);
}
EnumerableSet.AddressSet storage communityExtensionWhitelist = _getCommunityStorage()
._activityExtensionWhitelistByCommunity[communityId];
if (
isWhitelist
? communityExtensionWhitelist.add(extension)
: communityExtensionWhitelist.remove(extension)
) {
emit OspEvents.CommunityExtensionWhitelistSet(
communityId,
extension,
isWhitelist,
msg.sender,
block.timestamp
);
}
}
function getCommunityTokenURI(
uint256 communityId
) external view override returns (string memory) {
string memory baseURI = _getGovernanceStorage()._baseURI;
return
bytes(baseURI).length > 0
? string(abi.encodePacked(baseURI, 'community/', communityId.toString()))
: communityId.toString();
}
function getCommunity(
uint256 communityId
) external view override returns (OspDataTypes.CommunityStruct memory) {
CommunityStorage storage communityStorage = _getCommunityStorage();
OspDataTypes.CommunityStruct memory communityData = communityStorage._communityById[
communityId
];
return communityData;
}
function getJoinNFT(uint256 communityId) external view override returns (address) {
CommunityStorage storage communityStorage = _getCommunityStorage();
return communityStorage._communityById[communityId].joinNFT;
}
function getJoinCondition(uint256 communityId) external view override returns (address) {
CommunityStorage storage communityStorage = _getCommunityStorage();
return communityStorage._communityById[communityId].joinCondition;
}
function getActivityCondition(uint256 communityId) external view override returns (address) {
CommunityStorage storage communityStorage = _getCommunityStorage();
return communityStorage._communityById[communityId].activityCondition;
}
function getCommunityIdByHandle(string calldata handle) public view override returns (uint256) {
return _getCommunityStorage()._communityIdByHandleHash[keccak256(bytes(handle))];
}
function getCommunityAccount(uint256 communityId) public view override returns (address) {
return
IERC6551Registry(Constants.ERC6551_REGISTRY).account(
_getGovernanceStorage()._communityAccountProxy,
Constants.COMMUNITY_TBA_SALT,
block.chainid,
_getGovernanceStorage()._communityNFT,
communityId
);
}
function getCommunityAccount(string calldata handle) external view override returns (address) {
return getCommunityAccount(getCommunityIdByHandle(handle));
}
function getCommunityActivityExtensionWhitelist(
uint256 communityId
) external view override returns (address[] memory extensions) {
EnumerableSet.AddressSet storage communityExtensionWhitelist = _getCommunityStorage()
._activityExtensionWhitelistByCommunity[communityId];
uint256 length = communityExtensionWhitelist.length();
extensions = new address[](length);
for (uint256 i; i < length; i += 1) {
extensions[i] = communityExtensionWhitelist.at(i);
}
}
function _setJoinCondition(uint256 communityId, bytes calldata joinConditionInitCode) internal {
address joinCondition = joinConditionInitCode.length == 0
? address(0)
: _initJoinCondition(communityId, joinConditionInitCode);
_getCommunityStorage()._communityById[communityId].joinCondition = joinCondition;
emit OspEvents.JoinConditionSet(communityId, msg.sender, joinCondition, block.timestamp);
}
function _setActivityCondition(
uint256 communityId,
bytes calldata activityConditionInitCode
) internal {
address activityCondition = activityConditionInitCode.length == 0
? address(0)
: _initActivityCondition(communityId, activityConditionInitCode);
_getCommunityStorage()._communityById[communityId].activityCondition = activityCondition;
emit OspEvents.ActivityConditionSet(
communityId,
msg.sender,
activityCondition,
block.timestamp
);
}
function _setViewPrivacyCondition(
uint256 communityId,
bytes calldata viewPrivacyConditionInitCode
) internal {
address viewPrivacyCondition = viewPrivacyConditionInitCode.length == 0
? address(0)
: _initViewPrivacyCondition(communityId, viewPrivacyConditionInitCode);
_getCommunityStorage()
._communityById[communityId]
.viewPrivacyCondition = viewPrivacyCondition;
emit OspEvents.ViewPrivacyConditionSet(
communityId,
msg.sender,
viewPrivacyCondition,
block.timestamp
);
}
function _createCommunity(
OspDataTypes.CreateCommunityData calldata vars
) internal returns (uint256 communityId) {
if (vars.tags.length > Constants.MAX_TAGS_NUMBER) revert OspErrors.TooManyTags();
bool isSuperCreator = _hashRole(Constants.SUPER_COMMUNITY_CREATOR, msg.sender);
if (!isSuperCreator) {
_validateHasProfile(msg.sender);
_validateCommunityCondition(
msg.sender,
vars.handle,
vars.communityConditionAndData,
msg.value
);
}
communityId = ICommunityNFT(_communityNFT()).mint(msg.sender);
_registerHandle(vars.handle, isSuperCreator, communityId);
address joinNFT = _deployJoinNFT(communityId, vars.handle);
_deployCommunityTBA(communityId);
_getCommunityStorage()._communityById[communityId].joinNFT = joinNFT;
IJoinNFT(joinNFT).mint(msg.sender);
address joinCondition;
if (vars.joinConditionInitCode.length != 0) {
joinCondition = _initJoinCondition(communityId, vars.joinConditionInitCode);
_getCommunityStorage()._communityById[communityId].joinCondition = joinCondition;
}
emit OspEvents.CommunityCreated(
communityId,
msg.sender,
vars.handle,
vars.communityConditionAndData,
joinCondition,
joinNFT,
vars.tags,
vars.ctx,
block.timestamp
);
}
function _initJoinCondition(
uint256 communityId,
bytes calldata initCode
) private returns (address joinCondition) {
joinCondition = address(bytes20(initCode[:20]));
_checkJoinCondition(joinCondition);
bytes memory initCallData = initCode[20:];
IJoinCondition(joinCondition).initializeCommunityJoinCondition(communityId, initCallData);
}
function _initActivityCondition(
uint256 communityId,
bytes calldata initCode
) private returns (address activityCondition) {
activityCondition = address(bytes20(initCode[:20]));
_checkActivityCondition(activityCondition);
bytes memory initCallData = initCode[20:];
IActivityCondition(activityCondition).initializeCommunityActivityCondition(
communityId,
initCallData
);
}
function _initViewPrivacyCondition(
uint256 communityId,
bytes calldata initCode
) private returns (address viewPrivacyCondition) {
viewPrivacyCondition = address(bytes20(initCode[:20]));
_checkViewPrivacyCondition(viewPrivacyCondition);
bytes memory initCallData = initCode[20:];
IViewPrivacyCondition(viewPrivacyCondition).initializeCommunityViewPrivacyCondition(
communityId,
initCallData
);
}
function _deployJoinNFT(uint256 communityId, string memory handle) internal returns (address) {
string memory idStr = communityId.toString();
string memory name = string(abi.encodePacked(idStr, Constants.JOIN_NFT_NAME_SUFFIX));
string memory symbol = string(abi.encodePacked(idStr, Constants.JOIN_NFT_SYMBOL_SUFFIX));
bytes memory functionData = abi.encodeWithSelector(
IJoinNFT.initialize.selector,
communityId,
name,
symbol
);
address joinNFT = address(new JoinNFTProxy(functionData));
emit OspEvents.JoinNFTDeployed(communityId, joinNFT, block.timestamp);
return joinNFT;
}
function _deployCommunityTBA(uint256 communityId) internal returns (address) {
if (_getGovernanceStorage()._erc6551AccountImpl == address(0)) {
revert OspErrors.ERC6551AccountImplNotDeployed();
}
address tbaAccount = IERC6551Registry(Constants.ERC6551_REGISTRY).createAccount(
_getGovernanceStorage()._communityAccountProxy,
Constants.COMMUNITY_TBA_SALT,
block.chainid,
_communityNFT(),
communityId
);
ERC6551Account(payable(tbaAccount)).initialize(communityId);
return tbaAccount;
}
function _validateCommunityCondition(
address creator,
string calldata handle,
bytes calldata communityConditionAndData,
uint256 value
) internal {
address communityCondition = address(bytes20(communityConditionAndData[:20]));
_checkCommunityCondition(communityCondition);
bytes memory callData = communityConditionAndData[20:];
ICommunityCondition(communityCondition).processCreateCommunity{value: value}(
creator,
handle,
callData
);
}
function _validateHandle(
string calldata handle,
bool isSuperCreator,
CommunityStorage storage communityStorage
) internal view returns (bytes32 hash) {
bytes memory byteHandle = bytes(handle);
bytes32 handleHash = keccak256(bytes(handle));
if (byteHandle.length == 0 || byteHandle.length > Constants.MAX_COMMUNITY_NAME_LENGTH)
revert OspErrors.HandleLengthInvalid();
GovernanceStorage storage governanceStorage = _getGovernanceStorage();
if (governanceStorage._reserveCommunityHandleHash[handleHash] && !isSuperCreator)
revert OspErrors.HandleTaken();
if (communityStorage._communityIdByHandleHash[handleHash] != 0)
revert OspErrors.HandleTaken();
uint256 byteHandleLength = byteHandle.length;
for (uint256 i; i < byteHandleLength; ) {
if (
(byteHandle[i] < '0' ||
byteHandle[i] > 'z' ||
(byteHandle[i] > '9' && byteHandle[i] < 'a')) && byteHandle[i] != '_'
) revert OspErrors.HandleContainsInvalidCharacters();
unchecked {
++i;
}
}
return keccak256(byteHandle);
}
function _registerHandle(
string calldata handle,
bool isSuperCreator,
uint256 communityId
) internal {
CommunityStorage storage communityStorage = _getCommunityStorage();
bytes32 handleHash = _validateHandle(handle, isSuperCreator, communityStorage);
communityStorage._communityIdByHandleHash[handleHash] = communityId;
communityStorage._communityById[communityId].handle = handle;
}
function _validateCallerHasCommunityRole(uint256 communityId, uint256 role) internal view {
address joinNFT = _getCommunityStorage()._communityById[communityId].joinNFT;
if (joinNFT == address(0)) revert OspErrors.InvalidCommunityId();
if (IJoinNFT(joinNFT).hasRole(role, msg.sender)) return;
revert OspErrors.JoinNFTUnauthorizedAccount();
}
function _communityNFT() internal view returns (address) {
return _getGovernanceStorage()._communityNFT;
}
}
文件 8 的 124:CommunityNFT.sol
pragma solidity 0.8.20;
import './logics/interfaces/OspClient.sol';
import '../interfaces/ICommunityNFT.sol';
import '../libraries/OspErrors.sol';
import './base/OspNFTBase.sol';
import './base/IERC4906.sol';
import '@thirdweb-dev/contracts/extension/upgradeable/ContractMetadata.sol';
import '@openzeppelin/contracts-upgradeable/token/common/ERC2981Upgradeable.sol';
contract CommunityNFT is OspNFTBase, ContractMetadata, ICommunityNFT, IERC4906, ERC2981Upgradeable {
address public immutable OSP;
uint256 internal _tokenIdCounter;
constructor(address osp) {
if (osp == address(0)) revert OspErrors.InitParamsInvalid();
OSP = osp;
}
function initialize(string calldata name, string calldata symbol) external {
super._initialize(name, symbol);
}
function mint(address to) external override returns (uint256) {
if (msg.sender != OSP) revert OspErrors.NotOSP();
unchecked {
uint256 tokenId = ++_tokenIdCounter;
_mint(to, tokenId);
return tokenId;
}
}
function tokenURI(uint256 tokenId) public view override returns (string memory) {
return ICommunityLogic(OSP).getCommunityTokenURI(tokenId);
}
function _afterTokenTransfer(address from, address to, uint256 tokenId) internal override {
ICommunityLogic(OSP).emitCommunityNFTTransferEvent(tokenId, from, to);
super._afterTokenTransfer(from, to, tokenId);
}
function setTokenRoyalty(address receiver, uint96 feeNumerator) external {
if (!OspClient(OSP).hasRole(Constants.GOVERNANCE, _msgSender())) {
revert OspErrors.NotGovernance();
}
_setDefaultRoyalty(receiver, feeNumerator);
}
function updateMetadata() external override {
emit BatchMetadataUpdate(1, type(uint256).max);
}
function burn(uint256 tokenId) public override {
_update(address(this), tokenId, _msgSender());
}
function _canSetContractURI() internal view override returns (bool) {
return OspClient(OSP).hasRole(Constants.GOVERNANCE, _msgSender());
}
function supportsInterface(
bytes4 interfaceId
) public view virtual override(OspNFTBase, ERC2981Upgradeable) returns (bool) {
return
ERC2981Upgradeable.supportsInterface(interfaceId) ||
OspNFTBase.supportsInterface(interfaceId);
}
}
文件 9 的 124:CompositeActivityCond.sol
pragma solidity 0.8.20;
import {IERC165} from '@openzeppelin/contracts/interfaces/IERC165.sol';
import {ERC165Checker} from '@openzeppelin/contracts/utils/introspection/ERC165Checker.sol';
import {OspContext} from 'contracts/core/base/OspContext.sol';
import {IActivityCondition} from 'contracts/interfaces/IActivityCondition.sol';
import {CondErrors} from '../libraries/CondErrors.sol';
import {CondHelpers} from '../libraries/CondHelpers.sol';
import {ICompositeActivityCond} from './interfaces/ICompositeActivityCond.sol';
contract CompositeActivityCond is OspContext, ICompositeActivityCond, IERC165 {
uint256 private constant MAX_CONDITIONS = 5;
mapping(uint256 => CompositeData) internal _dataByCommunity;
constructor(address osp) OspContext(osp) {}
function initializeCommunityActivityCondition(
uint256 communityId,
bytes calldata data
) external override onlyOsp {
(
OperatorEnum operator,
IActivityCondition[] memory conditions,
bytes[] memory initDatas
) = abi.decode(data, (OperatorEnum, IActivityCondition[], bytes[]));
uint256 length = conditions.length;
if (length > MAX_CONDITIONS) revert CondErrors.TooManyConditions();
if (length != initDatas.length) revert CondErrors.ArrayMismatch();
for (uint256 i; i < length; ) {
for (uint256 j; j < i; ) {
if (conditions[i] == conditions[j]) {
revert CondErrors.ArrayDuplicated();
}
unchecked {
++j;
}
}
_checkActivityCondition(address(conditions[i]));
conditions[i].initializeCommunityActivityCondition(communityId, initDatas[i]);
unchecked {
++i;
}
}
_dataByCommunity[communityId].operator = operator;
_dataByCommunity[communityId].conditions = conditions;
}
function processActivity(
uint256 communityId,
address profileOwner,
uint256 profileId
) external override onlyOsp {
IActivityCondition[] storage conditions = _dataByCommunity[communityId].conditions;
OperatorEnum operator = _dataByCommunity[communityId].operator;
if (operator == OperatorEnum.AND) {
for (uint256 i; i < conditions.length; i++) {
conditions[i].processActivity(communityId, profileOwner, profileId);
}
} else {
for (uint256 i; i < conditions.length; i++) {
bool hasError = false;
try conditions[i].processActivity(communityId, profileOwner, profileId) {} catch {
hasError = true;
}
if (!hasError) {
return;
}
}
revert CondErrors.ActivityConditionNotMet();
}
}
function getCompositeData(uint256 communityId) external view returns (CompositeData memory) {
return _dataByCommunity[communityId];
}
function supportsInterface(bytes4 interfaceId) public pure override returns (bool) {
return
interfaceId == type(IActivityCondition).interfaceId ||
interfaceId == type(IERC165).interfaceId ||
interfaceId == type(ICompositeActivityCond).interfaceId;
}
function _checkActivityCondition(address condition) internal view {
if (
!OSP.isAppWhitelisted(condition) ||
!ERC165Checker.supportsInterface(condition, type(IActivityCondition).interfaceId)
) revert CondErrors.ConditionNotWhitelisted();
}
}
文件 10 的 124:CompositeViewPrivacyCond.sol
pragma solidity 0.8.20;
import {IERC165} from '@openzeppelin/contracts/interfaces/IERC165.sol';
import {ERC165Checker} from '@openzeppelin/contracts/utils/introspection/ERC165Checker.sol';
import {OspContext} from 'contracts/core/base/OspContext.sol';
import {IViewPrivacyCondition} from 'contracts/interfaces/IViewPrivacyCondition.sol';
import {CondErrors} from '../libraries/CondErrors.sol';
import {CondHelpers} from '../libraries/CondHelpers.sol';
import {ICompositeViewPrivacyCond} from './interfaces/ICompositeViewPrivacyCond.sol';
contract CompositeViewPrivacyCond is OspContext, ICompositeViewPrivacyCond, IERC165 {
uint256 private constant MAX_CONDITIONS = 5;
mapping(uint256 => CompositeData) internal _dataByCommunity;
constructor(address osp) OspContext(osp) {}
function initializeCommunityViewPrivacyCondition(
uint256 communityId,
bytes calldata data
) external override onlyOsp {
(
OperatorEnum operator,
ICompositeViewPrivacyCond[] memory conditions,
bytes[] memory initDatas
) = abi.decode(data, (OperatorEnum, ICompositeViewPrivacyCond[], bytes[]));
uint256 length = conditions.length;
if (length > MAX_CONDITIONS) revert CondErrors.TooManyConditions();
if (length != initDatas.length) revert CondErrors.ArrayMismatch();
for (uint256 i; i < length; ) {
for (uint256 j; j < i; ) {
if (conditions[i] == conditions[j]) {
revert CondErrors.ArrayDuplicated();
}
unchecked {
++j;
}
}
_checkViewPrivacyCondition(address(conditions[i]));
conditions[i].initializeCommunityViewPrivacyCondition(communityId, initDatas[i]);
unchecked {
++i;
}
}
_dataByCommunity[communityId].operator = operator;
_dataByCommunity[communityId].conditions = conditions;
}
function isViewPrivacyAllowed(
uint256 communityId,
address profileOwner,
uint256 profileId
) external view override onlyOsp returns (bool) {
IViewPrivacyCondition[] storage conditions = _dataByCommunity[communityId].conditions;
OperatorEnum operator = _dataByCommunity[communityId].operator;
if (operator == OperatorEnum.AND) {
for (uint256 i; i < conditions.length; i++) {
if (!conditions[i].isViewPrivacyAllowed(communityId, profileOwner, profileId)) {
return false;
}
}
return true;
} else {
for (uint256 i; i < conditions.length; i++) {
if (conditions[i].isViewPrivacyAllowed(communityId, profileOwner, profileId)) {
return true;
}
}
return false;
}
}
function getCompositeData(uint256 communityId) external view returns (CompositeData memory) {
return _dataByCommunity[communityId];
}
function supportsInterface(bytes4 interfaceId) public pure override returns (bool) {
return
interfaceId == type(IViewPrivacyCondition).interfaceId ||
interfaceId == type(IERC165).interfaceId ||
interfaceId == type(ICompositeViewPrivacyCond).interfaceId;
}
function _checkViewPrivacyCondition(address condition) internal view {
if (
!OSP.isAppWhitelisted(condition) ||
!ERC165Checker.supportsInterface(condition, type(IViewPrivacyCondition).interfaceId)
) revert CondErrors.ConditionNotWhitelisted();
}
}
文件 11 的 124:CondDataTypes.sol
pragma solidity 0.8.20;
library CondDataTypes {
struct SlotNFTCondData {
bool whitelist;
uint256 minHandleLength;
}
struct FixedFeeCondData {
uint256 price1Letter;
uint256 price2Letter;
uint256 price3Letter;
uint256 price4Letter;
uint256 price5Letter;
uint256 price6Letter;
uint256 price7ToMoreLetter;
uint256 createStartTime;
}
}
文件 12 的 124:CondErrors.sol
pragma solidity 0.8.20;
library CondErrors {
error ArrayMismatch();
error ArrayDuplicated();
error ConditionNotWhitelisted();
error NotWhitelisted();
error ConditionDataMismatch();
error InitParamsInvalid();
error HandleLengthNotEnough();
error SlotNFTNotWhitelisted();
error NotSlotNFTOwner();
error SlotNFTAlreadyUsed();
error NotCreateTime();
error NotPresaleTime();
error InvalidTicket();
error InsufficientPayment();
error SignatureInvalid();
error JoinNFTTransferInvalid();
error JoinInvalid();
error AccessDenied();
error ActivityConditionNotMet();
error NotEnoughERC721Balance();
error TooManyConditions();
}
文件 13 的 124:CondHelpers.sol
pragma solidity 0.8.20;
import {CondDataTypes} from './CondDataTypes.sol';
library CondHelpers {
function getHandleETHPrice(
string calldata handle,
CondDataTypes.FixedFeeCondData memory fixedFeeCondData
) internal pure returns (uint256) {
uint256 len = bytes(handle).length;
uint256 ethPrice;
if (len >= 7) {
ethPrice = fixedFeeCondData.price7ToMoreLetter;
} else if (len == 6) {
ethPrice = fixedFeeCondData.price6Letter;
} else if (len == 5) {
ethPrice = fixedFeeCondData.price5Letter;
} else if (len == 4) {
ethPrice = fixedFeeCondData.price4Letter;
} else if (len == 3) {
ethPrice = fixedFeeCondData.price3Letter;
} else if (len == 2) {
ethPrice = fixedFeeCondData.price2Letter;
} else {
ethPrice = fixedFeeCondData.price1Letter;
}
return ethPrice;
}
}
文件 14 的 124:ConditionContext.sol
pragma solidity 0.8.20;
import '@openzeppelin/contracts/utils/Context.sol';
import 'contracts/libraries/OspErrors.sol';
abstract contract ConditionContext is Context {
address immutable OSP;
address immutable COMPOSITE_CONDITION;
constructor(address osp, address compositeCondition) {
if (osp == address(0)) revert OspErrors.InitParamsInvalid();
if (compositeCondition == address(0)) revert OspErrors.InitParamsInvalid();
OSP = osp;
COMPOSITE_CONDITION = compositeCondition;
}
modifier onlyOsp() {
if (_msgSender() != address(OSP)) revert OspErrors.NotOSP();
_;
}
modifier onlyOspOrCompositeCondition() {
if (_msgSender() != COMPOSITE_CONDITION && _msgSender() != address(OSP))
revert OspErrors.InvalidSender();
_;
}
modifier nonPayable() {
if (msg.value != 0) revert OspErrors.InvalidValue();
_;
}
}
文件 15 的 124:Constants.sol
pragma solidity 0.8.20;
library Constants {
string internal constant FOLLOW_NFT_NAME_SUFFIX = "'s Follower";
string internal constant FOLLOW_NFT_SYMBOL_SUFFIX = '-FOL';
string internal constant JOIN_NFT_NAME_SUFFIX = "'s Member";
string internal constant JOIN_NFT_SYMBOL_SUFFIX = '-MBR';
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');
bytes32 internal constant SUPER_COMMUNITY_CREATOR = keccak256('SUPER_COMMUNITY_CREATOR');
uint256 internal constant MAX_TAGS_NUMBER = 10;
uint256 internal constant COMMUNITY_NULL_ACCESS = 0x00000000;
uint256 internal constant COMMUNITY_MODERATOR_ACCESS = 0x55555555;
uint256 internal constant COMMUNITY_ADMIN_ACCESS = 0xaaaaaaaa;
uint256 internal constant ROYALTY_DENOMINATOR = 10000;
}
文件 16 的 124:ContentLogic.sol
pragma solidity 0.8.20;
import {IActivityExtension} from '../../interfaces/IActivityExtension.sol';
import {IReferenceCondition} from '../../interfaces/IReferenceCondition.sol';
import {IOpenReaction} from '../../interfaces/IOpenReaction.sol';
import {OspHelpers} from '../../libraries/OspHelpers.sol';
import {OspDataTypes} from '../../libraries/OspDataTypes.sol';
import {Constants} from '../../libraries/Constants.sol';
import {OspErrors} from '../../libraries/OspErrors.sol';
import {OspEvents} from '../../libraries/OspEvents.sol';
import {IContentLogic} from './interfaces/IContentLogic.sol';
import {OspLogicBase} from './OspLogicBase.sol';
import {Payment} from '../../libraries/Payment.sol';
import {IERC721} from '@openzeppelin/contracts/token/ERC721/IERC721.sol';
import {IActivityCondition} from '../../interfaces/IActivityCondition.sol';
import {EnumerableSet} from '@openzeppelin/contracts/utils/structs/EnumerableSet.sol';
contract ContentLogic is IContentLogic, OspLogicBase {
using EnumerableSet for EnumerableSet.AddressSet;
function createActivity(
OspDataTypes.CreateActivityData calldata vars
) external payable override whenPublishingEnabled returns (uint256 contentId) {
contentId = _createActivity(msg.sender, vars);
}
function createActivityWithSig(
OspDataTypes.CreateActivityData calldata vars,
OspDataTypes.EIP712Signature calldata sig
) external whenPublishingEnabled returns (uint256 contentId) {
unchecked {
_validateRecoveredAddress(
_calculateDigest(
keccak256(
abi.encode(
OspDataTypes.CREATE_ACTIVITY_WITH_SIG_TYPEHASH,
vars.profileId,
vars.communityId,
keccak256(bytes(vars.contentURI)),
keccak256(vars.extensionInitCode),
keccak256(vars.referenceConditionInitCode),
keccak256(vars.ctx),
_getProfileStorage()._sigNonces[sig.signer]++,
sig.deadline
)
)
),
sig
);
}
contentId = _createActivity(sig.signer, vars);
}
function createComment(
OspDataTypes.CreateCommentData calldata vars
) external payable whenPublishingEnabled returns (uint256 contentId) {
_validateIsProfileOwner(msg.sender, vars.profileId);
contentId = _createComment(vars);
}
function createCommentWithSig(
OspDataTypes.CreateCommentData calldata vars,
OspDataTypes.EIP712Signature calldata sig
) external whenPublishingEnabled returns (uint256 contentId) {
unchecked {
_validateRecoveredAddress(
_calculateDigest(
keccak256(
abi.encode(
OspDataTypes.CREATE_COMMENT_WITH_SIG_TYPEHASH,
vars.profileId,
vars.communityId,
keccak256(bytes(vars.contentURI)),
vars.referencedProfileId,
vars.referencedContentId,
keccak256(vars.referenceConditionInitCode),
keccak256(vars.referenceConditionData),
keccak256(vars.ctx),
_getProfileStorage()._sigNonces[sig.signer]++,
sig.deadline
)
)
),
sig
);
}
_validateIsProfileOwner(sig.signer, vars.profileId);
contentId = _createComment(vars);
}
function createOpenReaction(
OspDataTypes.CreateOpenReactionData calldata vars
) external payable whenPublishingEnabled {
_validateIsProfileOwner(msg.sender, vars.profileId);
_createOpenReaction(vars);
}
function createOpenReactionWithSig(
OspDataTypes.CreateOpenReactionData calldata vars,
OspDataTypes.EIP712Signature calldata sig
) external whenPublishingEnabled {
unchecked {
_validateRecoveredAddress(
_calculateDigest(
keccak256(
abi.encode(
OspDataTypes.CREATE_OPEN_REACTION_WITH_SIG_TYPEHASH,
vars.profileId,
vars.communityId,
vars.referencedProfileId,
vars.referencedContentId,
keccak256(vars.reactionAndData),
keccak256(vars.referenceConditionData),
keccak256(vars.ctx),
_getProfileStorage()._sigNonces[sig.signer]++,
sig.deadline
)
)
),
sig
);
}
_validateIsProfileOwner(sig.signer, vars.profileId);
_createOpenReaction(vars);
}
function createMegaphone(
OspDataTypes.CreateMegaphoneData calldata vars
) external payable whenPublishingEnabled returns (uint256 megaphoneId) {
_validateIsProfileOwner(msg.sender, vars.profileId);
return _createMegaphone(vars);
}
function getContentCount(uint256 profileId) external view override returns (uint256) {
return _getProfileStorage()._profileById[profileId].contentCount;
}
function getContent(
uint256 profileId,
uint256 contentId
) external view override returns (OspDataTypes.ContentStruct memory) {
return _getContentStorage()._contentByIdByProfile[profileId][contentId];
}
function getCommunityIdByContent(
uint256 profileId,
uint256 contentId
) external view returns (uint256) {
return _getContentStorage()._contentByIdByProfile[profileId][contentId].communityId;
}
function _createActivity(
address profileOwner,
OspDataTypes.CreateActivityData calldata vars
) internal returns (uint256 contentId) {
_validateIsProfileOwner(profileOwner, vars.profileId);
if (bytes(vars.contentURI).length == 0) {
revert OspErrors.InvalidContentURI();
}
uint256 profileId = vars.profileId;
_validateCallerIsJoinCommunity(profileId, vars.communityId);
_validateActivity(vars.communityId, profileOwner, vars.profileId);
contentId = ++_getProfileStorage()._profileById[profileId].contentCount;
OspDataTypes.ContentStruct storage activityContent = _getContentStorage()
._contentByIdByProfile[vars.profileId][contentId];
activityContent.contentURI = vars.contentURI;
activityContent.communityId = vars.communityId;
address extension;
if (vars.extensionInitCode.length != 0) {
extension = _initActivityExtension(
profileId,
contentId,
vars.extensionInitCode,
msg.value
);
activityContent.extension = extension;
}
EnumerableSet.AddressSet storage communityExtensionWhitelist = _getCommunityStorage()
._activityExtensionWhitelistByCommunity[vars.communityId];
bool enableExtensionWhitelist = communityExtensionWhitelist.length() != 0;
if (enableExtensionWhitelist && !communityExtensionWhitelist.contains(extension)) {
revert OspErrors.ExtensionNotCommunityWhitelisted();
}
if (!enableExtensionWhitelist && vars.communityId != 0 && extension != address(0)) {
revert OspErrors.ExtensionNotCommunityWhitelisted();
}
address referenceCondition;
if (vars.referenceConditionInitCode.length != 0) {
referenceCondition = _initReferenceCondition(
vars.profileId,
contentId,
vars.communityId,
vars.referenceConditionInitCode
);
activityContent.referenceCondition = referenceCondition;
}
emit OspEvents.ActivityCreated(
vars.profileId,
contentId,
vars.communityId,
vars.contentURI,
extension,
referenceCondition,
vars.ctx,
block.timestamp
);
}
function _createComment(
OspDataTypes.CreateCommentData calldata vars
) internal returns (uint256 contentId) {
if (bytes(vars.contentURI).length == 0) {
revert OspErrors.InvalidContentURI();
}
_validateCallerIsJoinCommunity(vars.profileId, vars.communityId);
_validateReferenced(
vars.profileId,
vars.communityId,
vars.referencedProfileId,
vars.referencedContentId,
vars.referenceConditionData,
msg.value
);
contentId = ++_getProfileStorage()._profileById[vars.profileId].contentCount;
OspDataTypes.ContentStruct storage commentContent = _getContentStorage()
._contentByIdByProfile[vars.profileId][contentId];
commentContent.referencedProfileId = vars.referencedProfileId;
commentContent.referencedContentId = vars.referencedContentId;
commentContent.contentURI = vars.contentURI;
commentContent.communityId = vars.communityId;
address referenceCondition;
if (vars.referenceConditionInitCode.length != 0) {
referenceCondition = _initReferenceCondition(
vars.profileId,
contentId,
vars.communityId,
vars.referenceConditionInitCode
);
commentContent.referenceCondition = referenceCondition;
}
emit OspEvents.CommentCreated(
vars.profileId,
contentId,
vars.communityId,
vars.contentURI,
vars.referencedProfileId,
vars.referencedContentId,
referenceCondition,
vars.ctx,
block.timestamp
);
}
function _createMegaphone(
OspDataTypes.CreateMegaphoneData calldata vars
) internal returns (uint256 megaphoneId) {
if (vars.tags.length > Constants.MAX_TAGS_NUMBER) revert OspErrors.TooManyTags();
ContentStorage storage contentStorage = _getContentStorage();
if (
vars.referencedContentId == 0 ||
_getProfileStorage()._profileById[vars.referencedProfileId].contentCount <
vars.referencedContentId
) {
revert OspErrors.ContentDoesNotExist();
}
if (
contentStorage
._contentByIdByProfile[vars.referencedProfileId][vars.referencedContentId]
.referenceCondition != address(0)
) {
revert OspErrors.ContentNotPublic();
}
if (!_getGovernanceStorage()._tokenWhitelisted[vars.currency]) {
revert OspErrors.InvalidToken();
}
megaphoneId = ++_getContentStorage()._megaphoneCount;
address treasure = _getGovernanceStorage()._treasure;
if (treasure == address(0)) revert OspErrors.InvalidTreasure();
if (vars.currency == address(0)) {
if (msg.value != vars.amount) revert OspErrors.DataMismatch();
Payment.payNative(treasure, vars.amount);
} else {
Payment.payERC20(vars.currency, msg.sender, treasure, vars.amount);
}
emit OspEvents.MegaphoneCreated(
megaphoneId,
vars.referencedProfileId,
vars.referencedContentId,
vars.profileId,
vars.tags,
vars.startTime,
vars.duration,
vars.currency,
vars.amount,
vars.ctx,
block.timestamp
);
}
function _createOpenReaction(OspDataTypes.CreateOpenReactionData calldata vars) internal {
_validateCallerIsJoinCommunity(vars.profileId, vars.communityId);
if (msg.value < vars.reactionValue) {
revert OspErrors.InvalidValue();
}
_validateReferenced(
vars.profileId,
vars.communityId,
vars.referencedProfileId,
vars.referencedContentId,
vars.referenceConditionData,
msg.value - vars.reactionValue
);
(address openReaction, bytes memory openReactionData) = _initOpenReaction(
vars.profileId,
vars.referencedProfileId,
vars.referencedContentId,
vars.reactionAndData,
vars.reactionValue
);
emit OspEvents.OpenReactionCreated(
vars.profileId,
vars.referencedProfileId,
vars.referencedContentId,
vars.communityId,
openReaction,
openReactionData,
vars.ctx,
block.timestamp
);
}
function _initReferenceCondition(
uint256 profileId,
uint256 contentId,
uint256 communityId,
bytes calldata initCode
) internal returns (address referenceCondition) {
referenceCondition = address(bytes20(initCode[:20]));
_checkReferenceCondition(referenceCondition);
bytes memory initCallData = initCode[20:];
IReferenceCondition(referenceCondition).initializeReferenceCondition(
profileId,
contentId,
communityId,
initCallData
);
}
function _initActivityExtension(
uint256 profileId,
uint256 contentId,
bytes calldata initCode,
uint256 value
) internal returns (address extension) {
extension = address(bytes20(initCode[:20]));
_checkActivityExtension(extension);
bytes memory initCallData = initCode[20:];
IActivityExtension(extension).initializeActivityExtension{value: value}(
profileId,
contentId,
initCallData
);
}
function _initOpenReaction(
uint256 profileId,
uint256 referencedProfileId,
uint256 referencedContentId,
bytes calldata initCode,
uint256 value
) internal returns (address openReaction, bytes memory openReactionData) {
openReaction = address(bytes20(initCode[:20]));
_checkOpenReaction(openReaction);
openReactionData = initCode[20:];
IOpenReaction(openReaction).processReaction{value: value}(
profileId,
referencedProfileId,
referencedContentId,
openReactionData
);
}
function _validateReferenced(
uint256 profileId,
uint256 communityId,
uint256 referencedProfileId,
uint256 referencedContentId,
bytes calldata referenceConditionData,
uint256 value
) internal {
OspDataTypes.ContentStruct storage referencedContent = _getContentStorage()
._contentByIdByProfile[referencedProfileId][referencedContentId];
if (
bytes(referencedContent.contentURI).length != 0 ||
referencedContent.referencedProfileId != 0
) {
address referenceCondition = referencedContent.referenceCondition;
if (referenceCondition != address(0)) {
IReferenceCondition(referenceCondition).processReactionReference{value: value}(
profileId,
communityId,
referencedProfileId,
referencedContentId,
referenceConditionData
);
}
} else {
revert OspErrors.ContentDoesNotExist();
}
}
function _validateCallerIsJoinCommunity(uint256 profileId, uint256 communityId) internal view {
if (communityId != 0) {
address owner = _ownerOf(profileId);
address joinNFT = _getCommunityStorage()._communityById[communityId].joinNFT;
if (joinNFT == address(0)) {
revert OspErrors.InvalidCommunityId();
}
uint256 isJoin = IERC721(joinNFT).balanceOf(owner);
if (isJoin == 0) {
revert OspErrors.NotJoinCommunity();
}
}
}
function _validateActivity(uint256 communityId, address owner, uint256 profileId) internal {
address activityCondition = _getCommunityStorage()
._communityById[communityId]
.activityCondition;
if (activityCondition == address(0)) return;
IActivityCondition(activityCondition).processActivity(communityId, owner, profileId);
}
}
文件 17 的 124:Context.sol
pragma solidity ^0.8.20;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 18 的 124:ContextUpgradeable.sol
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
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;
}
}
文件 19 的 124:ContractMetadata.sol
pragma solidity ^0.8.0;
import "../interface/IContractMetadata.sol";
library ContractMetadataStorage {
bytes32 public constant CONTRACT_METADATA_STORAGE_POSITION =
0x4bc804ba64359c0e35e5ed5d90ee596ecaa49a3a930ddcb1470ea0dd625da900;
struct Data {
string contractURI;
}
function data() internal pure returns (Data storage data_) {
bytes32 position = CONTRACT_METADATA_STORAGE_POSITION;
assembly {
data_.slot := position
}
}
}
abstract contract ContractMetadata is IContractMetadata {
function setContractURI(string memory _uri) external override {
if (!_canSetContractURI()) {
revert("Not authorized");
}
_setupContractURI(_uri);
}
function _setupContractURI(string memory _uri) internal {
string memory prevURI = _contractMetadataStorage().contractURI;
_contractMetadataStorage().contractURI = _uri;
emit ContractURIUpdated(prevURI, _uri);
}
function contractURI() public view virtual override returns (string memory) {
return _contractMetadataStorage().contractURI;
}
function _contractMetadataStorage() internal pure returns (ContractMetadataStorage.Data storage data) {
data = ContractMetadataStorage.data();
}
function _canSetContractURI() internal view virtual returns (bool);
}
文件 20 的 124:ECDSA.sol
pragma solidity ^0.8.20;
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS
}
error ECDSAInvalidSignature();
error ECDSAInvalidSignatureLength(uint256 length);
error ECDSAInvalidSignatureS(bytes32 s);
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
}
}
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
_throwError(error, errorArg);
return recovered;
}
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {
unchecked {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
}
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
_throwError(error, errorArg);
return recovered;
}
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError, bytes32) {
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS, s);
}
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature, bytes32(0));
}
return (signer, RecoverError.NoError, bytes32(0));
}
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
_throwError(error, errorArg);
return recovered;
}
function _throwError(RecoverError error, bytes32 errorArg) private pure {
if (error == RecoverError.NoError) {
return;
} else if (error == RecoverError.InvalidSignature) {
revert ECDSAInvalidSignature();
} else if (error == RecoverError.InvalidSignatureLength) {
revert ECDSAInvalidSignatureLength(uint256(errorArg));
} else if (error == RecoverError.InvalidSignatureS) {
revert ECDSAInvalidSignatureS(errorArg);
}
}
}
文件 21 的 124:EIP712Base.sol
pragma solidity 0.8.20;
import '../../libraries/OspDataTypes.sol';
import '../../libraries/OspErrors.sol';
import '@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol';
abstract contract EIP712Base {
using SignatureChecker for address;
bytes32 internal constant EIP712_REVISION_HASH = keccak256('1');
function _validateRecoveredAddress(
bytes32 digest,
OspDataTypes.EIP712Signature calldata sig
) internal view {
if (sig.deadline < block.timestamp) revert OspErrors.SignatureExpired();
if (!sig.signer.isValidSignatureNow(digest, sig.signature)) {
revert OspErrors.SignatureInvalid();
}
}
function _calculateDomainSeparator() internal view virtual returns (bytes32);
function _calculateDigest(bytes32 hashedMessage) internal view returns (bytes32) {
bytes32 digest;
unchecked {
digest = keccak256(
abi.encodePacked('\x19\x01', _calculateDomainSeparator(), hashedMessage)
);
}
return digest;
}
}
文件 22 的 124:ERC165.sol
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
文件 23 的 124:ERC165Checker.sol
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
library ERC165Checker {
bytes4 private constant INTERFACE_ID_INVALID = 0xffffffff;
function supportsERC165(address account) internal view returns (bool) {
return
supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) &&
!supportsERC165InterfaceUnchecked(account, INTERFACE_ID_INVALID);
}
function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {
return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId);
}
function getSupportedInterfaces(
address account,
bytes4[] memory interfaceIds
) internal view returns (bool[] memory) {
bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);
if (supportsERC165(account)) {
for (uint256 i = 0; i < interfaceIds.length; i++) {
interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]);
}
}
return interfaceIdsSupported;
}
function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {
if (!supportsERC165(account)) {
return false;
}
for (uint256 i = 0; i < interfaceIds.length; i++) {
if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) {
return false;
}
}
return true;
}
function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) {
bytes memory encodedParams = abi.encodeCall(IERC165.supportsInterface, (interfaceId));
bool success;
uint256 returnSize;
uint256 returnValue;
assembly {
success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20)
returnSize := returndatasize()
returnValue := mload(0x00)
}
return success && returnSize >= 0x20 && returnValue > 0;
}
}
文件 24 的 124:ERC165Upgradeable.sol
pragma solidity ^0.8.20;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";
abstract contract ERC165Upgradeable is Initializable, IERC165 {
function __ERC165_init() internal onlyInitializing {
}
function __ERC165_init_unchained() internal onlyInitializing {
}
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
文件 25 的 124:ERC1967Proxy.sol
pragma solidity ^0.8.20;
import {Proxy} from "../Proxy.sol";
import {ERC1967Utils} from "./ERC1967Utils.sol";
contract ERC1967Proxy is Proxy {
constructor(address implementation, bytes memory _data) payable {
ERC1967Utils.upgradeToAndCall(implementation, _data);
}
function _implementation() internal view virtual override returns (address) {
return ERC1967Utils.getImplementation();
}
}
文件 26 的 124:ERC1967Utils.sol
pragma solidity ^0.8.20;
import {IBeacon} from "../beacon/IBeacon.sol";
import {Address} from "../../utils/Address.sol";
import {StorageSlot} from "../../utils/StorageSlot.sol";
library ERC1967Utils {
event Upgraded(address indexed implementation);
event AdminChanged(address previousAdmin, address newAdmin);
event BeaconUpgraded(address indexed beacon);
bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
error ERC1967InvalidImplementation(address implementation);
error ERC1967InvalidAdmin(address admin);
error ERC1967InvalidBeacon(address beacon);
error ERC1967NonPayable();
function getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;
}
function _setImplementation(address newImplementation) private {
if (newImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(newImplementation);
}
StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
}
function upgradeToAndCall(address newImplementation, bytes memory data) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
if (data.length > 0) {
Address.functionDelegateCall(newImplementation, data);
} else {
_checkNonPayable();
}
}
bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
function getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(ADMIN_SLOT).value;
}
function _setAdmin(address newAdmin) private {
if (newAdmin == address(0)) {
revert ERC1967InvalidAdmin(address(0));
}
StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
}
function changeAdmin(address newAdmin) internal {
emit AdminChanged(getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
function getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(BEACON_SLOT).value;
}
function _setBeacon(address newBeacon) private {
if (newBeacon.code.length == 0) {
revert ERC1967InvalidBeacon(newBeacon);
}
StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;
address beaconImplementation = IBeacon(newBeacon).implementation();
if (beaconImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(beaconImplementation);
}
}
function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
} else {
_checkNonPayable();
}
}
function _checkNonPayable() private {
if (msg.value > 0) {
revert ERC1967NonPayable();
}
}
}
文件 27 的 124:ERC20FeeJoinCond.sol
pragma solidity 0.8.20;
import {OspErrors} from '../../../libraries/OspErrors.sol';
import {FeeConditionBase} from '../FeeConditionBase.sol';
import {JoinConditionBase} from '../../base/JoinConditionBase.sol';
import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
struct CommunityData {
address currency;
uint256 amount;
address recipient;
}
contract ERC20FeeJoinCond is FeeConditionBase, JoinConditionBase {
using SafeERC20 for IERC20;
mapping(uint256 => CommunityData) internal _dataByCommunity;
constructor(address osp) JoinConditionBase(osp) {}
function _initializeCommunityJoinCondition(
uint256 communityId,
bytes calldata data
) internal override {
(address currency, uint256 amount, address recipient) = abi.decode(
data,
(address, uint256, address)
);
if (!_tokenWhitelisted(currency) || recipient == address(0) || amount == 0)
revert OspErrors.InitParamsInvalid();
_dataByCommunity[communityId].amount = amount;
_dataByCommunity[communityId].currency = currency;
_dataByCommunity[communityId].recipient = recipient;
}
function _processJoin(
address follower,
uint256 communityId,
bytes calldata data
) internal override nonPayable {
uint256 amount = _dataByCommunity[communityId].amount;
address currency = _dataByCommunity[communityId].currency;
_validateDataIsExpected(data, currency, amount);
IERC20(currency).safeTransferFrom(
follower,
_dataByCommunity[communityId].recipient,
amount
);
}
function getCommunityData(uint256 communityId) external view returns (CommunityData memory) {
return _dataByCommunity[communityId];
}
}
文件 28 的 124:ERC2981Upgradeable.sol
pragma solidity ^0.8.20;
import {IERC2981} from "@openzeppelin/contracts/interfaces/IERC2981.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {ERC165Upgradeable} from "../../utils/introspection/ERC165Upgradeable.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";
abstract contract ERC2981Upgradeable is Initializable, IERC2981, ERC165Upgradeable {
struct RoyaltyInfo {
address receiver;
uint96 royaltyFraction;
}
struct ERC2981Storage {
RoyaltyInfo _defaultRoyaltyInfo;
mapping(uint256 tokenId => RoyaltyInfo) _tokenRoyaltyInfo;
}
bytes32 private constant ERC2981StorageLocation = 0xdaedc9ab023613a7caf35e703657e986ccfad7e3eb0af93a2853f8d65dd86b00;
function _getERC2981Storage() private pure returns (ERC2981Storage storage $) {
assembly {
$.slot := ERC2981StorageLocation
}
}
error ERC2981InvalidDefaultRoyalty(uint256 numerator, uint256 denominator);
error ERC2981InvalidDefaultRoyaltyReceiver(address receiver);
error ERC2981InvalidTokenRoyalty(uint256 tokenId, uint256 numerator, uint256 denominator);
error ERC2981InvalidTokenRoyaltyReceiver(uint256 tokenId, address receiver);
function __ERC2981_init() internal onlyInitializing {
}
function __ERC2981_init_unchained() internal onlyInitializing {
}
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165Upgradeable) returns (bool) {
return interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId);
}
function royaltyInfo(uint256 tokenId, uint256 salePrice) public view virtual returns (address, uint256) {
ERC2981Storage storage $ = _getERC2981Storage();
RoyaltyInfo memory royalty = $._tokenRoyaltyInfo[tokenId];
if (royalty.receiver == address(0)) {
royalty = $._defaultRoyaltyInfo;
}
uint256 royaltyAmount = (salePrice * royalty.royaltyFraction) / _feeDenominator();
return (royalty.receiver, royaltyAmount);
}
function _feeDenominator() internal pure virtual returns (uint96) {
return 10000;
}
function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual {
ERC2981Storage storage $ = _getERC2981Storage();
uint256 denominator = _feeDenominator();
if (feeNumerator > denominator) {
revert ERC2981InvalidDefaultRoyalty(feeNumerator, denominator);
}
if (receiver == address(0)) {
revert ERC2981InvalidDefaultRoyaltyReceiver(address(0));
}
$._defaultRoyaltyInfo = RoyaltyInfo(receiver, feeNumerator);
}
function _deleteDefaultRoyalty() internal virtual {
ERC2981Storage storage $ = _getERC2981Storage();
delete $._defaultRoyaltyInfo;
}
function _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) internal virtual {
ERC2981Storage storage $ = _getERC2981Storage();
uint256 denominator = _feeDenominator();
if (feeNumerator > denominator) {
revert ERC2981InvalidTokenRoyalty(tokenId, feeNumerator, denominator);
}
if (receiver == address(0)) {
revert ERC2981InvalidTokenRoyaltyReceiver(tokenId, address(0));
}
$._tokenRoyaltyInfo[tokenId] = RoyaltyInfo(receiver, feeNumerator);
}
function _resetTokenRoyalty(uint256 tokenId) internal virtual {
ERC2981Storage storage $ = _getERC2981Storage();
delete $._tokenRoyaltyInfo[tokenId];
}
}
文件 29 的 124:ERC6551Account.sol
pragma solidity 0.8.20;
import {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';
import {IERC721Receiver} from '@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol';
import {IERC1155Receiver} from '@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol';
import {OspErrors} from '../../libraries/OspErrors.sol';
import {OspClient} from '../logics/interfaces/OspClient.sol';
import {IERC721} from '@openzeppelin/contracts/token/ERC721/IERC721.sol';
contract ERC6551Account is IERC721Receiver, IERC1155Receiver {
struct Execution {
address target;
uint256 value;
bytes data;
}
address immutable OSP;
uint256 public tokenId;
constructor(address osp) {
OSP = osp;
}
function initialize(uint256 communityId) external {
if (msg.sender != OSP) revert OspErrors.NotOSP();
tokenId = communityId;
}
function setCommunityId(uint256 communityId) external {
if (tokenId == 0 && OspClient(OSP).getCommunityAccount(communityId) == address(this)) {
tokenId = communityId;
return;
}
revert OspErrors.InitParamsInvalid();
}
function execute(
Execution calldata execution
) public payable virtual returns (bytes memory result) {
_onlyOwner(msg.sender);
result = _exec(execution.target, execution.value, execution.data);
}
function executeBatch(
Execution[] calldata executions
) public payable virtual returns (bytes[] memory results) {
_onlyOwner(msg.sender);
uint256 executionsLength = executions.length;
results = new bytes[](executionsLength);
for (uint256 i = 0; i < executionsLength; ) {
results[i] = _exec(executions[i].target, executions[i].value, executions[i].data);
unchecked {
++i;
}
}
}
function onERC721Received(
address,
address,
uint256,
bytes calldata
) external pure override returns (bytes4) {
return IERC721Receiver.onERC721Received.selector;
}
function onERC1155Received(
address,
address,
uint256,
uint256,
bytes calldata
) external pure override returns (bytes4) {
return IERC1155Receiver.onERC1155Received.selector;
}
function onERC1155BatchReceived(
address,
address,
uint256[] calldata,
uint256[] calldata,
bytes calldata
) external pure override returns (bytes4) {
return IERC1155Receiver.onERC1155BatchReceived.selector;
}
function supportsInterface(bytes4 interfaceId) external view virtual override returns (bool) {
return
interfaceId == type(IERC721Receiver).interfaceId ||
interfaceId == type(IERC1155Receiver).interfaceId ||
interfaceId == type(IERC165).interfaceId;
}
function _exec(
address target,
uint256 value,
bytes memory data
) internal returns (bytes memory result) {
bool success;
(success, result) = target.call{value: value}(data);
if (!success) {
assembly ('memory-safe') {
revert(add(result, 32), mload(result))
}
}
}
function _onlyOwner(address account) internal view {
if (account != IERC721(OspClient(OSP).getCommunityNFT()).ownerOf(tokenId))
revert OspErrors.NotCommunityOwner();
}
receive() external payable {}
}
文件 30 的 124:ERC721BurnableUpgradeable.sol
pragma solidity ^0.8.20;
import {ERC721Upgradeable} from "../ERC721Upgradeable.sol";
import {ContextUpgradeable} from "../../../utils/ContextUpgradeable.sol";
import {Initializable} from "../../../proxy/utils/Initializable.sol";
abstract contract ERC721BurnableUpgradeable is Initializable, ContextUpgradeable, ERC721Upgradeable {
function __ERC721Burnable_init() internal onlyInitializing {
}
function __ERC721Burnable_init_unchained() internal onlyInitializing {
}
function burn(uint256 tokenId) public virtual {
_update(address(0), tokenId, _msgSender());
}
}
文件 31 的 124:ERC721EnumerableUpgradeable.sol
pragma solidity ^0.8.20;
import {ERC721Upgradeable} from "../ERC721Upgradeable.sol";
import {IERC721Enumerable} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {Initializable} from "../../../proxy/utils/Initializable.sol";
abstract contract ERC721EnumerableUpgradeable is Initializable, ERC721Upgradeable, IERC721Enumerable {
struct ERC721EnumerableStorage {
mapping(address owner => mapping(uint256 index => uint256)) _ownedTokens;
mapping(uint256 tokenId => uint256) _ownedTokensIndex;
uint256[] _allTokens;
mapping(uint256 tokenId => uint256) _allTokensIndex;
}
bytes32 private constant ERC721EnumerableStorageLocation = 0x645e039705490088daad89bae25049a34f4a9072d398537b1ab2425f24cbed00;
function _getERC721EnumerableStorage() private pure returns (ERC721EnumerableStorage storage $) {
assembly {
$.slot := ERC721EnumerableStorageLocation
}
}
error ERC721OutOfBoundsIndex(address owner, uint256 index);
error ERC721EnumerableForbiddenBatchMint();
function __ERC721Enumerable_init() internal onlyInitializing {
}
function __ERC721Enumerable_init_unchained() internal onlyInitializing {
}
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721Upgradeable) returns (bool) {
return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId);
}
function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual returns (uint256) {
ERC721EnumerableStorage storage $ = _getERC721EnumerableStorage();
if (index >= balanceOf(owner)) {
revert ERC721OutOfBoundsIndex(owner, index);
}
return $._ownedTokens[owner][index];
}
function totalSupply() public view virtual returns (uint256) {
ERC721EnumerableStorage storage $ = _getERC721EnumerableStorage();
return $._allTokens.length;
}
function tokenByIndex(uint256 index) public view virtual returns (uint256) {
ERC721EnumerableStorage storage $ = _getERC721EnumerableStorage();
if (index >= totalSupply()) {
revert ERC721OutOfBoundsIndex(address(0), index);
}
return $._allTokens[index];
}
function _update(address to, uint256 tokenId, address auth) internal virtual override returns (address) {
address previousOwner = super._update(to, tokenId, auth);
if (previousOwner == address(0)) {
_addTokenToAllTokensEnumeration(tokenId);
} else if (previousOwner != to) {
_removeTokenFromOwnerEnumeration(previousOwner, tokenId);
}
if (to == address(0)) {
_removeTokenFromAllTokensEnumeration(tokenId);
} else if (previousOwner != to) {
_addTokenToOwnerEnumeration(to, tokenId);
}
return previousOwner;
}
function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
ERC721EnumerableStorage storage $ = _getERC721EnumerableStorage();
uint256 length = balanceOf(to) - 1;
$._ownedTokens[to][length] = tokenId;
$._ownedTokensIndex[tokenId] = length;
}
function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
ERC721EnumerableStorage storage $ = _getERC721EnumerableStorage();
$._allTokensIndex[tokenId] = $._allTokens.length;
$._allTokens.push(tokenId);
}
function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
ERC721EnumerableStorage storage $ = _getERC721EnumerableStorage();
uint256 lastTokenIndex = balanceOf(from);
uint256 tokenIndex = $._ownedTokensIndex[tokenId];
if (tokenIndex != lastTokenIndex) {
uint256 lastTokenId = $._ownedTokens[from][lastTokenIndex];
$._ownedTokens[from][tokenIndex] = lastTokenId;
$._ownedTokensIndex[lastTokenId] = tokenIndex;
}
delete $._ownedTokensIndex[tokenId];
delete $._ownedTokens[from][lastTokenIndex];
}
function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
ERC721EnumerableStorage storage $ = _getERC721EnumerableStorage();
uint256 lastTokenIndex = $._allTokens.length - 1;
uint256 tokenIndex = $._allTokensIndex[tokenId];
uint256 lastTokenId = $._allTokens[lastTokenIndex];
$._allTokens[tokenIndex] = lastTokenId;
$._allTokensIndex[lastTokenId] = tokenIndex;
delete $._allTokensIndex[tokenId];
$._allTokens.pop();
}
function _increaseBalance(address account, uint128 amount) internal virtual override {
if (amount > 0) {
revert ERC721EnumerableForbiddenBatchMint();
}
super._increaseBalance(account, amount);
}
}
文件 32 的 124:ERC721Upgradeable.sol
pragma solidity ^0.8.20;
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import {IERC721Metadata} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
import {ContextUpgradeable} from "../../utils/ContextUpgradeable.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {ERC165Upgradeable} from "../../utils/introspection/ERC165Upgradeable.sol";
import {IERC721Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";
abstract contract ERC721Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradeable, IERC721, IERC721Metadata, IERC721Errors {
using Strings for uint256;
struct ERC721Storage {
string _name;
string _symbol;
mapping(uint256 tokenId => address) _owners;
mapping(address owner => uint256) _balances;
mapping(uint256 tokenId => address) _tokenApprovals;
mapping(address owner => mapping(address operator => bool)) _operatorApprovals;
}
bytes32 private constant ERC721StorageLocation = 0x80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab0079300;
function _getERC721Storage() private pure returns (ERC721Storage storage $) {
assembly {
$.slot := ERC721StorageLocation
}
}
function __ERC721_init(string memory name_, string memory symbol_) internal onlyInitializing {
__ERC721_init_unchained(name_, symbol_);
}
function __ERC721_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {
ERC721Storage storage $ = _getERC721Storage();
$._name = name_;
$._symbol = symbol_;
}
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165Upgradeable, IERC165) returns (bool) {
return
interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC721Metadata).interfaceId ||
super.supportsInterface(interfaceId);
}
function balanceOf(address owner) public view virtual returns (uint256) {
ERC721Storage storage $ = _getERC721Storage();
if (owner == address(0)) {
revert ERC721InvalidOwner(address(0));
}
return $._balances[owner];
}
function ownerOf(uint256 tokenId) public view virtual returns (address) {
return _requireOwned(tokenId);
}
function name() public view virtual returns (string memory) {
ERC721Storage storage $ = _getERC721Storage();
return $._name;
}
function symbol() public view virtual returns (string memory) {
ERC721Storage storage $ = _getERC721Storage();
return $._symbol;
}
function tokenURI(uint256 tokenId) public view virtual returns (string memory) {
_requireOwned(tokenId);
string memory baseURI = _baseURI();
return bytes(baseURI).length > 0 ? string.concat(baseURI, tokenId.toString()) : "";
}
function _baseURI() internal view virtual returns (string memory) {
return "";
}
function approve(address to, uint256 tokenId) public virtual {
_approve(to, tokenId, _msgSender());
}
function getApproved(uint256 tokenId) public view virtual returns (address) {
_requireOwned(tokenId);
return _getApproved(tokenId);
}
function setApprovalForAll(address operator, bool approved) public virtual {
_setApprovalForAll(_msgSender(), operator, approved);
}
function isApprovedForAll(address owner, address operator) public view virtual returns (bool) {
ERC721Storage storage $ = _getERC721Storage();
return $._operatorApprovals[owner][operator];
}
function transferFrom(address from, address to, uint256 tokenId) public virtual {
if (to == address(0)) {
revert ERC721InvalidReceiver(address(0));
}
address previousOwner = _update(to, tokenId, _msgSender());
if (previousOwner != from) {
revert ERC721IncorrectOwner(from, tokenId, previousOwner);
}
}
function safeTransferFrom(address from, address to, uint256 tokenId) public {
safeTransferFrom(from, to, tokenId, "");
}
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual {
transferFrom(from, to, tokenId);
_checkOnERC721Received(from, to, tokenId, data);
}
function _ownerOf(uint256 tokenId) internal view virtual returns (address) {
ERC721Storage storage $ = _getERC721Storage();
return $._owners[tokenId];
}
function _getApproved(uint256 tokenId) internal view virtual returns (address) {
ERC721Storage storage $ = _getERC721Storage();
return $._tokenApprovals[tokenId];
}
function _isAuthorized(address owner, address spender, uint256 tokenId) internal view virtual returns (bool) {
return
spender != address(0) &&
(owner == spender || isApprovedForAll(owner, spender) || _getApproved(tokenId) == spender);
}
function _checkAuthorized(address owner, address spender, uint256 tokenId) internal view virtual {
if (!_isAuthorized(owner, spender, tokenId)) {
if (owner == address(0)) {
revert ERC721NonexistentToken(tokenId);
} else {
revert ERC721InsufficientApproval(spender, tokenId);
}
}
}
function _increaseBalance(address account, uint128 value) internal virtual {
ERC721Storage storage $ = _getERC721Storage();
unchecked {
$._balances[account] += value;
}
}
function _update(address to, uint256 tokenId, address auth) internal virtual returns (address) {
ERC721Storage storage $ = _getERC721Storage();
address from = _ownerOf(tokenId);
if (auth != address(0)) {
_checkAuthorized(from, auth, tokenId);
}
if (from != address(0)) {
_approve(address(0), tokenId, address(0), false);
unchecked {
$._balances[from] -= 1;
}
}
if (to != address(0)) {
unchecked {
$._balances[to] += 1;
}
}
$._owners[tokenId] = to;
emit Transfer(from, to, tokenId);
return from;
}
function _mint(address to, uint256 tokenId) internal {
if (to == address(0)) {
revert ERC721InvalidReceiver(address(0));
}
address previousOwner = _update(to, tokenId, address(0));
if (previousOwner != address(0)) {
revert ERC721InvalidSender(address(0));
}
}
function _safeMint(address to, uint256 tokenId) internal {
_safeMint(to, tokenId, "");
}
function _safeMint(address to, uint256 tokenId, bytes memory data) internal virtual {
_mint(to, tokenId);
_checkOnERC721Received(address(0), to, tokenId, data);
}
function _burn(uint256 tokenId) internal {
address previousOwner = _update(address(0), tokenId, address(0));
if (previousOwner == address(0)) {
revert ERC721NonexistentToken(tokenId);
}
}
function _transfer(address from, address to, uint256 tokenId) internal {
if (to == address(0)) {
revert ERC721InvalidReceiver(address(0));
}
address previousOwner = _update(to, tokenId, address(0));
if (previousOwner == address(0)) {
revert ERC721NonexistentToken(tokenId);
} else if (previousOwner != from) {
revert ERC721IncorrectOwner(from, tokenId, previousOwner);
}
}
function _safeTransfer(address from, address to, uint256 tokenId) internal {
_safeTransfer(from, to, tokenId, "");
}
function _safeTransfer(address from, address to, uint256 tokenId, bytes memory data) internal virtual {
_transfer(from, to, tokenId);
_checkOnERC721Received(from, to, tokenId, data);
}
function _approve(address to, uint256 tokenId, address auth) internal {
_approve(to, tokenId, auth, true);
}
function _approve(address to, uint256 tokenId, address auth, bool emitEvent) internal virtual {
ERC721Storage storage $ = _getERC721Storage();
if (emitEvent || auth != address(0)) {
address owner = _requireOwned(tokenId);
if (auth != address(0) && owner != auth && !isApprovedForAll(owner, auth)) {
revert ERC721InvalidApprover(auth);
}
if (emitEvent) {
emit Approval(owner, to, tokenId);
}
}
$._tokenApprovals[tokenId] = to;
}
function _setApprovalForAll(address owner, address operator, bool approved) internal virtual {
ERC721Storage storage $ = _getERC721Storage();
if (operator == address(0)) {
revert ERC721InvalidOperator(operator);
}
$._operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
function _requireOwned(uint256 tokenId) internal view returns (address) {
address owner = _ownerOf(tokenId);
if (owner == address(0)) {
revert ERC721NonexistentToken(tokenId);
}
return owner;
}
function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory data) private {
if (to.code.length > 0) {
try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {
if (retval != IERC721Receiver.onERC721Received.selector) {
revert ERC721InvalidReceiver(to);
}
} catch (bytes memory reason) {
if (reason.length == 0) {
revert ERC721InvalidReceiver(to);
} else {
assembly {
revert(add(32, reason), mload(reason))
}
}
}
}
}
}
文件 33 的 124:EnumerableSet.sol
pragma solidity ^0.8.20;
library EnumerableSet {
struct Set {
bytes32[] _values;
mapping(bytes32 value => uint256) _positions;
}
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
set._positions[value] = set._values.length;
return true;
} else {
return false;
}
}
function _remove(Set storage set, bytes32 value) private returns (bool) {
uint256 position = set._positions[value];
if (position != 0) {
uint256 valueIndex = position - 1;
uint256 lastIndex = set._values.length - 1;
if (valueIndex != lastIndex) {
bytes32 lastValue = set._values[lastIndex];
set._values[valueIndex] = lastValue;
set._positions[lastValue] = position;
}
set._values.pop();
delete set._positions[value];
return true;
} else {
return false;
}
}
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._positions[value] != 0;
}
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
struct Bytes32Set {
Set _inner;
}
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
assembly {
result := store
}
return result;
}
struct AddressSet {
Set _inner;
}
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
assembly {
result := store
}
return result;
}
struct UintSet {
Set _inner;
}
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
assembly {
result := store
}
return result;
}
}
文件 34 的 124:FeeConditionBase.sol
pragma solidity 0.8.20;
import {OspContext} from '../../core/base/OspContext.sol';
import {CondErrors} from './libraries/CondErrors.sol';
import {IGovernanceLogic} from '../logics/interfaces/IGovernanceLogic.sol';
abstract contract FeeConditionBase is OspContext {
function _validateDataIsExpected(
bytes calldata data,
address currency,
uint256 amount
) internal pure {
(address decodedCurrency, uint256 decodedAmount) = abi.decode(data, (address, uint256));
if (decodedAmount != amount || decodedCurrency != currency)
revert CondErrors.ConditionDataMismatch();
}
function _tokenWhitelisted(address token) internal view returns (bool) {
return IGovernanceLogic(OSP).isTokenWhitelisted(token);
}
}
文件 35 的 124:FixedFeeCommunityCond.sol
pragma solidity 0.8.20;
import {IERC721} from '@openzeppelin/contracts/token/ERC721/IERC721.sol';
import {CommunityCondBase} from '../../base/CommunityCondBase.sol';
import {Payment} from '../../../libraries/Payment.sol';
import {ECDSA} from '@openzeppelin/contracts/utils/cryptography/ECDSA.sol';
import {CondErrors} from '../libraries/CondErrors.sol';
import {CondDataTypes} from '../libraries/CondDataTypes.sol';
import {CondHelpers} from '../libraries/CondHelpers.sol';
contract FixedFeeCommunityCond is CommunityCondBase {
event FixFeeCondDataSet(CondDataTypes.FixedFeeCondData data, uint256 timestamp);
event FixFeePaid(address indexed to, uint256 price, string handle, uint256 timestamp);
CondDataTypes.FixedFeeCondData public fixedFeeCondData;
constructor(address osp) CommunityCondBase(osp) {}
function _processCreateCommunity(
address to,
string calldata handle,
bytes calldata
) internal override {
if (
block.timestamp < fixedFeeCondData.createStartTime ||
fixedFeeCondData.createStartTime == 0
) {
revert CondErrors.NotCreateTime();
}
uint256 price = CondHelpers.getHandleETHPrice(handle, fixedFeeCondData);
_charge(price, to);
emit FixFeePaid(to, price, handle, block.timestamp);
}
function setFixedFeeCondData(
CondDataTypes.FixedFeeCondData calldata data
) external onlyOperation {
fixedFeeCondData = CondDataTypes.FixedFeeCondData({
price1Letter: data.price1Letter,
price2Letter: data.price2Letter,
price3Letter: data.price3Letter,
price4Letter: data.price4Letter,
price5Letter: data.price5Letter,
price6Letter: data.price6Letter,
price7ToMoreLetter: data.price7ToMoreLetter,
createStartTime: data.createStartTime
});
emit FixFeeCondDataSet(data, block.timestamp);
}
function getHandlePrice(string calldata handle) external view returns (uint256) {
return CondHelpers.getHandleETHPrice(handle, fixedFeeCondData);
}
function _charge(uint256 price, address to) internal virtual {
if (msg.value < price) {
revert CondErrors.InsufficientPayment();
}
uint256 overpayment;
unchecked {
overpayment = msg.value - price;
}
if (overpayment > 0) {
Payment.payNative(to, overpayment);
}
address treasure = OSP.getTreasureAddress();
require(treasure != address(0), 'Invalid treasure');
Payment.payNative(treasure, price);
}
}
文件 36 的 124:FollowSBT.sol
pragma solidity 0.8.20;
import '../interfaces/IFollowSBT.sol';
import '../interfaces/IFollowCondition.sol';
import './logics/interfaces/OspClient.sol';
import '../libraries/OspErrors.sol';
import '../libraries/OspEvents.sol';
import './base/OspSBTBase.sol';
contract FollowSBT is OspSBTBase, IFollowSBT {
address public immutable OSP;
uint256 internal _profileId;
uint256 internal _tokenIdCounter;
constructor(address osp) {
if (osp == address(0)) revert OspErrors.InitParamsInvalid();
OSP = osp;
}
function initialize(
uint256 profileId,
string calldata name,
string calldata symbol
) external override {
if (msg.sender != OSP) revert OspErrors.NotOSP();
_profileId = profileId;
super._initialize(name, symbol);
emit OspEvents.FollowSBTInitialized(profileId, block.timestamp);
}
function mint(address to) external override returns (uint256) {
if (msg.sender != OSP) revert OspErrors.NotOSP();
unchecked {
uint256 tokenId = ++_tokenIdCounter;
_mint(to, tokenId);
return tokenId;
}
}
function tokenURI(uint256 tokenId) public view override returns (string memory) {
return OspClient(OSP).getFollowSBTURI(_profileId, tokenId);
}
function _afterTokenTransfer(address from, address to, uint256 tokenId) internal override {
super._afterTokenTransfer(from, to, tokenId);
OspClient(OSP).emitFollowSBTTransferEvent(_profileId, tokenId, from, to);
}
}
文件 37 的 124:FollowSBTProxy.sol
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 FollowSBTProxy is Proxy {
using Address for address;
address immutable OSP;
constructor(bytes memory data) {
OSP = msg.sender;
IGovernanceLogic(msg.sender).getFollowSBTImpl().functionDelegateCall(data);
}
function _implementation() internal view override returns (address) {
return IGovernanceLogic(OSP).getFollowSBTImpl();
}
}
文件 38 的 124:GovernanceLogic.sol
pragma solidity 0.8.20;
import './OspLogicBase.sol';
import './interfaces/IGovernanceLogic.sol';
import '../../libraries/OspDataTypes.sol';
import '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';
import '@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol';
import '../../interfaces/IERC6551Registry.sol';
import '../../libraries/Constants.sol';
import '../../upgradeability/CommunityAccountProxy.sol';
import '@thirdweb-dev/contracts/extension/upgradeable/ContractMetadata.sol';
contract GovernanceLogic is
IGovernanceLogic,
OspLogicBase,
AccessControlUpgradeable,
ContractMetadata
{
function initialize(
string calldata name,
string calldata symbol,
address followSBTImpl,
address joinNFTImpl,
address communityNFT
) external override initializer {
_grantRole(DEFAULT_ADMIN_ROLE, _msgSender());
GovernanceStorage storage governanceStorage = _getGovernanceStorage();
governanceStorage._name = name;
governanceStorage._symbol = symbol;
governanceStorage._followSBTImpl = followSBTImpl;
governanceStorage._joinNFTImpl = joinNFTImpl;
governanceStorage._communityNFT = communityNFT;
address communityAccountProxy = address(new CommunityAccountProxy());
governanceStorage._communityAccountProxy = communityAccountProxy;
_setState(OspDataTypes.ProtocolState.Paused);
emit OspEvents.OSPInitialized(
name,
symbol,
followSBTImpl,
joinNFTImpl,
communityNFT,
communityAccountProxy,
block.timestamp
);
}
function setState(
OspDataTypes.ProtocolState newState
) external onlyRole(Constants.STATE_ADMIN) {
_setState(newState);
}
function whitelistApp(address app, bool whitelist) external onlyRole(Constants.APP_ADMIN) {
_getGovernanceStorage()._appWhitelisted[app] = whitelist;
emit OspEvents.AppWhitelisted(app, whitelist, block.timestamp);
}
function whitelistToken(
address token,
bool whitelist
) external override onlyRole(Constants.OPERATION) {
_getGovernanceStorage()._tokenWhitelisted[token] = whitelist;
emit OspEvents.TokenWhitelisted(token, whitelist, block.timestamp);
}
function reserveCommunityHandle(
string calldata handle,
bool isReserve
) external override onlyRole(Constants.SUPER_COMMUNITY_CREATOR) {
_getGovernanceStorage()._reserveCommunityHandleHash[keccak256(bytes(handle))] = isReserve;
emit OspEvents.CommunityHandleReserve(
keccak256(bytes(handle)),
isReserve,
handle,
block.timestamp
);
}
function setBaseURI(string calldata baseURI) external override onlyRole(Constants.GOVERNANCE) {
_getGovernanceStorage()._baseURI = baseURI;
emit OspEvents.BaseURISet(baseURI, block.timestamp);
}
function setERC6551AccountImpl(
address accountImpl
) external override onlyRole(Constants.GOVERNANCE) {
_getGovernanceStorage()._erc6551AccountImpl = accountImpl;
emit OspEvents.ERC6551AccountImplSet(accountImpl, block.timestamp);
}
function setJoinNFTImpl(address joinNFTImpl) external override onlyRole(Constants.GOVERNANCE) {
_getGovernanceStorage()._joinNFTImpl = joinNFTImpl;
emit OspEvents.JoinNFTImplSet(joinNFTImpl, block.timestamp);
}
function updateMetadata() external override onlyRole(Constants.GOVERNANCE) {
emit BatchMetadataUpdate(1, type(uint256).max);
}
function setTreasureAddress(address treasure) external override onlyRole(Constants.GOVERNANCE) {
if (treasure == address(0)) revert OspErrors.InvalidAddress();
_getGovernanceStorage()._treasure = treasure;
}
function setJoinNFTRoyalty(
uint128 royaltyFraction,
uint128 ospTreasureFraction
) external onlyRole(Constants.GOVERNANCE) {
if (
royaltyFraction > Constants.ROYALTY_DENOMINATOR ||
ospTreasureFraction > Constants.ROYALTY_DENOMINATOR
) {
revert OspErrors.InvalidParam();
}
_getGovernanceStorage()._joinNFTRoyaltyInfo = OspDataTypes.RoyaltyInfo({
royaltyFraction: royaltyFraction,
ospTreasureFraction: ospTreasureFraction
});
}
function isAppWhitelisted(address app) external view override returns (bool) {
return _getGovernanceStorage()._appWhitelisted[app];
}
function isTokenWhitelisted(address token) external view override returns (bool) {
return _getGovernanceStorage()._tokenWhitelisted[token];
}
function isReserveCommunityHandle(
string calldata handle
) external view override returns (bool) {
return _getGovernanceStorage()._reserveCommunityHandleHash[keccak256(bytes(handle))];
}
function getFollowSBTImpl() external view override returns (address) {
return _getGovernanceStorage()._followSBTImpl;
}
function getJoinNFTImpl() external view override returns (address) {
return _getGovernanceStorage()._joinNFTImpl;
}
function getCommunityNFT() external view override returns (address) {
return _getGovernanceStorage()._communityNFT;
}
function getERC6551AccountImpl() external view override returns (address) {
return _getGovernanceStorage()._erc6551AccountImpl;
}
function getState() external view override returns (OspDataTypes.ProtocolState) {
return _getState();
}
function getBaseURI() external view override returns (string memory) {
return _getGovernanceStorage()._baseURI;
}
function eip712Domain()
external
view
override
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
)
{
return (
hex'0f',
_getGovernanceStorage()._name,
'1',
block.chainid,
address(this),
bytes32(0),
new uint256[](0)
);
}
function getTreasureAddress() external view override returns (address) {
return _getGovernanceStorage()._treasure;
}
function joinNFTRoyaltyInfo()
external
view
returns (uint128 royaltyFraction, uint128 ospTreasureFraction)
{
OspDataTypes.RoyaltyInfo memory joinNFTRoyalty = _getGovernanceStorage()
._joinNFTRoyaltyInfo;
return (joinNFTRoyalty.royaltyFraction, joinNFTRoyalty.ospTreasureFraction);
}
function _canSetContractURI() internal view override returns (bool) {
return _hashRole(Constants.GOVERNANCE, _msgSender());
}
}
文件 39 的 124:HoldERC721ActivityCond.sol
pragma solidity 0.8.20;
import {ActivityConditionBase} from 'contracts/core/base/ActivityConditionBase.sol';
import {IHoldERC721ActivityCond} from './interfaces/IHoldERC721ActivityCond.sol';
import {CondErrors} from '../libraries/CondErrors.sol';
import {IERC721} from '@openzeppelin/contracts/token/ERC721/IERC721.sol';
contract HoldERC721ActivityCond is ActivityConditionBase, IHoldERC721ActivityCond {
mapping(uint256 => HoldERC721Data) internal _dataByCommunity;
constructor(
address osp,
address compositeActivityCondition
) ActivityConditionBase(osp, compositeActivityCondition) {}
function _initializeCommunityActivityCondition(
uint256 communityId,
bytes calldata data
) internal override {
(address erc721Address, uint96 minAmount) = abi.decode(data, (address, uint96));
_dataByCommunity[communityId] = HoldERC721Data(erc721Address, minAmount);
}
function _processActivity(
uint256 communityId,
address profileOwner,
uint256 profileId
) internal override {
HoldERC721Data memory data = _dataByCommunity[communityId];
uint256 balance = IERC721(data.tokenAddress).balanceOf(profileOwner);
if (balance < data.amount) revert CondErrors.NotEnoughERC721Balance();
}
function getHoldERC721Data(uint256 communityId) external view returns (HoldERC721Data memory) {
return _dataByCommunity[communityId];
}
function supportsInterface(bytes4 interfaceId) public pure override returns (bool) {
return
ActivityConditionBase.supportsInterface(interfaceId) ||
interfaceId == type(IHoldERC721ActivityCond).interfaceId;
}
}
文件 40 的 124:HoldERC721ViewPrivacyCond.sol
pragma solidity ^0.8.0;
import {ViewPrivacyConditionBase} from 'contracts/core/base/ViewPrivacyConditionBase.sol';
import {IHoldERC721ViewPrivacyCond} from './interfaces/IHoldERC721ViewPrivacyCond.sol';
import {IERC721} from '@openzeppelin/contracts/token/ERC721/IERC721.sol';
contract HoldERC721ViewPrivacyCond is ViewPrivacyConditionBase, IHoldERC721ViewPrivacyCond {
mapping(uint256 => HoldERC721Data) _dataByCommunity;
constructor(
address osp,
address compositeCondition
) ViewPrivacyConditionBase(osp, compositeCondition) {}
function _initializeCommunityViewPrivacyCondition(
uint256 communityId,
bytes calldata data
) internal override {
(address erc721Address, uint96 minAmount) = abi.decode(data, (address, uint96));
_dataByCommunity[communityId] = HoldERC721Data(erc721Address, minAmount);
}
function _isViewPrivacyAllowed(
uint256 communityId,
address profileOwner,
uint256 profileId
) internal view override returns (bool) {
HoldERC721Data memory data = _dataByCommunity[communityId];
uint256 balance = IERC721(data.tokenAddress).balanceOf(profileOwner);
return balance >= data.amount;
}
function getHoldERC721Data(uint256 communityId) external view returns (HoldERC721Data memory) {
return _dataByCommunity[communityId];
}
function supportsInterface(bytes4 interfaceId) public pure override returns (bool) {
return
ViewPrivacyConditionBase.supportsInterface(interfaceId) ||
interfaceId == type(IHoldERC721ViewPrivacyCond).interfaceId;
}
}
文件 41 的 124:HoldTokenJoinCond.sol
pragma solidity 0.8.20;
import {CondErrors} from '../libraries/CondErrors.sol';
import {JoinConditionBase} from '../../base/JoinConditionBase.sol';
struct CommunityData {
address token;
uint256 amount;
}
interface IToken {
function balanceOf(address owner) external view returns (uint256);
}
contract HoldTokenJoinCond is JoinConditionBase {
mapping(uint256 => CommunityData) _dataByCommunity;
constructor(address osp) JoinConditionBase(osp) {}
function _initializeCommunityJoinCondition(
uint256 communityId,
bytes calldata data
) internal override {
(address _token, uint256 _amount) = abi.decode(data, (address, uint256));
_dataByCommunity[communityId].token = _token;
_dataByCommunity[communityId].amount = _amount;
}
function _processJoin(
address joiner,
uint256 communityId,
bytes calldata data
) internal override nonPayable {
(data);
address token = _dataByCommunity[communityId].token;
if (token == address(0) && joiner.balance >= _dataByCommunity[communityId].amount) {
return;
} else if (
token != address(0) &&
IToken(token).balanceOf(joiner) >= _dataByCommunity[communityId].amount
) {
return;
}
revert CondErrors.JoinInvalid();
}
function _processTransferJoinNFT(
uint256 communityId,
uint256 joinNFTId,
address from,
address to
) internal override {
if (from != address(0) && to != address(0)) {
revert CondErrors.JoinNFTTransferInvalid();
}
}
function getCommunityData(uint256 communityId) external view returns (CommunityData memory) {
return _dataByCommunity[communityId];
}
}
文件 42 的 124:IAccessControl.sol
pragma solidity ^0.8.20;
interface IAccessControl {
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
error AccessControlBadConfirmation();
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
function hasRole(bytes32 role, address account) external view returns (bool);
function getRoleAdmin(bytes32 role) external view returns (bytes32);
function grantRole(bytes32 role, address account) external;
function revokeRole(bytes32 role, address account) external;
function renounceRole(bytes32 role, address callerConfirmation) external;
}
文件 43 的 124:IActivityCondition.sol
pragma solidity 0.8.20;
interface IActivityCondition {
function initializeCommunityActivityCondition(
uint256 communityId,
bytes calldata data
) external;
function processActivity(uint256 communityId, address profileOwner, uint256 profileId) external;
}
文件 44 的 124:IActivityExtension.sol
pragma solidity 0.8.20;
interface IActivityExtension {
function initializeActivityExtension(
uint256 profileId,
uint256 contentId,
bytes calldata initData
) external payable;
}
文件 45 的 124:IActivityExtensionQueryable.sol
pragma solidity 0.8.20;
import {IActivityExtension} from './IActivityExtension.sol';
interface IActivityExtensionQueryable is IActivityExtension {
function getExtensionData(
uint256 profileId,
uint256 contentId
) external view returns (bytes memory);
}
文件 46 的 124:IBeacon.sol
pragma solidity ^0.8.20;
interface IBeacon {
function implementation() external view returns (address);
}
文件 47 的 124:ICommunityCondition.sol
pragma solidity 0.8.20;
interface ICommunityCondition {
function processCreateCommunity(
address to,
string calldata handle,
bytes calldata data
) external payable;
}
文件 48 的 124:ICommunityLogic.sol
pragma solidity 0.8.20;
import '../../../libraries/OspDataTypes.sol';
interface ICommunityLogic {
function createCommunity(
OspDataTypes.CreateCommunityData calldata vars
) external payable returns (uint256);
function createCommunity(
OspDataTypes.CreateCommunityData calldata vars,
bytes calldata activityConditionInitCode,
bytes calldata viewPrivacyConditionInitCode
) external payable returns (uint256);
function setJoinCondition(uint256 communityId, bytes calldata joinConditionInitCode) external;
function setActivityCondition(
uint256 communityId,
bytes calldata activityConditionInitCode
) external;
function setViewPrivacyCondition(
uint256 communityId,
bytes calldata viewPrivacyConditionInitCode
) external;
function isViewPrivacyAllowed(
uint256 communityId,
uint256 profileId
) external view returns (bool);
function updateTags(uint256 communityId, string[] calldata tags) external;
function setCommunityActivityExtensionWhitelist(
uint256 communityId,
address extension,
bool isWhitelist
) external;
function emitCommunityNFTTransferEvent(uint256 communityId, address from, address to) external;
function getCommunity(
uint256 communityId
) external view returns (OspDataTypes.CommunityStruct memory);
function getJoinNFT(uint256 communityId) external view returns (address);
function getJoinCondition(uint256 communityId) external view returns (address);
function getActivityCondition(uint256 communityId) external view returns (address);
function getCommunityTokenURI(uint256 communityId) external view returns (string memory);
function getCommunityIdByHandle(string calldata handle) external view returns (uint256);
function getCommunityAccount(uint256 communityId) external view returns (address);
function getCommunityAccount(string calldata handle) external view returns (address);
function getCommunityActivityExtensionWhitelist(
uint256 communityId
) external view returns (address[] memory extensions);
}
文件 49 的 124:ICommunityNFT.sol
pragma solidity 0.8.20;
interface ICommunityNFT {
function mint(address to) external returns (uint256);
function updateMetadata() external;
}
文件 50 的 124:ICompositeActivityCond.sol
pragma solidity 0.8.20;
import {IActivityCondition} from 'contracts/interfaces/IActivityCondition.sol';
interface ICompositeActivityCond is IActivityCondition {
enum OperatorEnum {
AND,
OR
}
struct CompositeData {
OperatorEnum operator;
IActivityCondition[] conditions;
}
function getCompositeData(uint256 communityId) external view returns (CompositeData memory);
}
文件 51 的 124:ICompositeViewPrivacyCond.sol
pragma solidity 0.8.20;
import {IViewPrivacyCondition} from 'contracts/interfaces/IViewPrivacyCondition.sol';
interface ICompositeViewPrivacyCond is IViewPrivacyCondition {
enum OperatorEnum {
AND,
OR
}
struct CompositeData {
OperatorEnum operator;
IViewPrivacyCondition[] conditions;
}
function getCompositeData(uint256 communityId) external view returns (CompositeData memory);
}
文件 52 的 124:IContentLogic.sol
pragma solidity 0.8.20;
import '../../../libraries/OspDataTypes.sol';
interface IContentLogic {
function createActivity(
OspDataTypes.CreateActivityData calldata vars
) external payable returns (uint256 contentId);
function createActivityWithSig(
OspDataTypes.CreateActivityData calldata vars,
OspDataTypes.EIP712Signature calldata sig
) external returns (uint256 contentId);
function createComment(
OspDataTypes.CreateCommentData calldata vars
) external payable returns (uint256 contentId);
function createCommentWithSig(
OspDataTypes.CreateCommentData calldata vars,
OspDataTypes.EIP712Signature calldata sig
) external returns (uint256 contentId);
function createOpenReaction(OspDataTypes.CreateOpenReactionData calldata vars) external payable;
function createOpenReactionWithSig(
OspDataTypes.CreateOpenReactionData calldata vars,
OspDataTypes.EIP712Signature calldata sig
) external;
function createMegaphone(
OspDataTypes.CreateMegaphoneData calldata vars
) external payable returns (uint256 megaphoneId);
function getContentCount(uint256 profileId) external view returns (uint256);
function getContent(
uint256 profileId,
uint256 contentId
) external view returns (OspDataTypes.ContentStruct memory);
function getCommunityIdByContent(
uint256 profileId,
uint256 contentId
) external view returns (uint256);
}
文件 53 的 124:IContractMetadata.sol
pragma solidity ^0.8.0;
interface IContractMetadata {
function contractURI() external view returns (string memory);
function setContractURI(string calldata _uri) external;
event ContractURIUpdated(string prevURI, string newURI);
}
文件 54 的 124:IERC1155Receiver.sol
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
interface IERC1155Receiver is IERC165 {
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}
文件 55 的 124:IERC1271.sol
pragma solidity ^0.8.20;
interface IERC1271 {
function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
}
文件 56 的 124:IERC165.sol
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";
文件 57 的 124:IERC20.sol
pragma solidity ^0.8.20;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
文件 58 的 124:IERC20Permit.sol
pragma solidity ^0.8.20;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
文件 59 的 124:IERC2981.sol
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";
interface IERC2981 is IERC165 {
function royaltyInfo(
uint256 tokenId,
uint256 salePrice
) external view returns (address receiver, uint256 royaltyAmount);
}
文件 60 的 124:IERC4906.sol
pragma solidity 0.8.20;
interface IERC4906 {
event MetadataUpdate(uint256 _tokenId);
event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId);
}
文件 61 的 124:IERC5267.sol
pragma solidity ^0.8.20;
interface IERC5267 {
event EIP712DomainChanged();
function eip712Domain()
external
view
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
);
}
文件 62 的 124:IERC6551Registry.sol
pragma solidity 0.8.20;
interface IERC6551Registry {
event ERC6551AccountCreated(
address account,
address indexed implementation,
bytes32 salt,
uint256 chainId,
address indexed tokenContract,
uint256 indexed tokenId
);
error AccountCreationFailed();
function createAccount(
address implementation,
bytes32 salt,
uint256 chainId,
address tokenContract,
uint256 tokenId
) external returns (address account);
function account(
address implementation,
bytes32 salt,
uint256 chainId,
address tokenContract,
uint256 tokenId
) external view returns (address account);
}
文件 63 的 124:IERC721.sol
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
interface IERC721 is IERC165 {
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
function balanceOf(address owner) external view returns (uint256 balance);
function ownerOf(uint256 tokenId) external view returns (address owner);
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
function safeTransferFrom(address from, address to, uint256 tokenId) external;
function transferFrom(address from, address to, uint256 tokenId) external;
function approve(address to, uint256 tokenId) external;
function setApprovalForAll(address operator, bool approved) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function isApprovedForAll(address owner, address operator) external view returns (bool);
}
文件 64 的 124:IERC721Burnable.sol
pragma solidity 0.8.20;
import {IERC721} from '@openzeppelin/contracts/token/ERC721/IERC721.sol';
interface IERC721Burnable is IERC721 {
function burn(uint256 tokenId) external;
}
文件 65 的 124:IERC721Enumerable.sol
pragma solidity ^0.8.20;
import {IERC721} from "../IERC721.sol";
interface IERC721Enumerable is IERC721 {
function totalSupply() external view returns (uint256);
function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
function tokenByIndex(uint256 index) external view returns (uint256);
}
文件 66 的 124:IERC721Metadata.sol
pragma solidity ^0.8.20;
import {IERC721} from "../IERC721.sol";
interface IERC721Metadata is IERC721 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function tokenURI(uint256 tokenId) external view returns (string memory);
}
文件 67 的 124:IERC721Receiver.sol
pragma solidity ^0.8.20;
interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
文件 68 的 124:IFollowCondition.sol
pragma solidity 0.8.20;
interface IFollowCondition {
function initializeFollowCondition(uint256 profileId, bytes calldata data) external;
function processFollow(
address follower,
uint256 profileId,
bytes calldata data
) external payable;
}
文件 69 的 124:IFollowSBT.sol
pragma solidity 0.8.20;
interface IFollowSBT {
function initialize(uint256 profileId, string calldata name, string calldata symbol) external;
function mint(address to) external returns (uint256);
}
文件 70 的 124:IGovernanceLogic.sol
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';
import '@thirdweb-dev/contracts/extension/interface/IContractMetadata.sol';
interface IGovernanceLogic is IERC4906, IERC5267, IAccessControl, IContractMetadata {
function initialize(
string calldata name,
string calldata symbol,
address followSBTImpl,
address joinNFTImpl,
address communityNFT
) external;
function setState(OspDataTypes.ProtocolState newState) external;
function whitelistApp(address app, bool whitelist) external;
function whitelistToken(address token, bool whitelist) external;
function reserveCommunityHandle(string calldata handle, bool isReserve) external;
function setBaseURI(string calldata baseURI) external;
function setERC6551AccountImpl(address accountImpl) external;
function setJoinNFTImpl(address joinNFTImpl) external;
function isAppWhitelisted(address app) external view returns (bool);
function isTokenWhitelisted(address token) external view returns (bool);
function isReserveCommunityHandle(string calldata handle) external view returns (bool);
function getBaseURI() external view returns (string memory);
function getFollowSBTImpl() external view returns (address);
function getJoinNFTImpl() external view returns (address);
function getCommunityNFT() external view returns (address);
function getERC6551AccountImpl() external view returns (address);
function getState() external view returns (OspDataTypes.ProtocolState);
function updateMetadata() external;
function setTreasureAddress(address treasure) external;
function getTreasureAddress() external view returns (address);
function setJoinNFTRoyalty(uint128 royaltyFraction, uint128 ospTreasureFraction) external;
function joinNFTRoyaltyInfo()
external
view
returns (uint128 royaltyFraction, uint128 ospTreasureFraction);
}
文件 71 的 124:IHoldERC721ActivityCond.sol
pragma solidity 0.8.20;
import {IActivityCondition} from 'contracts/interfaces/IActivityCondition.sol';
interface IHoldERC721ActivityCond is IActivityCondition {
struct HoldERC721Data {
address tokenAddress;
uint96 amount;
}
function getHoldERC721Data(uint256 communityId) external view returns (HoldERC721Data memory);
}
文件 72 的 124:IHoldERC721ViewPrivacyCond.sol
pragma solidity 0.8.20;
import {IViewPrivacyCondition} from 'contracts/interfaces/IViewPrivacyCondition.sol';
interface IHoldERC721ViewPrivacyCond is IViewPrivacyCondition {
struct HoldERC721Data {
address tokenAddress;
uint96 amount;
}
function getHoldERC721Data(uint256 communityId) external view returns (HoldERC721Data memory);
}
文件 73 的 124:IJoinCondition.sol
pragma solidity 0.8.20;
interface IJoinCondition {
function initializeCommunityJoinCondition(uint256 communityId, bytes calldata data) external;
function processJoin(address joiner, uint256 community, bytes calldata data) external payable;
function processTransferJoinNFT(
uint256 communityId,
uint256 joinNFTId,
address from,
address to
) external;
}
文件 74 的 124:IJoinNFT.sol
pragma solidity 0.8.20;
interface IJoinNFT {
function initialize(uint256 communityId, string calldata name, string calldata symbol) external;
function mint(address to) external returns (uint256);
function setAdmin(address account) external returns (bool);
function setModerator(address account) external returns (bool);
function removeRole(address account) external returns (bool);
function setMemberLevel(address account, uint256 level) external returns (bool);
function setBlockList(address account, bool enable) external returns (bool);
function getSourceCommunityPointer() external view returns (uint256);
function hasRole(uint256 roles, address account) external view returns (bool);
function getRole(address account) external view returns (uint256);
function getMemberLevel(address account) external view returns (uint256);
function getMemberLevel(uint256 tokenId) external view returns (uint256);
function isBlock(address account) external view returns (bool);
}
文件 75 的 124:IOpenReaction.sol
pragma solidity 0.8.20;
interface IOpenReaction {
function processReaction(
uint256 profileId,
uint256 referencedProfileId,
uint256 referencedContentId,
bytes calldata data
) external payable;
}
文件 76 的 124:IProfileLogic.sol
pragma solidity 0.8.20;
import '../../../libraries/OspDataTypes.sol';
import '../../../interfaces/IERC721Burnable.sol';
import {IERC721Metadata} from '@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol';
import {IERC721Enumerable} from '@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol';
import {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';
interface IProfileLogic is IERC721Burnable, IERC721Metadata, IERC721Enumerable {
function createProfile(OspDataTypes.CreateProfileData calldata vars) external returns (uint256);
function setFollowCondition(uint256 profileId, bytes calldata followConditionInitCode) external;
function getFollowSBT(uint256 profileId) external view returns (address);
function getFollowCondition(uint256 profileId) external view returns (address);
function getHandle(uint256 profileId) external view returns (string memory);
function getProfileIdByHandle(string calldata handle) external view returns (uint256);
function getProfile(
uint256 profileId
) external view returns (OspDataTypes.ProfileStruct memory);
function getProfileIdByAddress(address addr) external view returns (uint256);
function nonces(address singer) external view returns (uint256);
}
文件 77 的 124:IReferenceCondition.sol
pragma solidity 0.8.20;
interface IReferenceCondition {
function initializeReferenceCondition(
uint256 profileId,
uint256 contendId,
uint256 communityId,
bytes calldata data
) external;
function processReactionReference(
uint256 profileId,
uint256 communityId,
uint256 referencedProfileId,
uint256 referencedContentId,
bytes calldata data
) external payable;
}
文件 78 的 124:IRelationLogic.sol
pragma solidity 0.8.20;
import '../../../libraries/OspDataTypes.sol';
interface IRelationLogic {
function follow(OspDataTypes.FollowData calldata vars) external payable returns (uint256);
function batchFollow(
OspDataTypes.BatchFollowData calldata vars
) external payable returns (uint256[] memory);
function join(OspDataTypes.JoinData calldata vars) external payable returns (uint256);
function batchJoin(
OspDataTypes.BatchJoinData calldata vars
) external payable returns (uint256[] memory);
function getFollowSBTURI(
uint256 profileId,
uint256 tokenId
) external view returns (string memory);
function isFollow(uint256 profileId, address addr) external view returns (bool);
function isJoin(uint256 communityId, address addr) external view returns (bool);
function hasCommunityRole(
uint256 communityId,
uint256 role,
address account
) external view returns (bool);
function getCommunityRole(uint256 communityId, address account) external view returns (uint256);
function getCommunityMemberLevel(
uint256 communityId,
address account
) external view returns (uint256);
function isCommunityBlock(uint256 communityId, address account) external view returns (bool);
function getJoinNFTURI(
uint256 communityId,
uint256 tokenId
) external view returns (string memory);
function emitFollowSBTTransferEvent(
uint256 profileId,
uint256 followSBTId,
address from,
address to
) external;
function emitJoinNFTTransferEvent(
uint256 communityId,
uint256 joinNFTId,
address from,
address to
) external;
function emitJoinNFTRoleChangedEvent(
uint256 communityId,
address sender,
address account,
uint256 role
) external;
function emitJoinNFTAccountBlockedEvent(
uint256 communityId,
address sender,
address account,
bool isBlock
) external;
function emitJoinNFTAccountLevelChangedEvent(
uint256 communityId,
address sender,
uint256 tokenId,
address account,
uint256 level
) external;
}
文件 79 的 124:IRoleActivityCond.sol
pragma solidity 0.8.20;
import {IActivityCondition} from 'contracts/interfaces/IActivityCondition.sol';
interface IRoleActivityCond is IActivityCondition {
function getRoleLimit(uint256 communityId) external view returns (uint256 roleLimit);
}
文件 80 的 124:IRoleViewPrivacyCond.sol
pragma solidity 0.8.20;
import {IViewPrivacyCondition} from 'contracts/interfaces/IViewPrivacyCondition.sol';
interface IRoleViewPrivacyCond is IViewPrivacyCondition {
struct RoleLimitData {
uint256 roleLimit;
}
function getRoleLimit(uint256 communityId) external view returns (uint256 roleLimit);
}
文件 81 的 124:IRouter.sol
pragma solidity 0.8.20;
interface IRouter {
struct Router {
bytes4 functionSelector;
address routerAddress;
string functionSignature;
}
event RouterAdded(bytes4 indexed functionSelector, address indexed routerAddress);
event RouterUpdated(
bytes4 indexed functionSelector,
address indexed oldRouterAddress,
address indexed newRouterAddress
);
event RouterSet(
bytes4 indexed functionSelector,
string indexed functionSignature,
address indexed routerAddress
);
event RouterRemoved(bytes4 indexed functionSelector, address indexed routerAddress);
function addRouter(Router memory router) external;
function updateRouter(Router memory router) external;
function removeRouter(bytes4 selector, string calldata functionSignature) external;
function getRouterForFunction(bytes4 functionSelector) external view returns (address);
function getAllFunctionsOfRouter(address routerAddress) external view returns (bytes4[] memory);
function getAllRouters() external view returns (Router[] memory);
}
文件 82 的 124:IViewPrivacyCondition.sol
pragma solidity 0.8.20;
interface IViewPrivacyCondition {
function initializeCommunityViewPrivacyCondition(
uint256 communityId,
bytes calldata data
) external;
function isViewPrivacyAllowed(
uint256 communityId,
address profileOwner,
uint256 profileId
) external view returns (bool);
}
文件 83 的 124:Initializable.sol
pragma solidity ^0.8.20;
abstract contract Initializable {
struct InitializableStorage {
uint64 _initialized;
bool _initializing;
}
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
error InvalidInitialization();
error NotInitializing();
event Initialized(uint64 version);
modifier initializer() {
InitializableStorage storage $ = _getInitializableStorage();
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
modifier reinitializer(uint64 version) {
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
modifier onlyInitializing() {
_checkInitializing();
_;
}
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
function _disableInitializers() internal virtual {
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}
文件 84 的 124:JoinConditionBase.sol
pragma solidity 0.8.20;
import {OspContext} from './OspContext.sol';
import {IJoinCondition} from '../../interfaces/IJoinCondition.sol';
import {IERC165} from '@openzeppelin/contracts/interfaces/IERC165.sol';
abstract contract JoinConditionBase is OspContext, IERC165, IJoinCondition {
constructor(address osp) OspContext(osp) {}
function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {
return
interfaceId == type(IJoinCondition).interfaceId ||
interfaceId == type(IERC165).interfaceId;
}
function initializeCommunityJoinCondition(
uint256 communityId,
bytes calldata data
) external onlyOsp {
_initializeCommunityJoinCondition(communityId, data);
}
function processJoin(
address joiner,
uint256 community,
bytes calldata data
) external payable onlyOsp {
_processJoin(joiner, community, data);
}
function processTransferJoinNFT(
uint256 communityId,
uint256 joinNFTId,
address from,
address to
) external onlyOsp {
_processTransferJoinNFT(communityId, joinNFTId, from, to);
}
function _initializeCommunityJoinCondition(
uint256 communityId,
bytes calldata data
) internal virtual;
function _processJoin(address joiner, uint256 community, bytes calldata data) internal virtual;
function _processTransferJoinNFT(
uint256 communityId,
uint256 joinNFTId,
address from,
address to
) internal virtual {}
}
文件 85 的 124:JoinNFT.sol
pragma solidity 0.8.20;
import {IJoinNFT} from '../interfaces/IJoinNFT.sol';
import {OspErrors} from '../libraries/OspErrors.sol';
import {OspEvents} from '../libraries/OspEvents.sol';
import {Constants} from '../libraries/Constants.sol';
import {OspDataTypes} from '../libraries/OspDataTypes.sol';
import {Payment} from '../libraries/Payment.sol';
import {OspNFTBase, ERC721Upgradeable} from './base/OspNFTBase.sol';
import {OspClient} from './logics/interfaces/OspClient.sol';
import {IERC721} from '@openzeppelin/contracts/token/ERC721/IERC721.sol';
import {IERC2981} from '@openzeppelin/contracts/interfaces/IERC2981.sol';
import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
contract JoinNFT is OspNFTBase, IJoinNFT, IERC2981 {
using Payment for address;
address public immutable OSP;
uint256 internal _communityId;
uint256 internal _tokenIdCounter;
mapping(address => bool) internal _blockList;
mapping(address => uint256) internal _role;
mapping(uint256 => uint256) internal _level;
modifier notBlock(address account) {
if (_blockList[account]) revert OspErrors.JoinNFTBlocked();
_;
}
constructor(address osp) {
if (osp == address(0)) revert OspErrors.InitParamsInvalid();
OSP = osp;
}
function initialize(
uint256 communityId,
string calldata name,
string calldata symbol
) external override {
if (msg.sender != OSP) revert OspErrors.NotOSP();
_communityId = communityId;
super._initialize(name, symbol);
emit OspEvents.JoinNFTInitialized(communityId, block.timestamp);
}
function mint(address to) external override returns (uint256) {
if (msg.sender != OSP) revert OspErrors.NotOSP();
unchecked {
uint256 tokenId = ++_tokenIdCounter;
_mint(to, tokenId);
return tokenId;
}
}
function setAdmin(address account) public override notBlock(account) returns (bool) {
return _setRole(Constants.COMMUNITY_ADMIN_ACCESS, account);
}
function setModerator(address account) public override notBlock(account) returns (bool) {
return _setRole(Constants.COMMUNITY_MODERATOR_ACCESS, account);
}
function removeRole(address account) public override returns (bool) {
return _setRole(Constants.COMMUNITY_NULL_ACCESS, account);
}
function setMemberLevel(address account, uint256 level) public override returns (bool) {
uint256 tokenId = tokenOfOwnerByIndex(account, 0);
if (hasRole(Constants.COMMUNITY_MODERATOR_ACCESS, _msgSender())) {
if (_level[tokenId] != level) {
_level[tokenId] = level;
OspClient(OSP).emitJoinNFTAccountLevelChangedEvent(
_communityId,
_msgSender(),
tokenId,
ownerOf(tokenId),
level
);
return true;
}
return false;
}
revert OspErrors.JoinNFTUnauthorizedAccount();
}
function setBlockList(address account, bool enable) public override returns (bool) {
if (hasRole(Constants.COMMUNITY_MODERATOR_ACCESS, _msgSender())) {
if (_blockList[account] != enable) {
_blockList[account] = enable;
OspClient(OSP).emitJoinNFTAccountBlockedEvent(
_communityId,
_msgSender(),
account,
enable
);
return true;
}
return false;
}
revert OspErrors.JoinNFTUnauthorizedAccount();
}
function withdraw(address token) external {
OspClient ospClient = OspClient(OSP);
(, uint128 ospTreasureFraction) = ospClient.joinNFTRoyaltyInfo();
address treasureAddress = ospClient.getTreasureAddress();
address communityAccount = ospClient.getCommunityAccount(_communityId);
uint256 value;
if (address(0) == token) {
value = address(this).balance;
uint256 serviceFee = (value * ospTreasureFraction) / Constants.ROYALTY_DENOMINATOR;
Payment.payNative(treasureAddress, serviceFee);
Payment.payNative(communityAccount, value - serviceFee);
} else {
value = IERC20(token).balanceOf(address(this));
uint256 serviceFee = (value * ospTreasureFraction) / Constants.ROYALTY_DENOMINATOR;
token.payERC20(treasureAddress, serviceFee);
token.payERC20(communityAccount, value - serviceFee);
}
}
function getSourceCommunityPointer() external view override returns (uint256) {
return _communityId;
}
function tokenURI(uint256 tokenId) public view override returns (string memory) {
return OspClient(OSP).getJoinNFTURI(_communityId, tokenId);
}
function balanceOf(
address addr
) public view override(IERC721, ERC721Upgradeable) notBlock(addr) returns (uint256) {
return super.balanceOf(addr);
}
function ownerOf(
uint256 tokenId
) public view override(IERC721, ERC721Upgradeable) returns (address) {
address owner = super.ownerOf(tokenId);
if (_blockList[owner]) {
revert OspErrors.JoinNFTBlocked();
}
return owner;
}
function hasRole(uint256 roles, address account) public view override returns (bool) {
return _role[account] >= roles || _isCommunityOwner(account);
}
function getRole(address account) public view override returns (uint256) {
if (_isCommunityOwner(account)) {
return type(uint256).max;
}
return _role[account];
}
function getMemberLevel(address account) external view override returns (uint256) {
return _level[tokenOfOwnerByIndex(account, 0)];
}
function getMemberLevel(uint256 tokenId) external view override returns (uint256) {
return _level[tokenId];
}
function isBlock(address account) external view override returns (bool) {
return _blockList[account];
}
function royaltyInfo(
uint256 ,
uint256 salePrice
) external view returns (address receiver, uint256 royaltyAmount) {
(uint128 royaltyFraction, ) = OspClient(OSP).joinNFTRoyaltyInfo();
return (address(this), (salePrice * royaltyFraction) / Constants.ROYALTY_DENOMINATOR);
}
function _afterTokenTransfer(address from, address to, uint256 tokenId) internal override {
if (_blockList[from] || _blockList[to]) {
revert OspErrors.JoinNFTBlocked();
}
super._afterTokenTransfer(from, to, tokenId);
if (to != address(0) && balanceOf(to) > 1) revert OspErrors.JoinNFTDuplicated();
if (from != address(0)) {
_setRole(Constants.COMMUNITY_NULL_ACCESS, from);
}
if (to == address(0)) {
_level[tokenId] = 0;
}
OspClient(OSP).emitJoinNFTTransferEvent(_communityId, tokenId, from, to);
}
function _isCommunityOwner(address account) internal view returns (bool) {
return IERC721(OspClient(OSP).getCommunityNFT()).ownerOf(_communityId) == account;
}
function _setRole(uint256 role, address account) internal returns (bool) {
address sender = _msgSender();
uint256 oldRole = getRole(account);
if (balanceOf(account) == 0) {
if (role != Constants.COMMUNITY_NULL_ACCESS) revert OspErrors.NotJoinCommunity();
} else {
uint256 senderRole = getRole(sender);
if (senderRole <= oldRole || role >= senderRole) {
revert OspErrors.JoinNFTUnauthorizedAccount();
}
}
if (oldRole != role) {
_role[account] = role;
OspClient(OSP).emitJoinNFTRoleChangedEvent(_communityId, sender, account, role);
return true;
}
return false;
}
}
文件 86 的 124:JoinNFTProxy.sol
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();
}
}
文件 87 的 124:LikeReaction.sol
pragma solidity 0.8.20;
import {OpenReactionBase} from '../base/OpenReactionBase.sol';
import {OspErrors} from '../../libraries/OspErrors.sol';
contract LikeReaction is OpenReactionBase {
constructor(address osp) OpenReactionBase(osp) {}
function _processReaction(
uint256 ,
uint256 ,
uint256 ,
bytes calldata data
) internal view override {
abi.decode(data, (bool));
}
}
文件 88 的 124:Math.sol
pragma solidity ^0.8.20;
library Math {
error MathOverflowedMulDiv();
enum Rounding {
Floor,
Ceil,
Trunc,
Expand
}
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function average(uint256 a, uint256 b) internal pure returns (uint256) {
return (a & b) + (a ^ b) / 2;
}
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
return a / b;
}
return a == 0 ? 0 : (a - 1) / b + 1;
}
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
uint256 prod0 = x * y;
uint256 prod1;
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
if (prod1 == 0) {
return prod0 / denominator;
}
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
uint256 remainder;
assembly {
remainder := mulmod(x, y, denominator)
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
uint256 twos = denominator & (0 - denominator);
assembly {
denominator := div(denominator, twos)
prod0 := div(prod0, twos)
twos := add(div(sub(0, twos), twos), 1)
}
prod0 |= prod1 * twos;
uint256 inverse = (3 * denominator) ^ 2;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
result = prod0 * inverse;
return result;
}
}
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 result = 1 << (log2(a) >> 1);
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);
}
}
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 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;
}
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 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;
}
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
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;
}
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}
文件 89 的 124:MessageHashUtils.sol
pragma solidity ^0.8.20;
import {Strings} from "../Strings.sol";
library MessageHashUtils {
function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
assembly {
mstore(0x00, "\x19Ethereum Signed Message:\n32")
mstore(0x1c, messageHash)
digest := keccak256(0x00, 0x3c)
}
}
function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
return
keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message));
}
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(hex"19_00", validator, data));
}
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
assembly {
let ptr := mload(0x40)
mstore(ptr, hex"19_01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
digest := keccak256(ptr, 0x42)
}
}
}
文件 90 的 124:Multicall.sol
pragma solidity ^0.8.20;
import {Address} from "./Address.sol";
abstract contract Multicall {
function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) {
results = new bytes[](data.length);
for (uint256 i = 0; i < data.length; i++) {
results[i] = Address.functionDelegateCall(address(this), data[i]);
}
return results;
}
}
文件 91 的 124:NativeFeeJoinCond.sol
pragma solidity 0.8.20;
import {CondErrors} from '../libraries/CondErrors.sol';
import {JoinConditionBase} from '../../base/JoinConditionBase.sol';
import {Payment} from '../../../libraries/Payment.sol';
struct CommunityData {
uint256 amount;
address recipient;
}
contract NativeFeeJoinCond is JoinConditionBase {
mapping(uint256 => CommunityData) internal _dataByCommunity;
constructor(address osp) JoinConditionBase(osp) {}
function _initializeCommunityJoinCondition(
uint256 communityId,
bytes calldata data
) internal override onlyOsp {
(uint256 amount, address recipient) = abi.decode(data, (uint256, address));
if (recipient == address(0) || amount == 0) revert CondErrors.InitParamsInvalid();
_dataByCommunity[communityId].amount = amount;
_dataByCommunity[communityId].recipient = recipient;
}
function _processJoin(
address follower,
uint256 communityId,
bytes calldata data
) internal override onlyOsp {
uint256 value = msg.value;
if (value != _dataByCommunity[communityId].amount)
revert CondErrors.ConditionDataMismatch();
Payment.payNative(_dataByCommunity[communityId].recipient, value);
(follower, data);
}
function getCommunityData(uint256 communityId) external view returns (CommunityData memory) {
return _dataByCommunity[communityId];
}
}
文件 92 的 124:OnlyMemberReferenceCond.sol
pragma solidity 0.8.20;
import {OspErrors} from '../../../libraries/OspErrors.sol';
import {ReferenceConditionBase} from '../../base/ReferenceConditionBase.sol';
contract OnlyMemberReferenceCond is ReferenceConditionBase {
constructor(address osp) ReferenceConditionBase(osp) {}
function _initializeReferenceCondition(
uint256 ,
uint256 ,
uint256 ,
bytes calldata
) internal override {
}
function _processReactionReference(
uint256 ,
uint256 communityId,
uint256 referencedProfileId,
uint256 referencedContentId,
bytes calldata
) internal override nonPayable {
uint256 referencedCommunityId = OSP.getCommunityIdByContent(
referencedProfileId,
referencedContentId
);
if (communityId != referencedCommunityId) {
revert OspErrors.InvalidCommunityId();
}
}
}
文件 93 的 124:OpenReactionBase.sol
pragma solidity 0.8.20;
import {IOpenReaction} from '../../interfaces/IOpenReaction.sol';
import {OspContext} from './OspContext.sol';
import {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';
abstract contract OpenReactionBase is OspContext, IOpenReaction, IERC165 {
constructor(address osp) OspContext(osp) {}
function processReaction(
uint256 profileId,
uint256 referencedProfileId,
uint256 referencedContentId,
bytes calldata data
) external payable override onlyOsp {
_processReaction(profileId, referencedProfileId, referencedContentId, data);
}
function _processReaction(
uint256 profileId,
uint256 referencedProfileId,
uint256 referencedContentId,
bytes calldata data
) internal virtual;
function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {
return
interfaceId == type(IOpenReaction).interfaceId ||
interfaceId == type(IERC165).interfaceId;
}
}
文件 94 的 124:OspClient.sol
pragma solidity 0.8.20;
import './IGovernanceLogic.sol';
import './IProfileLogic.sol';
import './IContentLogic.sol';
import './IRelationLogic.sol';
import './ICommunityLogic.sol';
import '../../../libraries/OspErrors.sol';
import '../../../libraries/OspEvents.sol';
interface OspClient is
IGovernanceLogic,
IProfileLogic,
IContentLogic,
IRelationLogic,
ICommunityLogic
{
}
文件 95 的 124:OspContext.sol
pragma solidity 0.8.20;
import '@openzeppelin/contracts/utils/Context.sol';
import '../logics/interfaces/OspClient.sol';
abstract contract OspContext is Context {
OspClient immutable OSP;
constructor(address osp) {
if (osp == address(0)) revert OspErrors.InitParamsInvalid();
OSP = OspClient(osp);
}
modifier onlyOsp() {
if (_msgSender() != address(OSP)) revert OspErrors.NotOSP();
_;
}
modifier onlyGov() {
if (!OSP.hasRole(Constants.GOVERNANCE, _msgSender())) revert OspErrors.NotGovernance();
_;
}
modifier onlyOperation() {
if (!OSP.hasRole(Constants.OPERATION, _msgSender())) revert OspErrors.NotOperation();
_;
}
modifier onlyProfile() {
if (OSP.getProfileIdByAddress(_msgSender()) == 0) revert OspErrors.NotHasProfile();
_;
}
modifier nonPayable() {
if (msg.value != 0) revert OspErrors.InvalidValue();
_;
}
}
文件 96 的 124:OspDataTypes.sol
pragma solidity 0.8.20;
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)'
);
enum ProtocolState {
Unpaused,
PublishingPaused,
Paused
}
struct EIP712Signature {
address signer;
bytes signature;
uint256 deadline;
}
struct ProfileStruct {
uint256 contentCount;
address followCondition;
address followSBT;
string handle;
address owner;
uint96 mintTimestamp;
uint256 inviter;
}
struct CommunityStruct {
string handle;
address joinCondition;
address joinNFT;
address activityCondition;
address viewPrivacyCondition;
}
struct ContentStruct {
uint256 communityId;
uint256 referencedProfileId;
uint256 referencedContentId;
string contentURI;
address extension;
address referenceCondition;
}
struct PluginStruct {
bool isEnable;
address tokenAddress;
uint256 amount;
}
struct CreateProfileData {
string handle;
bytes followConditionInitCode;
uint256 inviter;
bytes ctx;
}
struct CreateActivityData {
uint256 profileId;
uint256 communityId;
string contentURI;
bytes extensionInitCode;
bytes referenceConditionInitCode;
bytes ctx;
}
struct CreateCommentData {
uint256 profileId;
uint256 communityId;
string contentURI;
uint256 referencedProfileId;
uint256 referencedContentId;
bytes referenceConditionInitCode;
bytes referenceConditionData;
bytes ctx;
}
struct CreateMegaphoneData {
uint256 profileId;
uint256 referencedProfileId;
uint256 referencedContentId;
string[] tags;
uint256 startTime;
uint256 duration;
address currency;
uint256 amount;
bytes ctx;
}
struct CreateOpenReactionData {
uint256 profileId;
uint256 communityId;
uint256 referencedProfileId;
uint256 referencedContentId;
uint256 reactionValue;
bytes reactionAndData;
bytes referenceConditionData;
bytes ctx;
}
struct CreateCommunityData {
string handle;
bytes communityConditionAndData;
bytes joinConditionInitCode;
string[] tags;
bytes ctx;
}
struct FollowData {
uint256 profileId;
bytes data;
bytes ctx;
}
struct BatchFollowData {
uint256[] profileIds;
bytes[] datas;
uint256[] values;
bytes ctx;
}
struct JoinData {
uint256 communityId;
bytes data;
bytes ctx;
}
struct BatchJoinData {
uint256[] communityIds;
bytes[] datas;
uint256[] values;
bytes ctx;
}
struct RoyaltyInfo {
uint128 royaltyFraction;
uint128 ospTreasureFraction;
}
}
文件 97 的 124:OspErrors.sol
pragma solidity 0.8.20;
library OspErrors {
error ArrayMismatch();
error SignatureExpired();
error SignatureInvalid();
error NotOwnerOrApproved();
error TokenDoesNotExist();
error SBTTokenAlreadyExists();
error SBTTransferNotAllowed();
error JoinNFTDuplicated();
error JoinNFTUnauthorizedAccount();
error JoinNFTBlocked();
error NotOSP();
error InvalidSender();
error NotGovernance();
error NotOperation();
error EmergencyAdminCannotUnpause();
error AppNotWhitelisted();
error ExtensionNotCommunityWhitelisted();
error NotProfileOwner();
error NotHasProfile();
error ProfileDoesNotExist();
error ContentDoesNotExist();
error HandleTaken();
error HandleLengthInvalid();
error HandleContainsInvalidCharacters();
error NotCommunityOwner();
error NotJoinCommunity();
error NotFollowProfile();
error NotJoinNFT();
error NotFollowSBT();
error NotCommunityNFT();
error ContentNotPublic();
error TagDoesNotExist();
error TooManyTags();
error InitParamsInvalid();
error ERC6551AccountImplNotDeployed();
error DataMismatch();
error InvalidToken();
error InvalidContentURI();
error InvalidProfileId();
error InvalidCommunityId();
error InvalidValue();
error InvalidTreasure();
error InvalidAddress();
error InvalidParam();
error PluginNotEnable();
error PluginAlreadyPurchased();
error Paused();
error PublishingPaused();
error ReactionInvalid();
}
文件 98 的 124:OspEvents.sol
pragma solidity 0.8.20;
import {OspDataTypes} from './OspDataTypes.sol';
library OspEvents {
event OSPInitialized(
string name,
string symbol,
address followSBTImpl,
address joinNFTImpl,
address communityNFT,
address communityAccountProxy,
uint256 timestamp
);
event StateSet(
address indexed caller,
OspDataTypes.ProtocolState indexed prevState,
OspDataTypes.ProtocolState indexed newState,
uint256 timestamp
);
event BaseURISet(string communityNFTBaseURI, uint256 timestamp);
event AppWhitelisted(address indexed app, bool indexed whitelisted, uint256 timestamp);
event TokenWhitelisted(address indexed token, bool indexed whitelisted, uint256 timestamp);
event CommunityHandleReserve(
bytes32 indexed handleHash,
bool indexed isReserved,
string handle,
uint256 timestamp
);
event ProfileCreated(
uint256 indexed profileId,
address indexed to,
string handle,
address followCondition,
uint256 inviter,
bytes ctx,
uint256 timestamp
);
event FollowConditionSet(uint256 indexed profileId, address followCondition, uint256 timestamp);
event FollowSBTDeployed(
uint256 indexed profileId,
address indexed followSBT,
uint256 timestamp
);
event Followed(
address indexed follower,
uint256 indexed followerProfileId,
uint256 profileId,
bytes followConditionData,
uint256 tokenId,
bytes ctx,
uint256 timestamp
);
event BatchFollowed(
address indexed follower,
uint256 followerProfileId,
uint256[] profileIds,
bytes[] followConditionDatas,
uint256[] tokenIds,
bytes ctx,
uint256 timestamp
);
event FollowSBTTransferred(
uint256 indexed profileId,
uint256 indexed followSBTId,
address from,
address to,
uint256 timestamp
);
event CommunityNFTTransferred(
uint256 indexed communityId,
address from,
address to,
uint256 timestamp
);
event JoinNFTTransferred(
uint256 indexed communityId,
uint256 indexed joinNFTId,
address from,
address to,
uint256 timestamp
);
event FollowSBTInitialized(uint256 indexed profileId, uint256 timestamp);
event JoinNFTInitialized(uint256 indexed communityId, uint256 timestamp);
event JoinNFTDeployed(uint256 indexed communityId, address indexed joinNFT, uint256 timestamp);
event CommunityCreated(
uint256 indexed communityId,
address indexed to,
string handle,
bytes communityConditionAndData,
address joinCondition,
address joinNFT,
string[] tags,
bytes ctx,
uint256 timestamp
);
event CommunityTagsUpdated(
uint256 indexed communityId,
address indexed sender,
string[] tags,
uint256 timestamp
);
event Joined(
address indexed joiner,
uint256 joinerProfileId,
uint256 communityId,
bytes joinConditionData,
uint256 tokenId,
bytes ctx,
uint256 timestamp
);
event BatchJoined(
address indexed joiner,
uint256 joinerProfileId,
uint256[] communityIds,
bytes[] joinConditionDatas,
uint256[] tokenIds,
bytes ctx,
uint256 timestamp
);
event JoinConditionSet(
uint256 indexed communityId,
address indexed sender,
address joinCondition,
uint256 timestamp
);
event ActivityConditionSet(
uint256 indexed communityId,
address indexed sender,
address activityCondition,
uint256 timestamp
);
event ViewPrivacyConditionSet(
uint256 indexed communityId,
address indexed sender,
address viewPrivacyCondition,
uint256 timestamp
);
event ActivityCreated(
uint256 indexed profileId,
uint256 indexed contentId,
uint256 communityId,
string contentURI,
address extension,
address referenceCondition,
bytes ctx,
uint256 timestamp
);
event CommentCreated(
uint256 indexed profileId,
uint256 indexed contentId,
uint256 communityId,
string contentURI,
uint256 referencedProfileId,
uint256 referencedContentId,
address referenceCondition,
bytes ctx,
uint256 timestamp
);
event OpenReactionCreated(
uint256 indexed profileId,
uint256 indexed referencedProfileId,
uint256 indexed referencedContentId,
uint256 communityId,
address openReaction,
bytes openReactionData,
bytes ctx,
uint256 timestamp
);
event MegaphoneCreated(
uint256 indexed megaphoneId,
uint256 indexed referencedProfileId,
uint256 indexed referencedContentId,
uint256 profileId,
string[] tags,
uint256 startTime,
uint256 duration,
address currency,
uint256 amount,
bytes ctx,
uint256 timestamp
);
event ERC6551AccountImplSet(address accountImpl, uint256 timestamp);
event JoinNFTImplSet(address accountImpl, uint256 timestamp);
event JoinNFTRoleChanged(
uint256 indexed communityId,
address indexed sender,
address indexed account,
uint256 role,
uint256 timestamp
);
event JoinNFTAccountBlocked(
uint256 indexed communityId,
address indexed sender,
address indexed account,
bool isBlock,
uint256 timestamp
);
event JoinNFTAccountLevelChanged(
uint256 indexed communityId,
uint256 indexed tokenId,
address indexed sender,
address account,
address communityJoinNFT,
uint256 level,
uint256 timestamp
);
event CommunityExtensionWhitelistSet(
uint256 indexed communityId,
address indexed extension,
bool indexed isWhitelist,
address sender,
uint256 timestamp
);
}
文件 99 的 124:OspHelpers.sol
pragma solidity 0.8.20;
import './OspDataTypes.sol';
import './OspErrors.sol';
library OspHelpers {
function getPointedIfWithContentRoot(
uint256 profileId,
uint256 contentId,
mapping(uint256 => mapping(uint256 => OspDataTypes.ContentStruct))
storage _contentByIdByProfile
) internal view returns (uint256, uint256) {
string memory contentURI = _contentByIdByProfile[profileId][contentId].contentURI;
if (bytes(contentURI).length == 0) {
uint256 pointedTokenId = _contentByIdByProfile[profileId][contentId]
.referencedProfileId;
if (pointedTokenId == 0) revert OspErrors.ContentDoesNotExist();
uint256 pointedcontentId = _contentByIdByProfile[profileId][contentId]
.referencedContentId;
return (pointedTokenId, pointedcontentId);
} else {
return (profileId, contentId);
}
}
}
文件 100 的 124:OspLogicBase.sol
pragma solidity 0.8.20;
import {OspStorage} from 'contracts/core/storage/OspStorage.sol';
import {OspMultiState} from 'contracts/core/base/OspMultiState.sol';
import {EIP712Base} from 'contracts/core/base/EIP712Base.sol';
import {OspErrors} from 'contracts/libraries/OspErrors.sol';
import {OspEvents} from 'contracts/libraries/OspEvents.sol';
import {OspDataTypes} from 'contracts/libraries/OspDataTypes.sol';
import {IJoinCondition} from 'contracts/interfaces/IJoinCondition.sol';
import {IOpenReaction} from 'contracts/interfaces/IOpenReaction.sol';
import {IActivityExtension} from 'contracts/interfaces/IActivityExtension.sol';
import {IReferenceCondition} from 'contracts/interfaces/IReferenceCondition.sol';
import {ICommunityCondition} from 'contracts/interfaces/ICommunityCondition.sol';
import {IFollowCondition} from 'contracts/interfaces/IFollowCondition.sol';
import {IActivityCondition} from 'contracts/interfaces/IActivityCondition.sol';
import {IViewPrivacyCondition} from 'contracts/interfaces/IViewPrivacyCondition.sol';
import {ERC165Checker} from '@openzeppelin/contracts/utils/introspection/ERC165Checker.sol';
import {AccessControlUpgradeable} from '@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol';
contract OspLogicBase is OspMultiState, OspStorage, EIP712Base {
function _checkFollowCondition(address followCondition) internal view {
if (
!_getGovernanceStorage()._appWhitelisted[followCondition] ||
!ERC165Checker.supportsInterface(followCondition, type(IFollowCondition).interfaceId)
) revert OspErrors.AppNotWhitelisted();
}
function _checkCommunityCondition(address communityCondition) internal view {
if (
!_getGovernanceStorage()._appWhitelisted[communityCondition] ||
!ERC165Checker.supportsInterface(
communityCondition,
type(ICommunityCondition).interfaceId
)
) revert OspErrors.AppNotWhitelisted();
}
function _checkJoinCondition(address joinCondition) internal view {
if (
!_getGovernanceStorage()._appWhitelisted[joinCondition] ||
!ERC165Checker.supportsInterface(joinCondition, type(IJoinCondition).interfaceId)
) revert OspErrors.AppNotWhitelisted();
}
function _checkActivityCondition(address activityCondition) internal view {
if (
!_getGovernanceStorage()._appWhitelisted[activityCondition] ||
!ERC165Checker.supportsInterface(
activityCondition,
type(IActivityCondition).interfaceId
)
) revert OspErrors.AppNotWhitelisted();
}
function _checkViewPrivacyCondition(address privacyCondition) internal view {
if (
!_getGovernanceStorage()._appWhitelisted[privacyCondition] ||
!ERC165Checker.supportsInterface(
privacyCondition,
type(IViewPrivacyCondition).interfaceId
)
) revert OspErrors.AppNotWhitelisted();
}
function _checkActivityExtension(address extension) internal view {
if (
!_getGovernanceStorage()._appWhitelisted[extension] ||
!ERC165Checker.supportsInterface(extension, type(IActivityExtension).interfaceId)
) revert OspErrors.AppNotWhitelisted();
}
function _checkOpenReaction(address openReaction) internal view {
if (
!_getGovernanceStorage()._appWhitelisted[openReaction] ||
!ERC165Checker.supportsInterface(openReaction, type(IOpenReaction).interfaceId)
) revert OspErrors.AppNotWhitelisted();
}
function _checkReferenceCondition(address referenceCondition) internal view {
if (
!_getGovernanceStorage()._appWhitelisted[referenceCondition] ||
!ERC165Checker.supportsInterface(
referenceCondition,
type(IReferenceCondition).interfaceId
)
) revert OspErrors.AppNotWhitelisted();
}
function _hashRole(bytes32 role, address account) internal view returns (bool) {
AccessControlUpgradeable.AccessControlStorage storage $;
assembly {
$.slot := 0x02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800
}
return $._roles[role].hasRole[account];
}
function _validateIsProfileOwner(address addr, uint256 profileId) internal view {
if (addr != _ownerOf(profileId)) revert OspErrors.NotProfileOwner();
}
function _validateHasProfile(address addr) internal view returns (uint256) {
uint256 profileId = _getProfileStorage()._profileIdByAddress[addr];
if (profileId == 0) revert OspErrors.NotHasProfile();
return profileId;
}
function _ownerOf(uint256 profileId) internal view returns (address) {
return _getProfileStorage()._profileById[profileId].owner;
}
function _calculateDomainSeparator() internal view virtual override returns (bytes32) {
return
keccak256(
abi.encode(
OspDataTypes.EIP712_DOMAIN_TYPEHASH,
keccak256(bytes(_getGovernanceStorage()._name)),
EIP712_REVISION_HASH,
block.chainid,
address(this)
)
);
}
}
文件 101 的 124:OspMultiState.sol
pragma solidity 0.8.20;
import '../../libraries/OspEvents.sol';
import '../../libraries/OspDataTypes.sol';
import '../../libraries/OspErrors.sol';
abstract contract OspMultiState {
struct ProtocolStateStorage {
OspDataTypes.ProtocolState state;
}
bytes32 internal constant STATE_STORAGE_POSITION = keccak256('osp.state.storage');
modifier whenNotPaused() {
_validateNotPaused();
_;
}
modifier whenPublishingEnabled() {
_validatePublishingEnabled();
_;
}
function protocolStateStorage()
internal
pure
returns (ProtocolStateStorage storage protocolState)
{
bytes32 position = STATE_STORAGE_POSITION;
assembly {
protocolState.slot := position
}
}
function _getState() internal view returns (OspDataTypes.ProtocolState) {
return protocolStateStorage().state;
}
function _setState(OspDataTypes.ProtocolState newState) internal {
OspDataTypes.ProtocolState prevState = protocolStateStorage().state;
protocolStateStorage().state = newState;
emit OspEvents.StateSet(msg.sender, prevState, newState, block.timestamp);
}
function _validatePublishingEnabled() internal view {
if (protocolStateStorage().state != OspDataTypes.ProtocolState.Unpaused) {
revert OspErrors.PublishingPaused();
}
}
function _validateNotPaused() internal view {
if (protocolStateStorage().state == OspDataTypes.ProtocolState.Paused)
revert OspErrors.Paused();
}
}
文件 102 的 124:OspNFTBase.sol
pragma solidity 0.8.20;
import {ERC721BurnableUpgradeable} from '@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol';
import {ERC721EnumerableUpgradeable} from '@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol';
import {ERC721Upgradeable} from '@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol';
abstract contract OspNFTBase is ERC721EnumerableUpgradeable, ERC721BurnableUpgradeable {
function _initialize(string memory name, string memory symbol) internal initializer {
__ERC721_init(name, symbol);
}
function _update(
address to,
uint256 tokenId,
address auth
)
internal
override(ERC721EnumerableUpgradeable, ERC721Upgradeable)
returns (address previousOwner)
{
previousOwner = ERC721EnumerableUpgradeable._update(to, tokenId, auth);
_afterTokenTransfer(previousOwner, to, tokenId);
}
function _afterTokenTransfer(address from, address to, uint256 tokenId) internal virtual {}
function supportsInterface(
bytes4 interfaceId
) public view virtual override(ERC721EnumerableUpgradeable, ERC721Upgradeable) returns (bool) {
return ERC721EnumerableUpgradeable.supportsInterface(interfaceId);
}
function _increaseBalance(
address account,
uint128 amount
) internal virtual override(ERC721EnumerableUpgradeable, ERC721Upgradeable) {
ERC721EnumerableUpgradeable._increaseBalance(account, amount);
}
}
文件 103 的 124:OspRouterImmutable.sol
pragma solidity 0.8.20;
import './IRouter.sol';
import '@openzeppelin/contracts/utils/introspection/ERC165.sol';
import '@openzeppelin/contracts/utils/structs/EnumerableSet.sol';
import '@openzeppelin/contracts/proxy/Proxy.sol';
import '@openzeppelin/contracts/utils/Multicall.sol';
contract OspRouterImmutable is Multicall, ERC165, IRouter, Proxy {
using EnumerableSet for EnumerableSet.Bytes32Set;
struct Data {
address admin;
EnumerableSet.Bytes32Set allSelectors;
mapping(address => EnumerableSet.Bytes32Set) selectorsForRouter;
mapping(bytes4 => Router) routerForSelector;
address pendingAdmin;
uint96 pendingAdminTimestamp;
}
event AdminChanged(address previousAdmin, address newAdmin);
event ChangeAdminStarted(address pendingAdmin, uint256 pendingAdminTimestamp);
event PendingAdminRevoked(address pendingAdmin);
constructor(address admin_) {
_changeAdmin(admin_);
}
bytes32 internal constant ROUTER_STORAGE_POSITION = keccak256('osp.router.storage');
function routerStorage() internal pure returns (Data storage routerData) {
bytes32 position = ROUTER_STORAGE_POSITION;
assembly {
routerData.slot := position
}
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
if (interfaceId == type(IRouter).interfaceId || super.supportsInterface(interfaceId)) {
return true;
} else {
address implementation = _implementation();
return
implementation == address(0)
? false
: IERC165(implementation).supportsInterface(interfaceId);
}
}
modifier onlyAdmin() {
Data storage data = routerStorage();
require(msg.sender == data.admin, 'Router: Not authorized.');
_;
}
function changeAdmin(address _newAdmin) public onlyAdmin {
Data storage data = routerStorage();
data.pendingAdmin = _newAdmin;
data.pendingAdminTimestamp = uint96(block.timestamp);
emit ChangeAdminStarted(_newAdmin, block.timestamp);
}
function revokePendingAdmin() public onlyAdmin {
Data storage data = routerStorage();
address pendingAdmin = data.pendingAdmin;
data.pendingAdmin = address(0);
data.pendingAdminTimestamp = 0;
emit PendingAdminRevoked(pendingAdmin);
}
function acceptAdminRole() public {
Data storage data = routerStorage();
require(
msg.sender == data.pendingAdmin &&
block.timestamp > data.pendingAdminTimestamp + 1 days,
'Router: Admin role not available.'
);
_changeAdmin(data.pendingAdmin);
data.pendingAdmin = address(0);
data.pendingAdminTimestamp = 0;
}
function getAdmin() public view returns (address) {
Data storage data = routerStorage();
return data.admin;
}
function getPendingAdmin() public view returns (address) {
Data storage data = routerStorage();
return data.pendingAdmin;
}
function getPendingAdminTimestamp() public view returns (uint96) {
Data storage data = routerStorage();
return data.pendingAdminTimestamp;
}
function addRouter(Router memory _router) public onlyAdmin {
_addRouter(_router);
}
function updateRouter(Router memory _router) public onlyAdmin {
_updateRouter(_router);
}
function removeRouter(bytes4 selector, string calldata functionSignature) public onlyAdmin {
_removeRouter(selector, functionSignature);
}
function getRouterForFunction(bytes4 _selector) public view returns (address) {
return _getRouterForFunction(_selector);
}
function getAllFunctionsOfRouter(
address _routerAddress
) public view returns (bytes4[] memory registered) {
Data storage data = routerStorage();
uint256 count = data.selectorsForRouter[_routerAddress].length();
registered = new bytes4[](count);
for (uint256 i; i < count; i += 1) {
registered[i] = bytes4(data.selectorsForRouter[_routerAddress].at(i));
}
}
function getAllRouters() public view returns (Router[] memory registered) {
Data storage data = routerStorage();
EnumerableSet.Bytes32Set storage selectors = data.allSelectors;
uint256 count = selectors.length();
registered = new Router[](count);
for (uint256 i; i < count; i += 1) {
registered[i] = data.routerForSelector[bytes4(selectors.at(i))];
}
}
function _implementation() internal view virtual override returns (address) {
address router = _getRouterForFunction(msg.sig);
require(router != address(0), 'Router: Not found.');
return router;
}
function _getRouterForFunction(bytes4 _selector) public view returns (address) {
Data storage data = routerStorage();
return data.routerForSelector[_selector].routerAddress;
}
function _addRouter(Router memory _router) internal {
Data storage data = routerStorage();
require(
data.allSelectors.add(bytes32(_router.functionSelector)),
'Router: router exists for function.'
);
require(
_router.functionSelector ==
bytes4(keccak256(abi.encodePacked(_router.functionSignature))),
'Router: fn selector and signature mismatch.'
);
data.routerForSelector[_router.functionSelector] = _router;
data.selectorsForRouter[_router.routerAddress].add(bytes32(_router.functionSelector));
emit RouterAdded(_router.functionSelector, _router.routerAddress);
}
function _updateRouter(Router memory _router) internal {
address currentRouter = getRouterForFunction(_router.functionSelector);
require(currentRouter != address(0), 'Router: No router available for selector.');
require(
_router.functionSelector ==
bytes4(keccak256(abi.encodePacked(_router.functionSignature))),
'Router: fn selector and signature mismatch.'
);
Data storage data = routerStorage();
data.allSelectors.add(bytes32(_router.functionSelector));
data.routerForSelector[_router.functionSelector] = _router;
data.selectorsForRouter[currentRouter].remove(bytes32(_router.functionSelector));
data.selectorsForRouter[_router.routerAddress].add(bytes32(_router.functionSelector));
emit RouterUpdated(_router.functionSelector, currentRouter, _router.routerAddress);
}
function _removeRouter(bytes4 _selector, string calldata _functionSignature) internal {
Data storage data = routerStorage();
address currentRouter = _getRouterForFunction(_selector);
require(currentRouter != address(0), 'Router: No router available for selector.');
require(
_selector == bytes4(keccak256(abi.encodePacked(_functionSignature))),
'Router: fn selector and signature mismatch.'
);
delete data.routerForSelector[_selector];
data.allSelectors.remove(_selector);
data.selectorsForRouter[currentRouter].remove(bytes32(_selector));
emit RouterRemoved(_selector, currentRouter);
}
function _changeAdmin(address admin_) internal {
Data storage data = routerStorage();
emit AdminChanged(data.admin, admin_);
data.admin = admin_;
}
}
文件 104 的 124:OspSBTBase.sol
pragma solidity 0.8.20;
import {OspNFTBase} from './OspNFTBase.sol';
import {OspErrors} from '../../libraries/OspErrors.sol';
abstract contract OspSBTBase is OspNFTBase {
function _afterTokenTransfer(
address from,
address to,
uint256
) internal virtual override {
if (from != address(0) && to != address(0)) {
revert OspErrors.SBTTransferNotAllowed();
}
if (from == address(0) && to != address(0) && balanceOf(to) > 1) {
revert OspErrors.SBTTokenAlreadyExists();
}
}
}
文件 105 的 124:OspStorage.sol
pragma solidity 0.8.20;
import '../../libraries/OspDataTypes.sol';
import {EnumerableSet} from '@openzeppelin/contracts/utils/structs/EnumerableSet.sol';
abstract contract OspStorage {
bytes32 internal constant PROFILE_STORAGE_POSITION = keccak256('osp.profile.storage');
struct ProfileStorage {
uint256[] _allTokens;
mapping(uint256 => uint256) _allTokensIndex;
mapping(bytes32 => uint256) _profileIdByHandleHash;
mapping(uint256 => OspDataTypes.ProfileStruct) _profileById;
mapping(address => uint256) _profileIdByAddress;
uint256 _profileCounter;
mapping(address => uint256) _sigNonces;
}
function _getProfileStorage() internal pure returns (ProfileStorage storage profileStorage) {
bytes32 position = PROFILE_STORAGE_POSITION;
assembly {
profileStorage.slot := position
}
}
bytes32 internal constant PUBLICATION_STORAGE_POSITION = keccak256('osp.content.storage');
struct ContentStorage {
mapping(uint256 => mapping(uint256 => OspDataTypes.ContentStruct)) _contentByIdByProfile;
uint256 _megaphoneCount;
}
function _getContentStorage()
internal
pure
returns (ContentStorage storage publicationStorage)
{
bytes32 position = PUBLICATION_STORAGE_POSITION;
assembly {
publicationStorage.slot := position
}
}
bytes32 internal constant GOVERNANCE_STORAGE_POSITION = keccak256('osp.governance.storage');
struct GovernanceStorage {
string _name;
string _symbol;
address _followSBTImpl;
address _joinNFTImpl;
address _communityNFT;
address _communityAccountProxy;
address _erc6551AccountImpl;
string _baseURI;
mapping(address => bool) _appWhitelisted;
mapping(bytes32 => bool) _reserveCommunityHandleHash;
mapping(address => bool) _tokenWhitelisted;
mapping(address => bool) DEPRECATED_superCommunityCreatorWhitelisted;
address _treasure;
OspDataTypes.RoyaltyInfo _joinNFTRoyaltyInfo;
}
function _getGovernanceStorage()
internal
pure
returns (GovernanceStorage storage governanceStorage)
{
bytes32 position = GOVERNANCE_STORAGE_POSITION;
assembly {
governanceStorage.slot := position
}
}
bytes32 internal constant COMMUNITY_STORAGE_POSITION = keccak256('osp.community.storage');
struct CommunityStorage {
mapping(uint256 => OspDataTypes.CommunityStruct) _communityById;
mapping(bytes32 => uint256) _communityIdByHandleHash;
mapping(uint256 => EnumerableSet.AddressSet) _activityExtensionWhitelistByCommunity;
}
function _getCommunityStorage()
internal
pure
returns (CommunityStorage storage communityStorage)
{
bytes32 position = COMMUNITY_STORAGE_POSITION;
assembly {
communityStorage.slot := position
}
}
}
文件 106 的 124:OspUniversalProxy.sol
pragma solidity 0.8.20;
import '../core/logics/interfaces/OspClient.sol';
import '../core/base/OspContext.sol';
import {ERC1967Utils} from '@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol';
import {ERC1967Proxy} from '@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol';
contract OspUniversalProxy is OspContext, ERC1967Proxy {
constructor(
address osp,
address implementation,
bytes memory data
) OspContext(osp) ERC1967Proxy(implementation, data) {}
function updateToAndCall(address newImplementation, bytes memory data) external onlyGov {
ERC1967Utils.upgradeToAndCall(newImplementation, data);
}
}
文件 107 的 124:Payment.sol
pragma solidity 0.8.20;
import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
library Payment {
using SafeERC20 for IERC20;
function payNative(address to, uint256 amount) internal {
(bool success, ) = to.call{value: amount}('');
require(success, 'Transfer failed');
}
function payERC20(address token, address from, address to, uint256 amount) internal {
IERC20 payToken = IERC20(token);
payToken.safeTransferFrom(from, to, amount);
}
function payERC20(address token, address to, uint256 amount) internal {
IERC20 payToken = IERC20(token);
payToken.safeTransfer(to, amount);
}
}
文件 108 的 124:PresaleSigCommunityCond.sol
pragma solidity 0.8.20;
import {CommunityCondBase} from '../../base/CommunityCondBase.sol';
import {Payment} from '../../../libraries/Payment.sol';
import {ECDSA} from '@openzeppelin/contracts/utils/cryptography/ECDSA.sol';
import {CondErrors} from '../libraries/CondErrors.sol';
import {CondDataTypes} from '../libraries/CondDataTypes.sol';
import {CondHelpers} from '../libraries/CondHelpers.sol';
import {MessageHashUtils} from '@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol';
import {IERC721} from '@openzeppelin/contracts/token/ERC721/IERC721.sol';
contract PresaleSigCommunityCond is CommunityCondBase {
event PresaleTimeSet(uint256 indexed presaleStartTime, uint256 timestamp);
event SignerSet(address indexed signer, uint256 timestamp);
event PresaleSigPaid(
address indexed to,
address indexed ticket,
uint256 indexed tokenId,
uint256 price,
string handle,
uint256 timestamp
);
using ECDSA for bytes32;
using MessageHashUtils for bytes32;
uint256 public presaleStartTime;
address immutable fixedFeeCommunityCond;
address signer;
mapping(address => mapping(uint256 => bool)) _ticketUsed;
constructor(
address osp,
address _fixedFeeCommunityCond,
address _signer,
uint256 _presaleStartTime
) CommunityCondBase(osp) {
fixedFeeCommunityCond = _fixedFeeCommunityCond;
signer = _signer;
emit SignerSet(signer, block.timestamp);
_setPresaleStartTime(_presaleStartTime);
emit PresaleTimeSet(presaleStartTime, block.timestamp);
}
function _processCreateCommunity(
address to,
string calldata handle,
bytes calldata data
) internal override {
CondDataTypes.FixedFeeCondData memory fixedFeeCondData = _getFixedFeeCondData();
if (!isPresaleTime()) {
revert CondErrors.NotPresaleTime();
}
(address ticket, uint256 tokenId) = _validateTicketAndSig(to, data);
uint256 price = CondHelpers.getHandleETHPrice(handle, fixedFeeCondData);
_charge(price, to);
emit PresaleSigPaid(to, ticket, tokenId, price, handle, block.timestamp);
}
function setPresaleStartTime(uint256 _presaleStartTime) external onlyOperation {
_setPresaleStartTime(_presaleStartTime);
emit PresaleTimeSet(presaleStartTime, block.timestamp);
}
function setSigner(address _signer) external onlyOperation {
signer = _signer;
emit SignerSet(signer, block.timestamp);
}
function getHandlePrice(string calldata handle) external view returns (uint256) {
CondDataTypes.FixedFeeCondData memory fixedFeeCondData = _getFixedFeeCondData();
return CondHelpers.getHandleETHPrice(handle, fixedFeeCondData);
}
function isTicketUsable(
address ticket,
uint256 tokenId,
address holder
) external view returns (bool) {
return !_ticketUsed[ticket][tokenId] && IERC721(ticket).ownerOf(tokenId) == holder;
}
function isPresaleTime() public view returns (bool) {
return
block.timestamp >= presaleStartTime &&
block.timestamp < _getFixedFeeCondData().createStartTime;
}
function getPresaleTime() public view returns (uint256 start, uint256 end) {
start = presaleStartTime;
end = _getFixedFeeCondData().createStartTime;
}
function _getFixedFeeCondData() internal view returns (CondDataTypes.FixedFeeCondData memory) {
(bool success, bytes memory returnData) = fixedFeeCommunityCond.staticcall(
abi.encodeWithSignature('fixedFeeCondData()')
);
require(success, 'call fixFeeCommunityCond failed');
return abi.decode(returnData, (CondDataTypes.FixedFeeCondData));
}
function _setPresaleStartTime(uint256 _presaleStartTime) internal {
CondDataTypes.FixedFeeCondData memory fixFeeCondData = _getFixedFeeCondData();
require(_presaleStartTime < fixFeeCondData.createStartTime, 'Invalid time');
presaleStartTime = _presaleStartTime;
}
function _charge(uint256 price, address to) internal virtual {
if (msg.value < price) {
revert CondErrors.InsufficientPayment();
}
uint256 overpayment;
unchecked {
overpayment = msg.value - price;
}
if (overpayment > 0) {
Payment.payNative(to, overpayment);
}
address treasure = OSP.getTreasureAddress();
require(treasure != address(0), 'Invalid treasure');
Payment.payNative(treasure, price);
}
function _validateTicketAndSig(
address to,
bytes calldata data
) internal returns (address, uint256) {
(
address ticket,
uint256 tokenId,
address holder,
address target,
uint256 chainid,
bytes memory signature
) = abi.decode(data, (address, uint256, address, address, uint256, bytes));
if (
(_ticketUsed[ticket][tokenId] || IERC721(ticket).ownerOf(tokenId) != holder) ||
target != to ||
chainid != block.chainid
) {
revert CondErrors.InvalidTicket();
}
bytes32 hash = keccak256(abi.encodePacked(ticket, tokenId, holder, target, chainid));
if (hash.toEthSignedMessageHash().recover(signature) != signer) {
revert CondErrors.SignatureInvalid();
}
_ticketUsed[ticket][tokenId] = true;
return (ticket, tokenId);
}
}
文件 109 的 124:ProfileLogic.sol
pragma solidity 0.8.20;
import './interfaces/IProfileLogic.sol';
import './OspLogicBase.sol';
import '../../libraries/Constants.sol';
import '../../interfaces/IFollowCondition.sol';
import '@openzeppelin/contracts/utils/Strings.sol';
contract ProfileLogic is IProfileLogic, OspLogicBase {
using Strings for uint256;
function createProfile(
OspDataTypes.CreateProfileData calldata vars
) external override whenNotPaused returns (uint256) {
return _createProfile(vars);
}
function setFollowCondition(
uint256 profileId,
bytes calldata followConditionInitCode
) external override whenNotPaused {
_validateIsProfileOwner(msg.sender, profileId);
_setFollowCondition(profileId, followConditionInitCode);
}
function burn(uint256 ) external view override whenNotPaused {
revert OspErrors.SBTTransferNotAllowed();
}
function safeTransferFrom(
address ,
address ,
uint256 ,
bytes calldata
) external pure override {
revert OspErrors.SBTTransferNotAllowed();
}
function safeTransferFrom(
address ,
address ,
uint256
) external pure override {
revert OspErrors.SBTTransferNotAllowed();
}
function transferFrom(
address ,
address ,
uint256
) external pure override {
revert OspErrors.SBTTransferNotAllowed();
}
function approve(address , uint256 ) external pure override {
revert OspErrors.SBTTransferNotAllowed();
}
function setApprovalForAll(address , bool ) external pure override {
revert OspErrors.SBTTransferNotAllowed();
}
function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {
return
interfaceId == type(IERC721Enumerable).interfaceId ||
interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC721Metadata).interfaceId ||
interfaceId == type(IERC165).interfaceId;
}
function ownerOf(uint256 tokenId) public view override returns (address) {
require(
_getProfileStorage()._profileById[tokenId].owner != address(0),
'ERC721: owner query for nonexistent token'
);
return _getProfileStorage()._profileById[tokenId].owner;
}
function name() external view override returns (string memory) {
return _getGovernanceStorage()._name;
}
function symbol() external view override returns (string memory) {
return _getGovernanceStorage()._symbol;
}
function tokenURI(uint256 tokenId) external view override returns (string memory) {
string memory baseURI = _getGovernanceStorage()._baseURI;
return
bytes(baseURI).length > 0
? string(abi.encodePacked(baseURI, 'profile/', tokenId.toString()))
: tokenId.toString();
}
function balanceOf(address owner) public view override returns (uint256) {
return _getProfileStorage()._profileIdByAddress[owner] != 0 ? 1 : 0;
}
function totalSupply() external view override returns (uint256) {
return _getProfileStorage()._allTokens.length;
}
function nonces(address singer) external view override returns (uint256) {
return _getProfileStorage()._sigNonces[singer];
}
function getFollowSBT(uint256 profileId) external view override returns (address) {
return _getProfileStorage()._profileById[profileId].followSBT;
}
function getFollowCondition(uint256 profileId) external view override returns (address) {
return _getProfileStorage()._profileById[profileId].followCondition;
}
function getHandle(uint256 profileId) external view override returns (string memory) {
return _getProfileStorage()._profileById[profileId].handle;
}
function getProfileIdByHandle(string calldata handle) external view override returns (uint256) {
return _getProfileStorage()._profileIdByHandleHash[keccak256(bytes(handle))];
}
function getProfileIdByAddress(address addr) external view override returns (uint256) {
return _getProfileStorage()._profileIdByAddress[addr];
}
function getProfile(
uint256 profileId
) external view override returns (OspDataTypes.ProfileStruct memory) {
return _getProfileStorage()._profileById[profileId];
}
function tokenOfOwnerByIndex(
address owner,
uint256 index
) external view override returns (uint256) {
require(index == 0 || balanceOf(owner) == 0, 'ERC721Enumerable: owner index out of bounds');
return _getProfileStorage()._profileIdByAddress[owner];
}
function tokenByIndex(uint256 index) external view override returns (uint256) {
return _getProfileStorage()._allTokens[index];
}
function getApproved(
uint256
) external pure override returns (address ) {
revert OspErrors.SBTTransferNotAllowed();
}
function isApprovedForAll(
address ,
address
) external pure override returns (bool) {
revert OspErrors.SBTTransferNotAllowed();
}
function _mint(address to) internal returns (uint256) {
ProfileStorage storage profileStorage = _getProfileStorage();
if (profileStorage._profileIdByAddress[to] != 0) revert OspErrors.SBTTokenAlreadyExists();
uint256 tokenId = ++profileStorage._profileCounter;
_addTokenToAllTokensEnumeration(tokenId);
profileStorage._profileById[tokenId].owner = to;
profileStorage._profileById[tokenId].mintTimestamp = uint96(block.timestamp);
profileStorage._profileIdByAddress[to] = tokenId;
emit Transfer(address(0), to, tokenId);
return tokenId;
}
function _validateHandle(string calldata handle) internal pure returns (bytes32 hash) {
bytes memory byteHandle = bytes(handle);
if (
byteHandle.length < Constants.MIN_HANDLE_LENGTH ||
byteHandle.length > Constants.MAX_HANDLE_LENGTH
) revert OspErrors.HandleLengthInvalid();
uint256 byteHandleLength = byteHandle.length;
for (uint256 i; i < byteHandleLength; ) {
if (
(byteHandle[i] < '0' ||
byteHandle[i] > 'z' ||
(byteHandle[i] > '9' && byteHandle[i] < 'a')) && byteHandle[i] != '_'
) revert OspErrors.HandleContainsInvalidCharacters();
unchecked {
++i;
}
}
return keccak256(byteHandle);
}
function _createProfile(
OspDataTypes.CreateProfileData calldata vars
) internal returns (uint256) {
bytes32 handleHash = _validateHandle(vars.handle);
mapping(bytes32 => uint256) storage _profileIdByHandleHash = _getProfileStorage()
._profileIdByHandleHash;
if (_profileIdByHandleHash[handleHash] != 0) revert OspErrors.HandleTaken();
uint256 profileId = _mint(msg.sender);
OspDataTypes.ProfileStruct storage profileStruct = _getProfileStorage()._profileById[
profileId
];
profileStruct.handle = vars.handle;
_profileIdByHandleHash[handleHash] = profileId;
address followCondition;
if (vars.followConditionInitCode.length != 0) {
followCondition = _initFollowCondition(profileId, vars.followConditionInitCode);
profileStruct.followCondition = followCondition;
}
if (vars.inviter != 0) {
address inviterAddress = _getProfileStorage()._profileById[vars.inviter].owner;
if (inviterAddress == address(0) || inviterAddress == msg.sender) {
revert OspErrors.ProfileDoesNotExist();
}
profileStruct.inviter = vars.inviter;
}
emit OspEvents.ProfileCreated(
profileId,
msg.sender,
vars.handle,
followCondition,
vars.inviter,
vars.ctx,
block.timestamp
);
return profileId;
}
function _setFollowCondition(
uint256 profileId,
bytes calldata followConditionInitCode
) internal {
address followCondition = followConditionInitCode.length == 0
? address(0)
: _initFollowCondition(profileId, followConditionInitCode);
_getProfileStorage()._profileById[profileId].followCondition = followCondition;
emit OspEvents.FollowConditionSet(profileId, followCondition, block.timestamp);
}
function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
ProfileStorage storage profileStorage = _getProfileStorage();
profileStorage._allTokensIndex[tokenId] = profileStorage._allTokens.length;
profileStorage._allTokens.push(tokenId);
}
function _initFollowCondition(
uint256 profileId,
bytes calldata initCode
) private returns (address followCondition) {
followCondition = address(bytes20(initCode[:20]));
_checkFollowCondition(followCondition);
bytes memory initCallData = initCode[20:];
IFollowCondition(followCondition).initializeFollowCondition(profileId, initCallData);
}
}
文件 110 的 124:Proxy.sol
pragma solidity ^0.8.20;
abstract contract Proxy {
function _delegate(address implementation) internal virtual {
assembly {
calldatacopy(0, 0, calldatasize())
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
switch result
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
function _implementation() internal view virtual returns (address);
function _fallback() internal virtual {
_delegate(_implementation());
}
fallback() external payable virtual {
_fallback();
}
}
文件 111 的 124:ReferenceConditionBase.sol
pragma solidity 0.8.20;
import {OspContext} from './OspContext.sol';
import {IReferenceCondition} from '../../interfaces/IReferenceCondition.sol';
import {IERC165} from '@openzeppelin/contracts/interfaces/IERC165.sol';
abstract contract ReferenceConditionBase is OspContext, IERC165, IReferenceCondition {
constructor(address osp) OspContext(osp) {}
function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {
return
interfaceId == type(IReferenceCondition).interfaceId ||
interfaceId == type(IERC165).interfaceId;
}
function initializeReferenceCondition(
uint256 profileId,
uint256 contendId,
uint256 communityId,
bytes calldata data
) external onlyOsp {
_initializeReferenceCondition(profileId, communityId, contendId, data);
}
function processReactionReference(
uint256 profileId,
uint256 communityId,
uint256 referencedProfileId,
uint256 referencedContentId,
bytes calldata data
) external payable onlyOsp {
_processReactionReference(
profileId,
communityId,
referencedProfileId,
referencedContentId,
data
);
}
function _initializeReferenceCondition(
uint256 profileId,
uint256 contendId,
uint256 communityId,
bytes calldata data
) internal virtual;
function _processReactionReference(
uint256 profileId,
uint256 communityId,
uint256 referencedProfileId,
uint256 referencedContentId,
bytes calldata data
) internal virtual;
}
文件 112 的 124:RelationLogic.sol
pragma solidity 0.8.20;
import '../../libraries/Constants.sol';
import '../../interfaces/IFollowCondition.sol';
import '../../interfaces/IFollowSBT.sol';
import '../../upgradeability/FollowSBTProxy.sol';
import '../../interfaces/IJoinCondition.sol';
import '../../interfaces/IJoinNFT.sol';
import './OspLogicBase.sol';
import './interfaces/IRelationLogic.sol';
import '@openzeppelin/contracts/utils/Strings.sol';
import '@openzeppelin/contracts/token/ERC721/IERC721.sol';
contract RelationLogic is IRelationLogic, OspLogicBase {
using Strings for uint256;
modifier onlyJoinNFT(uint256 communityId) {
_checkFromJoinNFT(communityId);
_;
}
function follow(
OspDataTypes.FollowData calldata vars
) external payable override whenNotPaused returns (uint256) {
return _follow(vars.profileId, vars.data, vars.ctx);
}
function batchFollow(
OspDataTypes.BatchFollowData calldata vars
) external payable override whenNotPaused returns (uint256[] memory) {
return _batchFollow(vars.profileIds, vars.datas, vars.values, vars.ctx);
}
function join(
OspDataTypes.JoinData calldata vars
) external payable override whenNotPaused returns (uint256) {
return _join(vars.communityId, vars.data, vars.ctx);
}
function batchJoin(
OspDataTypes.BatchJoinData calldata vars
) external payable override whenNotPaused returns (uint256[] memory) {
return _batchJoin(vars.communityIds, vars.datas, vars.values, vars.ctx);
}
function getFollowSBTURI(
uint256 profileId,
uint256 tokenId
) external view override returns (string memory) {
string memory baseURI = _getGovernanceStorage()._baseURI;
return
bytes(baseURI).length > 0
? string(
abi.encodePacked(baseURI, profileId.toString(), '/follow/', tokenId.toString())
)
: tokenId.toString();
}
function getJoinNFTURI(
uint256 communityId,
uint256 tokenId
) external view override returns (string memory) {
string memory baseURI = _getGovernanceStorage()._baseURI;
return
bytes(baseURI).length > 0
? string(
abi.encodePacked(baseURI, communityId.toString(), '/join/', tokenId.toString())
)
: tokenId.toString();
}
function isFollow(uint256 profileId, address addr) external view override returns (bool) {
address followSBT = _getProfileStorage()._profileById[profileId].followSBT;
return followSBT == address(0) ? false : IERC721(followSBT).balanceOf(addr) > 0;
}
function isJoin(uint256 communityId, address addr) external view override returns (bool) {
address joinNFT = _getCommunityStorage()._communityById[communityId].joinNFT;
try IERC721(joinNFT).balanceOf(addr) returns (uint256 balance) {
return balance > 0;
} catch {
return false;
}
}
function hasCommunityRole(
uint256 communityId,
uint256 role,
address account
) external view override returns (bool) {
address joinNFT = _getCommunityStorage()._communityById[communityId].joinNFT;
return IJoinNFT(joinNFT).hasRole(role, account);
}
function getCommunityRole(
uint256 communityId,
address account
) external view returns (uint256) {
address joinNFT = _getCommunityStorage()._communityById[communityId].joinNFT;
return IJoinNFT(joinNFT).getRole(account);
}
function getCommunityMemberLevel(
uint256 communityId,
address account
) external view returns (uint256) {
address joinNFT = _getCommunityStorage()._communityById[communityId].joinNFT;
return IJoinNFT(joinNFT).getMemberLevel(account);
}
function isCommunityBlock(uint256 communityId, address account) external view returns (bool) {
address joinNFT = _getCommunityStorage()._communityById[communityId].joinNFT;
return IJoinNFT(joinNFT).isBlock(account);
}
function emitFollowSBTTransferEvent(
uint256 profileId,
uint256 followSBTId,
address from,
address to
) external override {
if (_getProfileStorage()._profileById[profileId].followSBT != msg.sender) {
revert OspErrors.NotFollowSBT();
}
emit OspEvents.FollowSBTTransferred(profileId, followSBTId, from, to, block.timestamp);
}
function emitJoinNFTTransferEvent(
uint256 communityId,
uint256 joinNFTId,
address from,
address to
) external override {
if (_getCommunityStorage()._communityById[communityId].joinNFT != msg.sender) {
revert OspErrors.NotJoinNFT();
}
address joinCondition = _getCommunityStorage()._communityById[communityId].joinCondition;
if (joinCondition != address(0)) {
IJoinCondition(joinCondition).processTransferJoinNFT(communityId, joinNFTId, from, to);
}
emit OspEvents.JoinNFTTransferred(communityId, joinNFTId, from, to, block.timestamp);
}
function emitJoinNFTRoleChangedEvent(
uint256 communityId,
address sender,
address account,
uint256 role
) external override onlyJoinNFT(communityId) {
emit OspEvents.JoinNFTRoleChanged(communityId, sender, account, role, block.timestamp);
}
function emitJoinNFTAccountBlockedEvent(
uint256 communityId,
address sender,
address account,
bool isBlock
) external override onlyJoinNFT(communityId) {
emit OspEvents.JoinNFTAccountBlocked(
communityId,
sender,
account,
isBlock,
block.timestamp
);
}
function emitJoinNFTAccountLevelChangedEvent(
uint256 communityId,
address sender,
uint256 tokenId,
address account,
uint256 level
) external override onlyJoinNFT(communityId) {
address joinNFT = _getCommunityStorage()._communityById[communityId].joinNFT;
emit OspEvents.JoinNFTAccountLevelChanged(
communityId,
tokenId,
sender,
account,
joinNFT,
level,
block.timestamp
);
}
function _follow(
uint256 targetProfileId,
bytes calldata followConditionData,
bytes calldata ctx
) internal returns (uint256 tokenId) {
uint256 profileId = _validateHasProfile(msg.sender);
tokenId = _executeFollow(targetProfileId, followConditionData, msg.value);
emit OspEvents.Followed(
msg.sender,
profileId,
targetProfileId,
followConditionData,
tokenId,
ctx,
block.timestamp
);
}
function _batchFollow(
uint256[] calldata targetProfileIds,
bytes[] calldata followConditionDatas,
uint256[] calldata values,
bytes calldata ctx
) internal returns (uint256[] memory) {
uint256 profileId = _validateHasProfile(msg.sender);
uint256 length = targetProfileIds.length;
if (length != followConditionDatas.length || length != values.length)
revert OspErrors.ArrayMismatch();
uint256[] memory tokenIds = new uint256[](length);
uint256 batchValue;
for (uint256 i; i < length; ) {
batchValue += values[i];
tokenIds[i] = _executeFollow(targetProfileIds[i], followConditionDatas[i], values[i]);
unchecked {
++i;
}
}
if (batchValue > msg.value) {
revert OspErrors.InvalidValue();
}
emit OspEvents.BatchFollowed(
msg.sender,
profileId,
targetProfileIds,
followConditionDatas,
tokenIds,
ctx,
block.timestamp
);
return tokenIds;
}
function _executeFollow(
uint256 profileId,
bytes calldata followConditionData,
uint256 value
) internal returns (uint256 tokenId) {
address owner = _getProfileStorage()._profileById[profileId].owner;
if (owner == address(0)) revert OspErrors.TokenDoesNotExist();
if (owner == msg.sender) revert OspErrors.InvalidProfileId();
address followCondition = _getProfileStorage()._profileById[profileId].followCondition;
address followSBT = _getProfileStorage()._profileById[profileId].followSBT;
if (followSBT == address(0)) {
followSBT = _deployFollowSBT(profileId);
_getProfileStorage()._profileById[profileId].followSBT = followSBT;
}
tokenId = IFollowSBT(followSBT).mint(msg.sender);
if (followCondition != address(0)) {
IFollowCondition(followCondition).processFollow{value: value}(
msg.sender,
profileId,
followConditionData
);
}
}
function _deployFollowSBT(uint256 profileId) internal returns (address) {
string memory idStr = profileId.toString();
string memory name = string(abi.encodePacked(idStr, Constants.FOLLOW_NFT_NAME_SUFFIX));
string memory symbol = string(abi.encodePacked(idStr, Constants.FOLLOW_NFT_SYMBOL_SUFFIX));
bytes memory functionData = abi.encodeWithSelector(
IFollowSBT.initialize.selector,
profileId,
name,
symbol
);
address followSBT = address(new FollowSBTProxy(functionData));
emit OspEvents.FollowSBTDeployed(profileId, followSBT, block.timestamp);
return followSBT;
}
function _join(
uint256 communityId,
bytes calldata joinConditionData,
bytes calldata ctx
) internal returns (uint256 tokenId) {
uint256 profileId = _validateHasProfile(msg.sender);
tokenId = _executeJoin(communityId, joinConditionData, msg.value);
emit OspEvents.Joined(
msg.sender,
profileId,
communityId,
joinConditionData,
tokenId,
ctx,
block.timestamp
);
}
function _batchJoin(
uint256[] calldata communityIds,
bytes[] calldata joinConditionDatas,
uint256[] calldata values,
bytes calldata ctx
) internal returns (uint256[] memory) {
uint256 profileId = _validateHasProfile(msg.sender);
uint256 length = communityIds.length;
if (length != joinConditionDatas.length || length != values.length)
revert OspErrors.ArrayMismatch();
uint256[] memory tokenIds = new uint256[](length);
{
uint256 batchValue;
for (uint256 i; i < length; ) {
batchValue += values[i];
tokenIds[i] = _executeJoin(communityIds[i], joinConditionDatas[i], values[i]);
unchecked {
++i;
}
}
if (batchValue > msg.value) {
revert OspErrors.InvalidValue();
}
}
emit OspEvents.BatchJoined(
msg.sender,
profileId,
communityIds,
joinConditionDatas,
tokenIds,
ctx,
block.timestamp
);
return tokenIds;
}
function _executeJoin(
uint256 communityId,
bytes calldata joinConditionData,
uint256 value
) internal returns (uint256 tokenId) {
OspDataTypes.CommunityStruct memory community = _getCommunityStorage()._communityById[
communityId
];
if (community.joinNFT == address(0)) revert OspErrors.InvalidCommunityId();
tokenId = IJoinNFT(community.joinNFT).mint(msg.sender);
if (community.joinCondition != address(0)) {
IJoinCondition(community.joinCondition).processJoin{value: value}(
msg.sender,
communityId,
joinConditionData
);
}
}
function _checkFromJoinNFT(uint256 communityId) internal {
if (_getCommunityStorage()._communityById[communityId].joinNFT != msg.sender) {
revert OspErrors.NotJoinNFT();
}
}
}
文件 113 的 124:RoleActivityCond.sol
pragma solidity 0.8.20;
import {ActivityConditionBase} from 'contracts/core/base/ActivityConditionBase.sol';
import {IRoleActivityCond} from './interfaces/IRoleActivityCond.sol';
import {CondErrors} from '../libraries/CondErrors.sol';
import {IRelationLogic} from 'contracts/core/logics/interfaces/IRelationLogic.sol';
contract RoleActivityCond is ActivityConditionBase, IRoleActivityCond {
mapping(uint256 => uint256) internal _roleLimitByCommunity;
constructor(
address osp,
address compositeActivityCondition
) ActivityConditionBase(osp, compositeActivityCondition) {}
function _initializeCommunityActivityCondition(
uint256 communityId,
bytes calldata data
) internal override {
uint256 accessLimit = abi.decode(data, (uint256));
_roleLimitByCommunity[communityId] = accessLimit;
}
function _processActivity(
uint256 communityId,
address profileOwner,
uint256 profileId
) internal override {
if (
IRelationLogic(OSP).hasCommunityRole(
communityId,
_roleLimitByCommunity[communityId],
profileOwner
)
) return;
revert CondErrors.AccessDenied();
}
function getRoleLimit(uint256 communityId) external view returns (uint256 roleLimit) {
roleLimit = _roleLimitByCommunity[communityId];
}
function supportsInterface(bytes4 interfaceId) public pure override returns (bool) {
return
ActivityConditionBase.supportsInterface(interfaceId) ||
interfaceId == type(IRoleActivityCond).interfaceId;
}
}
文件 114 的 124:RoleViewPrivacyCond.sol
pragma solidity 0.8.20;
import {ViewPrivacyConditionBase} from 'contracts/core/base/ViewPrivacyConditionBase.sol';
import {IRoleViewPrivacyCond} from './interfaces/IRoleViewPrivacyCond.sol';
import {IRelationLogic} from 'contracts/core/logics/interfaces/IRelationLogic.sol';
contract RoleViewPrivacyCond is ViewPrivacyConditionBase, IRoleViewPrivacyCond {
mapping(uint256 => uint256) internal _roleLimitByCommunity;
constructor(
address osp,
address compositeCondition
) ViewPrivacyConditionBase(osp, compositeCondition) {}
function _initializeCommunityViewPrivacyCondition(
uint256 communityId,
bytes calldata data
) internal override {
uint256 accessLimit = abi.decode(data, (uint256));
_roleLimitByCommunity[communityId] = accessLimit;
}
function _isViewPrivacyAllowed(
uint256 communityId,
address profileOwner,
uint256 profileId
) internal view override returns (bool) {
if (
IRelationLogic(OSP).hasCommunityRole(
communityId,
_roleLimitByCommunity[communityId],
profileOwner
)
) return true;
return false;
}
function getRoleLimit(uint256 communityId) external view override returns (uint256 roleLimit) {
return _roleLimitByCommunity[communityId];
}
function supportsInterface(bytes4 interfaceId) public pure override returns (bool) {
return
ViewPrivacyConditionBase.supportsInterface(interfaceId) ||
interfaceId == type(IRoleViewPrivacyCond).interfaceId;
}
}
文件 115 的 124:SafeERC20.sol
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
error SafeERC20FailedOperation(address token);
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}
文件 116 的 124:SignatureChecker.sol
pragma solidity ^0.8.20;
import {ECDSA} from "./ECDSA.sol";
import {IERC1271} from "../../interfaces/IERC1271.sol";
library SignatureChecker {
function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) {
(address recovered, ECDSA.RecoverError error, ) = ECDSA.tryRecover(hash, signature);
return
(error == ECDSA.RecoverError.NoError && recovered == signer) ||
isValidERC1271SignatureNow(signer, hash, signature);
}
function isValidERC1271SignatureNow(
address signer,
bytes32 hash,
bytes memory signature
) internal view returns (bool) {
(bool success, bytes memory result) = signer.staticcall(
abi.encodeCall(IERC1271.isValidSignature, (hash, signature))
);
return (success &&
result.length >= 32 &&
abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector));
}
}
文件 117 的 124:SignedMath.sol
pragma solidity ^0.8.20;
library SignedMath {
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
function average(int256 a, int256 b) internal pure returns (int256) {
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
function abs(int256 n) internal pure returns (uint256) {
unchecked {
return uint256(n >= 0 ? n : -n);
}
}
}
文件 118 的 124:SlotNFTCommunityCond.sol
pragma solidity 0.8.20;
import {CondErrors} from '../libraries/CondErrors.sol';
import {IERC721} from '@openzeppelin/contracts/token/ERC721/IERC721.sol';
import {CommunityCondBase} from '../../base/CommunityCondBase.sol';
import {CondDataTypes} from '../libraries/CondDataTypes.sol';
contract SlotNFTCommunityCond is CommunityCondBase {
event SlotNFTCondDataSet(address indexed slot, uint256 minHandleLength, uint256 timestamp);
event SlotNFTUsed(
address indexed to,
address indexed slot,
uint256 indexed tokenId,
string handle,
uint256 timestamp
);
constructor(address osp) CommunityCondBase(osp) {}
mapping(address => mapping(uint256 => bool)) _slotNFTUsed;
mapping(address => CondDataTypes.SlotNFTCondData) _slotNFTCondData;
function _processCreateCommunity(
address to,
string calldata handle,
bytes calldata data
) internal override nonPayable {
(address slot, uint256 tokenId) = abi.decode(data, (address, uint256));
_validateSlotNFT(to, slot, tokenId);
uint256 len = bytes(handle).length;
if (len < _slotNFTCondData[slot].minHandleLength) {
revert CondErrors.HandleLengthNotEnough();
}
_slotNFTUsed[slot][tokenId] = true;
emit SlotNFTUsed(to, slot, tokenId, handle, block.timestamp);
}
function setSlotNFTCondData(
address slot,
bool whitelist,
uint256 minHandleLength
) external onlyOperation {
if (slot == address(0) || minHandleLength <= 0) {
revert CondErrors.InitParamsInvalid();
}
_slotNFTCondData[slot] = CondDataTypes.SlotNFTCondData({
whitelist: whitelist,
minHandleLength: minHandleLength
});
emit SlotNFTCondDataSet(slot, minHandleLength, block.timestamp);
}
function getSlotNFTCondData(
address slot
) external view returns (CondDataTypes.SlotNFTCondData memory) {
return _slotNFTCondData[slot];
}
function isSlotNFTUsable(
address slot,
address addr,
uint256 tokenId
) external view returns (bool) {
return
_slotNFTCondData[slot].whitelist &&
!_slotNFTUsed[slot][tokenId] &&
IERC721(slot).ownerOf(tokenId) == addr;
}
function _validateSlotNFT(address addr, address slot, uint256 tokenId) internal view {
if (!_slotNFTCondData[slot].whitelist) {
revert CondErrors.SlotNFTNotWhitelisted();
}
if (IERC721(slot).ownerOf(tokenId) != addr) {
revert CondErrors.NotSlotNFTOwner();
}
if (_slotNFTUsed[slot][tokenId]) {
revert CondErrors.SlotNFTAlreadyUsed();
}
}
}
文件 119 的 124:StorageSlot.sol
pragma solidity ^0.8.20;
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
assembly {
r.slot := slot
}
}
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
assembly {
r.slot := slot
}
}
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
assembly {
r.slot := slot
}
}
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
assembly {
r.slot := slot
}
}
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
assembly {
r.slot := slot
}
}
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
assembly {
r.slot := store.slot
}
}
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
assembly {
r.slot := slot
}
}
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
assembly {
r.slot := store.slot
}
}
}
文件 120 的 124:Strings.sol
pragma solidity ^0.8.20;
import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";
library Strings {
bytes16 private constant HEX_DIGITS = "0123456789abcdef";
uint8 private constant ADDRESS_LENGTH = 20;
error StringsInsufficientHexLength(uint256 value, uint256 length);
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
assembly {
mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
function toStringSigned(int256 value) internal pure returns (string memory) {
return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
}
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
uint256 localValue = value;
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = HEX_DIGITS[localValue & 0xf];
localValue >>= 4;
}
if (localValue != 0) {
revert StringsInsufficientHexLength(value, length);
}
return string(buffer);
}
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
}
function equal(string memory a, string memory b) internal pure returns (bool) {
return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
}
}
文件 121 的 124:ViewPrivacyConditionBase.sol
pragma solidity 0.8.20;
import {IViewPrivacyCondition} from 'contracts/interfaces/IViewPrivacyCondition.sol';
import {IERC165} from '@openzeppelin/contracts/interfaces/IERC165.sol';
import {ConditionContext} from './ConditionContext.sol';
abstract contract ViewPrivacyConditionBase is ConditionContext, IERC165, IViewPrivacyCondition {
constructor(
address osp,
address compositeCondition
) ConditionContext(osp, compositeCondition) {}
function initializeCommunityViewPrivacyCondition(
uint256 communityId,
bytes calldata data
) external onlyOspOrCompositeCondition {
_initializeCommunityViewPrivacyCondition(communityId, data);
}
function isViewPrivacyAllowed(
uint256 communityId,
address profileOwner,
uint256 profileId
) external view onlyOspOrCompositeCondition returns (bool) {
return _isViewPrivacyAllowed(communityId, profileOwner, profileId);
}
function _initializeCommunityViewPrivacyCondition(
uint256 communityId,
bytes calldata data
) internal virtual;
function _isViewPrivacyAllowed(
uint256 communityId,
address profileOwner,
uint256 profileId
) internal view virtual returns (bool);
function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {
return
interfaceId == type(IViewPrivacyCondition).interfaceId ||
interfaceId == type(IERC165).interfaceId;
}
}
文件 122 的 124:VoteReaction.sol
pragma solidity 0.8.20;
import {OpenReactionBase} from '../base/OpenReactionBase.sol';
import {OspErrors} from '../../libraries/OspErrors.sol';
contract VoteReaction is OpenReactionBase {
constructor(address osp) OpenReactionBase(osp) {}
enum Vote {
Cancel,
Up,
Down
}
function _processReaction(
uint256 ,
uint256 ,
uint256 ,
bytes calldata data
) internal view override {
abi.decode(data, (Vote));
}
}
文件 123 的 124:WhitelistAddressCommunityCond.sol
pragma solidity 0.8.20;
import {CondErrors} from '../libraries/CondErrors.sol';
import {CommunityCondBase} from '../../base/CommunityCondBase.sol';
contract WhitelistAddressCommunityCond is CommunityCondBase {
event MaxCreationNumberSet(address indexed to, uint256 maxCreationNumber, uint256 timestamp);
constructor(address osp) CommunityCondBase(osp) {}
mapping(address => uint256) public maxCreationNumber;
mapping(address => uint256) public creationCount;
function _processCreateCommunity(
address to,
string calldata ,
bytes calldata
) internal override nonPayable {
if (maxCreationNumber[to] <= creationCount[to]) {
revert CondErrors.NotWhitelisted();
}
creationCount[to]++;
}
function setMaxCreationNumber(address to, uint256 _maxCreationNumber) external onlyOperation {
maxCreationNumber[to] = _maxCreationNumber;
emit MaxCreationNumberSet(to, _maxCreationNumber, block.timestamp);
}
function allowedCreationNumber(address to) external view returns (uint256) {
return
maxCreationNumber[to] > creationCount[to]
? maxCreationNumber[to] - creationCount[to]
: 0;
}
}
文件 124 的 124:draft-IERC6093.sol
pragma solidity ^0.8.20;
interface IERC20Errors {
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
error ERC20InvalidSender(address sender);
error ERC20InvalidReceiver(address receiver);
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
error ERC20InvalidApprover(address approver);
error ERC20InvalidSpender(address spender);
}
interface IERC721Errors {
error ERC721InvalidOwner(address owner);
error ERC721NonexistentToken(uint256 tokenId);
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
error ERC721InvalidSender(address sender);
error ERC721InvalidReceiver(address receiver);
error ERC721InsufficientApproval(address operator, uint256 tokenId);
error ERC721InvalidApprover(address approver);
error ERC721InvalidOperator(address operator);
}
interface IERC1155Errors {
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
error ERC1155InvalidSender(address sender);
error ERC1155InvalidReceiver(address receiver);
error ERC1155MissingApprovalForAll(address operator, address owner);
error ERC1155InvalidApprover(address approver);
error ERC1155InvalidOperator(address operator);
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}
{
"compilationTarget": {
"contracts/upgradeability/OspRouterImmutable.sol": "OspRouterImmutable"
},
"evmVersion": "shanghai",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"admin_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"pendingAdmin","type":"address"},{"indexed":false,"internalType":"uint256","name":"pendingAdminTimestamp","type":"uint256"}],"name":"ChangeAdminStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"pendingAdmin","type":"address"}],"name":"PendingAdminRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"indexed":true,"internalType":"address","name":"routerAddress","type":"address"}],"name":"RouterAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"indexed":true,"internalType":"address","name":"routerAddress","type":"address"}],"name":"RouterRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"indexed":true,"internalType":"string","name":"functionSignature","type":"string"},{"indexed":true,"internalType":"address","name":"routerAddress","type":"address"}],"name":"RouterSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"indexed":true,"internalType":"address","name":"oldRouterAddress","type":"address"},{"indexed":true,"internalType":"address","name":"newRouterAddress","type":"address"}],"name":"RouterUpdated","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"internalType":"bytes4","name":"_selector","type":"bytes4"}],"name":"_getRouterForFunction","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptAdminRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"address","name":"routerAddress","type":"address"},{"internalType":"string","name":"functionSignature","type":"string"}],"internalType":"struct IRouter.Router","name":"_router","type":"tuple"}],"name":"addRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newAdmin","type":"address"}],"name":"changeAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_routerAddress","type":"address"}],"name":"getAllFunctionsOfRouter","outputs":[{"internalType":"bytes4[]","name":"registered","type":"bytes4[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllRouters","outputs":[{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"address","name":"routerAddress","type":"address"},{"internalType":"string","name":"functionSignature","type":"string"}],"internalType":"struct IRouter.Router[]","name":"registered","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPendingAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPendingAdminTimestamp","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_selector","type":"bytes4"}],"name":"getRouterForFunction","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"},{"internalType":"string","name":"functionSignature","type":"string"}],"name":"removeRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"revokePendingAdmin","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":[{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"address","name":"routerAddress","type":"address"},{"internalType":"string","name":"functionSignature","type":"string"}],"internalType":"struct IRouter.Router","name":"_router","type":"tuple"}],"name":"updateRouter","outputs":[],"stateMutability":"nonpayable","type":"function"}]