Amoy Testnet

Contract Diff Checker

Contract Name:
TimeBased

Contract Source Code:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;

import {NodeOwners} from "./NodeOwners.sol";
import {IContentGraph} from "../IContentGraph.sol";

contract TimeBased is NodeOwners {
    mapping(bytes32 => Embargo) contentEmbargo;
    mapping(bytes32 => mapping(address => bool)) purchased;

    enum Time {
        MINS,
        DAYS,
        WEEKS,
        YEARS
    }

    enum PricingFunction {
        STEP,
        LINEAR,
        EXPONENTIAL,
        BINARY
    }

    struct Embargo {
        uint256 embargoDate;
        uint256 retailPrice;
        uint256 premium;
        Time timeDenom;
        PricingFunction priceFunc;
    }

    event EmbargoSet(
        bytes32 id, uint256 embargoDate, uint256 retailPrice, uint256 premium, Time timeDenom, PricingFunction priceFunc
    );
    event AccessPurchased(bytes32 id, address purchaser, uint256 price);

    constructor(address _graph, address identity) NodeOwners(_graph, identity) {}

    function price(bytes32 id, uint256 time) public view returns (uint256 accessPrice) {
        Embargo memory embargo = contentEmbargo[id];
        if (time >= embargo.embargoDate) {
            accessPrice = embargo.retailPrice;
        } else {
            uint256 difference = embargo.embargoDate - time;
            uint256 premium = embargo.premium;

            if (embargo.timeDenom == Time.MINS) {
                difference = difference / 60;
            } else if (embargo.timeDenom == Time.DAYS) {
                difference = difference / (60 * 60 * 24);
            } else if (embargo.timeDenom == Time.WEEKS) {
                difference = difference / (60 * 60 * 24 * 7);
            } else if (embargo.timeDenom == Time.YEARS) {
                difference = difference / (60 * 60 * 24 * 365);
            }

            if (embargo.priceFunc == PricingFunction.LINEAR) {
                premium = premium * difference;
            } else if (embargo.priceFunc == PricingFunction.EXPONENTIAL) {
                for (uint256 i = 0; i < difference; i++) {
                    premium = premium * 2; // Assuming doubling the premium for each unit of difference
                }
            }
            accessPrice = embargo.retailPrice + premium;
        }
    }

    function setEmbargo(bytes32 id, Embargo calldata _embargo) public nodeOwner(id) {
        contentEmbargo[id] = _embargo;
        emit EmbargoSet(
            id, _embargo.embargoDate, _embargo.retailPrice, _embargo.premium, _embargo.timeDenom, _embargo.priceFunc
        );
    }

    function purchaseAccess(bytes32 id) public payable {
        Embargo memory embargo = contentEmbargo[id];
        if (embargo.priceFunc == PricingFunction.BINARY) {
            require(block.timestamp >= embargo.embargoDate, "EMBARGO: Binary embargo date not passed.");
        }
        uint256 priceNow = price(id, block.timestamp);
        require(msg.value >= priceNow, "EMBARGO: Value sent below price");
        uint256 refund = msg.value - priceNow;

        uint256 token = IContentGraph(contentGraph).getNode(id).token;
        address owner = IContentGraph(contentGraph).ownerOf(token);
        (bool sent,) = owner.call{value: priceNow}("");
        require(sent, "EMBARGO: Failed to send Ether to owner");

        if (refund > 0) {
            (sent,) = msg.sender.call{value: refund}("");
            require(sent, "EMBARGO: Failed to refund excess Ether");
        }

        purchased[id][msg.sender] = true;
        emit AccessPurchased(id, msg.sender, priceNow);
    }

    function getEmbargo(bytes32 id) external view returns (Embargo memory embargo) {
        embargo = contentEmbargo[id];
    }

    function auth(bytes32 id, address user) external view returns (bool isAuthorized) {
        isAuthorized = purchased[id][user];
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IContentGraph} from "../IContentGraph.sol";
import {IIdentityRegistry} from "../interfaces/IIdentityRegistry.sol";

/**
 * @title Node Owners
 * @author Blockchain Creative Labs
 */
contract NodeOwners {
    address contentGraph;
    address identityRegistry;

    error NotAuthorized();

    constructor(address _graph, address _identity) {
        contentGraph = _graph;
        identityRegistry = _identity;
    }

    modifier nodeOwner(bytes32 id) {
        _checkOwner(id);
        _;
    }

    function _checkOwner(bytes32 id) internal view virtual {
        uint256 token = IContentGraph(contentGraph).getNode(id).token;
        address owner = IContentGraph(contentGraph).ownerOf(token);
        address actingAs = IIdentityRegistry(identityRegistry).whoIs(msg.sender);
        if (actingAs != address(0)) {
            require(owner == actingAs, "NodeOwners: Caller is not authorized");
        } else {
            revert NotAuthorized();
        }
    }
}

// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.0;

import "./interfaces/IERC6150.sol";
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";

interface IContentGraph is IERC6150, IERC721 {
    event Moved(bytes32 _id, bytes32 indexed _from, bytes32 _to);
    event AccessAuthUpdate(bytes32 _id, address _auth);
    event ReferenceAuthUpdate(bytes32 _id, address _auth);
    event URIUpdate(bytes32 _id, string _uri);

    enum NodeType {
        ORG,
        REFERENCE,
        ASSET
    }

    struct ContentNode {
        bytes32 id;
        NodeType nodeType;
        bytes32 referenceOf;
        string uri;
    }

    struct Node {
        uint256 token;
        NodeType nodeType;
        bytes32 id;
        bytes32 referenceOf;
        string uri;
        address accessAuth;
        address referenceAuth;
    }

    /**
     * @notice Publishes a new set content node (assets/references) to the passed parent id.
     * @param parentId The id of an ORG node to publish the set of content nodes.
     * @param content A list of content.
     */
    function publishBulk(bytes32 parentId, ContentNode[] calldata content) external;

    /**
     * @notice Publishes a new asset node at a given parent in addition to setting the uri for the asset node.
     * @param parentId The id of an ORG node to publish the set of content nodes.
     * @param content A content node to publish.
     */
    function publish(bytes32 parentId, ContentNode calldata content) external;

    /**
     * @notice Creates a node of a given type under the parent node provided.
     * @param id The id of the node to create, must follow correct form based on type.
     * @param parentId The id of a admin node to publish the node under
     * @param nodeType The type of node to create, ADMIN, COLLECTION, or ASSET
     */
    function createNode(bytes32 id, bytes32 parentId, NodeType nodeType) external;

    /**
     * @notice Creates a node of a given type under the parent node provided.
     * @param id The id of the node to create, must follow the correct form based on type.
     * @param parentId The id of a ORG node to publish the node under
     * @param nodeType The type of node to create, ORG, REFERENCE, or ASSET
     * @param referenceOf If the type is of REFERENCE the id of the node that is being referenced
     */
    function createNode(bytes32 id, bytes32 parentId, NodeType nodeType, bytes32 referenceOf) external;

    /**
     * @notice Moves a node from current parent to a new parent.
     * @param id The id of the node to move.
     * @param newParentId The id of an existing admin node to move the node under.
     */
    function move(bytes32 id, bytes32 newParentId) external;

    /**
     * @notice Sets the access auth module for a given node.
     * @param id The id of the node whose auth modules should be set
     * @param accessAuth The address to the auth module to be used access of node's content.
     */
    function setAccessAuth(bytes32 id, address accessAuth) external;

    /**
     * @notice Sets the reference auth module for a given node.
     * @param id The id of the node whose auth modules should be set
     * @param referenceAuth The address to the auth module to be used for referencing a node in collection.
     */
    function setReferenceAuth(bytes32 id, address referenceAuth) external;

    /**
     * @notice Sets the uri for a node.
     * @param id The id of the node.
     * @param uri The URI to the metadata to set for a node.
     */
    function setURI(bytes32 id, string calldata uri) external;

    /**
     * @notice Validates if a given user may access the content at a given node.
     * @param id The id of the node whose content is being accessed.
     * @param user The address of the user who wishes to access the content.
     */
    function auth(bytes32 id, address user) external view returns (bool);

    /**
     * @notice Validates if a given user may reference a given node in a collection.
     * @param id The id of the node who is being referenced.
     * @param user The address of the user who wishes to reference the node.
     */
    function refAuth(bytes32 id, address user) external view returns (bool);

    /**
     * @notice retrieve node from node id
     * @param id The id of the node to retrieve.
     */
    function getNode(bytes32 id) external view returns (Node memory node);

    /**
     * @dev retrieve node from token id
     * @param token The tokenId for the node to retrieve.
     */
    function tokenToNode(uint256 token) external view returns (Node memory node);
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

interface IIdentityRegistry {
    function registerRoot(address root, string memory name) external;
    function deregisterRoot(address root) external;
    function registerIdentity(
        bytes memory signature,
        address root,
        address identity,
        uint256 expirary,
        uint256 deadline
    ) external;
    function deregisterIdentity(bytes memory signature, address root, address identity, uint256 deadline) external;
    function whoIs(address identity) external view returns (address root);
    function getSignature(address _root, address _identity)
        external
        view
        returns (bytes memory signature, bytes32 digest, address root, address identity, uint256 expirary);
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";

// Note: the ERC-165 identifier for this interface is 0x897e2c73.
interface IERC6150 { /* is IERC721, IERC165 */
    /**
     * @notice Emitted when `tokenId` token under `parentId` is minted.
     * @param minter The address of minter
     * @param to The address received token
     * @param parentId The id of parent token, if it's zero, it means minted `tokenId` is a root token.
     * @param tokenId The id of minted token, required to be greater than zero
     */
    event Minted(address indexed minter, address indexed to, uint256 parentId, uint256 tokenId);

    /**
     * @notice Get the parent token of `tokenId` token.
     * @param tokenId The child token
     * @return parentId The Parent token found
     */
    function parentOf(uint256 tokenId) external view returns (uint256 parentId);

    /**
     * @notice Get the children tokens of `tokenId` token.
     * @param tokenId The parent token
     * @return childrenIds The array of children tokens
     */
    function childrenOf(uint256 tokenId) external view returns (uint256[] memory childrenIds);

    /**
     * @notice Check the `tokenId` token if it is a root token.
     * @param tokenId The token want to be checked
     * @return Return `true` if it is a root token; if not, return `false`
     */
    function isRoot(uint256 tokenId) external view returns (bool);

    /**
     * @notice Check the `tokenId` token if it is a leaf token.
     * @param tokenId The token want to be checked
     * @return Return `true` if it is a leaf token; if not, return `false`
     */
    function isLeaf(uint256 tokenId) external view returns (bool);
}

// Note: the ERC-165 identifier for this interface is 0xba541a2e.
interface IERC6150Enumerable is IERC6150 /* IERC721Enumerable */ {
    /**
     * @notice Get total amount of children tokens under `parentId` token.
     * @dev If `parentId` is zero, it means get total amount of root tokens.
     * @return The total amount of children tokens under `parentId` token.
     */
    function childrenCountOf(uint256 parentId) external view returns (uint256);

    /**
     * @notice Get the token at the specified index of all children tokens under `parentId` token.
     * @dev If `parentId` is zero, it means get root token.
     * @return The token ID at `index` of all chlidren tokens under `parentId` token.
     */
    function childOfParentByIndex(uint256 parentId, uint256 index) external view returns (uint256);

    /**
     * @notice Get the index position of specified token in the children enumeration under specified parent token.
     * @dev Throws if the `tokenId` is not found in the children enumeration.
     * If `parentId` is zero, means get root token index.
     * @param parentId The parent token
     * @param tokenId The specified token to be found
     * @return The index position of `tokenId` found in the children enumeration
     */
    function indexInChildrenEnumeration(uint256 parentId, uint256 tokenId) external view returns (uint256);
}

// Note: the ERC-165 identifier for this interface is 0x4ac0aa46.
interface IERC6150Burnable is IERC6150 {
    /**
     * @notice Burn the `tokenId` token.
     * @dev Throws if `tokenId` is not a leaf token.
     * Throws if `tokenId` is not a valid NFT.
     * Throws if `owner` is not the owner of `tokenId` token.
     * Throws unless `msg.sender` is the current owner, an authorized operator, or the approved address for this token.
     * @param tokenId The token to be burnt
     */
    function safeBurn(uint256 tokenId) external;

    /**
     * @notice Batch burn tokens.
     * @dev Throws if one of `tokenIds` is not a leaf token.
     * Throws if one of `tokenIds` is not a valid NFT.
     * Throws if `owner` is not the owner of all `tokenIds` tokens.
     * Throws unless `msg.sender` is the current owner, an authorized operator, or the approved address for all `tokenIds`.
     * @param tokenIds The tokens to be burnt
     */
    function safeBatchBurn(uint256[] memory tokenIds) external;
}

// Note: the ERC-165 identifier for this interface is 0xfa574808.
interface IERC6150ParentTransferable is IERC6150 {
    /**
     * @notice Emitted when the parent of `tokenId` token changed.
     * @param tokenId The token changed
     * @param oldParentId Previous parent token
     * @param newParentId New parent token
     */
    event ParentTransferred(uint256 tokenId, uint256 oldParentId, uint256 newParentId);

    /**
     * @notice Transfer parentship of `tokenId` token to a new parent token
     * @param newParentId New parent token id
     * @param tokenId The token to be changed
     */
    function transferParent(uint256 newParentId, uint256 tokenId) external;

    /**
     * @notice Batch transfer parentship of `tokenIds` to a new parent token
     * @param newParentId New parent token id
     * @param tokenIds Array of token ids to be changed
     */
    function batchTransferParent(uint256 newParentId, uint256[] memory tokenIds) external;
}

// Note: the ERC-165 identifier for this interface is 0x1d04f0b3.
interface IERC6150AccessControl is IERC6150 {
    /**
     * @notice Check the account whether a admin of `tokenId` token.
     * @dev Each token can be set more than one admin. Admin have permission to do something to the token, like mint child token,
     * or burn token, or transfer parentship.
     * @param tokenId The specified token
     * @param account The account to be checked
     * @return If the account has admin permission, return true; otherwise, return false.
     */
    function isAdminOf(uint256 tokenId, address account) external view returns (bool);

    /**
     * @notice Check whether the specified parent token and account can mint children tokens
     * @dev If the `parentId` is zero, check whether account can mint root nodes
     * @param parentId The specified parent token to be checked
     * @param account The specified account to be checked
     * @return If the token and account has mint permission, return true; otherwise, return false.
     */
    function canMintChildren(uint256 parentId, address account) external view returns (bool);

    /**
     * @notice Check whether the specified token can be burnt by specified account
     * @param tokenId The specified token to be checked
     * @param account The specified account to be checked
     * @return If the tokenId can be burnt by account, return true; otherwise, return false.
     */
    function canBurnTokenByAccount(uint256 tokenId, address account) external view returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC-721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
     *   a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC-721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
     *   {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
     *   a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC-721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the address zero.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

Please enter a contract address above to load the contract details and source code.

Context size (optional):